Federated Virtual Filesystem

A virtual file system that unifies multiple cloud storage providers (Google Drive, S3, Nextcloud) in one place

1 1

Federated Virtual Filesystem#

Architectural Master Plan and Implementation Guide#

Table of Contents#

  1. Project Abstract
  2. System Architecture
  3. Technology Specifications
  4. Data Model
  5. Core Subsystems
  6. Detailed Implementation Plan
  7. Infrastructure and Deployment

Project Abstract#

Federated Virtual Filesystem is a storage orchestration middleware designed to aggregate distinct cloud storage providers (AWS S3, Google Drive, Nextcloud) into a single, federated Virtual File System (VFS). The system operates on a metadata-first principle: file metadata is indexed in a relational database (PostgreSQL) and a search engine (OpenSearch) to enable sub-second search and traversal without engaging provider APIs. Actual file content serves are proxied only when necessary, with a preference for direct-to-provider signed URLs. The backend utilizes an event-driven microservices architecture to handle high-throughput file synchronization and background transfers.

System Architecture#

The architecture distinguishes between the Control Plane (synchronous API operations) and the Data Plane (asynchronous workers). These planes are decoupled via Apache Kafka (for event streaming) and Redis (for task queuing).

Technology Specifications#

Component Technology Version Implementation Details
API Framework FastAPI 0.100+ Python 3.11+. Uses uvicorn as ASGI server.
Database PostgreSQL 15+ Requires ltree extension for hierarchical path storage and pg_trgm for fuzzy search.
Search Engine OpenSearch 2.0+ Used for full-text search, faceting, and storing flattened file metadata.
Message Broker Apache Kafka 3.5+ Handles system events: file.created, file.modified, sync.requested.
Task Queue Celery 5.3+ Uses Redis as the broker. Handles task retries, scheduling, and rate limiting.
Cache Redis 7.0+ Caches directory listings and stores ephemeral upload session data.
ORM SQLAlchemy 2.0+ AsyncIO implementation (asyncpg driver).

Data Model#

The database schema enforces referential integrity between users, their storage connections, and the virtual file tree.

Core Subsystems#

Virtual File System (VFS)#

The VFS abstracts external file structures. It uses the PostgreSQL ltree extension to allow efficient subtree queries (e.g., “Select all files inside Folder X”). Operations on the VFS (Move, Rename, Delete) must be transactionally atomic: updates are applied to the provider first, then committed to the database.

Provider Adapter Interface#

All storage providers must implement the BaseStorageAdapter abstract base class to ensure uniformity.

python
from abc import ABC
from typing import AsyncGenerator, List, Tuple

# Assuming these are defined elsewhere for type hints
class ListResult: pass
class DeltaResult: pass
class UploadSession: pass
class FileMetadata: pass

class BaseStorageAdapter(ABC):
    async def list_children(self, path: str, cursor: str) -> ListResult: ...
    async def get_changes(self, cursor: str) -> DeltaResult: ...
    async def download_stream(self, file_id: str, range: Tuple) -> AsyncGenerator: ...
    async def initiate_upload(self, name: str, size: int) -> UploadSession: ...
    async def move(self, file_id: str, new_parent: str) -> FileMetadata: ...

Synchronization Engine#

Synchronization is event-driven rather than poll-based where possible.

  1. Ingest: Webhooks (Drive) or Event Notifications (S3) push events to the API.
  2. Queue: Events are published to the sync.events Kafka topic.
  3. Process: Sync Workers consume events, fetch metadata from the provider, and upsert records in the virtual_nodes table.
  4. Index: Changes in virtual_nodes emit events to file.index, consumed by Index Workers for OpenSearch.

Transfer Engine#

Cross-provider transfers (e.g., Drive to S3) are handled by Transfer Workers.

  • Streaming: Data is streamed in chunks (5MB-10MB) through the worker to avoid memory exhaustion.
  • Resumability: Transfer progress is checkpointed in Redis. If a worker fails, another can resume from the last successful chunk.
  • Multipart: Large files utilize S3 Multipart Upload and Drive Resumable Upload APIs.

Detailed Implementation Plan#

This roadmap outlines the sequential development phases required to build the system.

Phase 1: Foundation and Infrastructure#

Objective: Establish the runtime environment and database schema.

  1. Container Orchestration:
    • Create docker-compose.yml defining services: postgres, redis, kafka, zookeeper, opensearch.
    • Configure persistent volumes for data durability.
  2. Database Definition:
    • Initialize SQLAlchemy Base and models (User, StorageConnection, VirtualNode).
    • Create Alembic migration scripts to enable ltree extension and create tables.
  3. Authentication Service:
    • Implement POST /auth/register and POST /auth/login using JWT (JSON Web Tokens).
    • Implement get_current_user dependency for FastAPI.

Phase 2: Connection Management#

Objective: Allow users to link storage accounts.

  1. Encryption Utilities:
    • Implement Fernet (symmetric encryption) helpers to store and retrieve provider credentials securely.
  2. Connection API:
    • Implement POST /connections to store provider config (bucket names, regions).
    • Implement GET /connections to list active integrations.
  3. Adapter Registry:
    • Create the ProviderRegistry pattern to instantiate the correct adapter class based on the provider_type column.

Phase 3: S3 Integration (Base Provider)#

Objective: Implement full read/write capability for S3-compatible stores.

  1. S3 Adapter Implementation:
    • Implement list_children using boto3.
    • Implement generate_presigned_url for downloads and uploads.
  2. VFS Browse API:
    • Implement GET /files endpoint. Logic: Query virtual_nodes by parent_id.
  3. Initial Sync Logic:
    • Create a simple Celery task sync_s3_bucket that lists all objects in a bucket and populates virtual_nodes.

Phase 4: The Sync Engine#

Objective: Handle ongoing changes and multi-provider state.

  1. Kafka Configuration:
    • Define topics: system.commands, file.events, file.index.
  2. Google Drive Integration:
    • Implement GoogleDriveAdapter.
    • Implement OAuth2 flow handling to acquire and store Refresh Tokens.
    • Implement get_changes using the Drive Activity API.
  3. Sync Worker:
    • Create a consumer service using aiokafka.
    • Logic: Listen for SYNC_REQUESTED. Iterate through provider changes. Upsert/Delete rows in Postgres.
  4. Delta Sync:
    • Implement logic to store and retrieve sync_cursor tokens from the sync_states table.

Phase 5: Search and Indexing#

Objective: Enable fast search across the VFS.

  1. OpenSearch Setup:
    • Define index mappings for files (name, size, MIME type, ltree path).
  2. Index Worker:
    • Create a Kafka consumer for file.events.
    • Logic: On FILE_CREATED or FILE_MODIFIED, transform the Postgres row into a JSON document and push to OpenSearch.
  3. Search API:
    • Implement GET /search. Logic: Query OpenSearch, return list of matching file IDs, enrich with latest metadata from Postgres if necessary.

Phase 6: Transfer Engine#

Objective: Enable moving files between providers.

  1. Transfer API:
    • Implement POST /transfers. Accepts source_node_id and destination_folder_id.
    • Creates a Job record in Postgres with status PENDING.
  2. Transfer Worker:
    • Implement process_transfer_job Celery task.
    • Logic:
      1. Acquire source stream (adapter.download_stream).
      2. Acquire destination upload session (adapter.initiate_upload).
      3. Pipe stream from source to destination.
      4. Update Job progress in Redis.
      5. On success, create new VirtualNode and mark Job as COMPLETED.

Phase 7: Optimization and Production Readiness#

Objective: Prepare for scale.

  1. Rate Limiting:
    • Implement Redis-based sliding window rate limiter for external API calls to prevent quota exhaustion.
  2. Refinement:
    • Implement error handling policies (exponential backoff) for failed sync tasks.
    • Add structural logging (JSON logs) for observability.

Infrastructure and Deployment#

Docker Compose Configuration#

For local development and testing, the system creates the following services:

yaml
version: '3.8'
services:
  api:
    build: ./backend
    ports: ["8000:8000"]
    depends_on: [postgres, redis, kafka]
    environment:
      - DATABASE_URL=postgresql+asyncpg://user:pass@postgres/unicloud
      - KAFKA_BOOTSTRAP_SERVERS=kafka:9092

  sync_worker:
    build: ./backend
    command: celery -A app.worker.celery worker -Q sync
    depends_on: [redis, kafka]

  transfer_worker:
    build: ./backend
    command: celery -A app.worker.celery worker -Q transfer
    depends_on: [redis, kafka]

  postgres:
    image: postgres:15
    volumes: [pg_data:/var/lib/postgresql/data]

  redis:
    image: redis:7

  kafka:
    image: confluentinc/cp-kafka:7.4.0
    environment:
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092

  zookeeper:
    image: confluentinc/cp-zookeeper:7.4.0

  opensearch:
    image: opensearchproject/opensearch:2.11.0
    ports: ["9200:9200"]