Federated Virtual Filesystem#
Architectural Master Plan and Implementation Guide#
Table of Contents#
- Project Abstract
- System Architecture
- Technology Specifications
- Data Model
- Core Subsystems
- Detailed Implementation Plan
- 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).
graph TD
subgraph Clients
Web[Web Client]
CLI[CLI Agent]
end
subgraph Load_Balancer
NGINX[Nginx Reverse Proxy]
end
subgraph Control_Plane
API[FastAPI Gateway]
Auth[Auth Service]
ConnMgr[Connection Manager]
VFSSvc[VFS Service]
API --> Auth
API --> ConnMgr
API --> VFSSvc
end
subgraph Message_Bus_and_State
Redis[(Redis - Cache/Broker)]
Kafka{{Apache Kafka}}
PG[(PostgreSQL - Metadata)]
Search[(OpenSearch - Index)]
end
subgraph Data_Plane
SyncWorker[Sync Worker]
TransferWorker[Transfer Worker]
IndexWorker[Index Worker]
end
subgraph External_Storage
S3[AWS S3]
GDrive[Google Drive]
NC[Nextcloud]
end
%% Data Flows
Clients --> NGINX --> API
API -- Read/Write --> PG
API -- Cache --> Redis
API -- Publish Events --> Kafka
Kafka -- Consume Commands --> SyncWorker
Kafka -- Consume Jobs --> TransferWorker
Kafka -- Consume File Events --> IndexWorker
SyncWorker -- Delta Sync --> S3 & GDrive & NC
SyncWorker -- Update State --> PG
SyncWorker -- Publish Changes --> Kafka
TransferWorker -- Stream Data --> S3 & GDrive & NC
TransferWorker -- Update Progress --> Redis
TransferWorker -- Finalize --> PG
IndexWorker -- Upsert Documents --> SearchTechnology 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.
erDiagram
USERS ||--o{ STORAGE_CONNECTIONS : owns
USERS ||--o{ VIRTUAL_NODES : owns
STORAGE_CONNECTIONS ||--o{ VIRTUAL_NODES : contains
STORAGE_CONNECTIONS ||--|| SYNC_STATES : maintains
VIRTUAL_NODES ||--o{ VIRTUAL_NODES : parent_of
USERS {
uuid id PK
string email
string password_hash
timestamp created_at
}
STORAGE_CONNECTIONS {
uuid id PK
uuid user_id FK
enum provider_type "s3|gdrive|nextcloud"
jsonb config "bucket, region, root_id"
string encrypted_credentials
enum status "active|error|syncing"
}
VIRTUAL_NODES {
uuid id PK
uuid parent_id FK "Self-referencing"
uuid connection_id FK
string name
boolean is_folder
ltree path "Materialized Path"
string provider_id "External ID"
string etag "Change detection"
bigint size_bytes
jsonb raw_metadata
timestamp indexed_at
}
SYNC_STATES {
uuid connection_id PK
string cursor "PageToken or DeltaToken"
timestamp last_successful_sync
}
JOBS {
uuid id PK
uuid user_id FK
enum type "transfer|sync"
enum status "pending|running|completed|failed"
jsonb progress
}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.
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.
- Ingest: Webhooks (Drive) or Event Notifications (S3) push events to the API.
- Queue: Events are published to the
sync.eventsKafka topic. - Process: Sync Workers consume events, fetch metadata from the provider, and upsert records in the
virtual_nodestable. - Index: Changes in
virtual_nodesemit events tofile.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.
- Container Orchestration:
- Create
docker-compose.ymldefining services:postgres,redis,kafka,zookeeper,opensearch. - Configure persistent volumes for data durability.
- Create
- Database Definition:
- Initialize SQLAlchemy Base and models (User, StorageConnection, VirtualNode).
- Create Alembic migration scripts to enable
ltreeextension and create tables.
- Authentication Service:
- Implement
POST /auth/registerandPOST /auth/loginusing JWT (JSON Web Tokens). - Implement
get_current_userdependency for FastAPI.
- Implement
Phase 2: Connection Management#
Objective: Allow users to link storage accounts.
- Encryption Utilities:
- Implement Fernet (symmetric encryption) helpers to store and retrieve provider credentials securely.
- Connection API:
- Implement
POST /connectionsto store provider config (bucket names, regions). - Implement
GET /connectionsto list active integrations.
- Implement
- Adapter Registry:
- Create the
ProviderRegistrypattern to instantiate the correct adapter class based on theprovider_typecolumn.
- Create the
Phase 3: S3 Integration (Base Provider)#
Objective: Implement full read/write capability for S3-compatible stores.
- S3 Adapter Implementation:
- Implement
list_childrenusingboto3. - Implement
generate_presigned_urlfor downloads and uploads.
- Implement
- VFS Browse API:
- Implement
GET /filesendpoint. Logic: Queryvirtual_nodesbyparent_id.
- Implement
- Initial Sync Logic:
- Create a simple Celery task
sync_s3_bucketthat lists all objects in a bucket and populatesvirtual_nodes.
- Create a simple Celery task
Phase 4: The Sync Engine#
Objective: Handle ongoing changes and multi-provider state.
- Kafka Configuration:
- Define topics:
system.commands,file.events,file.index.
- Define topics:
- Google Drive Integration:
- Implement
GoogleDriveAdapter. - Implement OAuth2 flow handling to acquire and store Refresh Tokens.
- Implement
get_changesusing the Drive Activity API.
- Implement
- Sync Worker:
- Create a consumer service using
aiokafka. - Logic: Listen for
SYNC_REQUESTED. Iterate through provider changes. Upsert/Delete rows in Postgres.
- Create a consumer service using
- Delta Sync:
- Implement logic to store and retrieve
sync_cursortokens from thesync_statestable.
- Implement logic to store and retrieve
Phase 5: Search and Indexing#
Objective: Enable fast search across the VFS.
- OpenSearch Setup:
- Define index mappings for files (name, size, MIME type,
ltreepath).
- Define index mappings for files (name, size, MIME type,
- Index Worker:
- Create a Kafka consumer for
file.events. - Logic: On
FILE_CREATEDorFILE_MODIFIED, transform the Postgres row into a JSON document and push to OpenSearch.
- Create a Kafka consumer for
- Search API:
- Implement
GET /search. Logic: Query OpenSearch, return list of matching file IDs, enrich with latest metadata from Postgres if necessary.
- Implement
Phase 6: Transfer Engine#
Objective: Enable moving files between providers.
- Transfer API:
- Implement
POST /transfers. Acceptssource_node_idanddestination_folder_id. - Creates a Job record in Postgres with status
PENDING.
- Implement
- Transfer Worker:
- Implement
process_transfer_jobCelery task. - Logic:
- Acquire source stream (
adapter.download_stream). - Acquire destination upload session (
adapter.initiate_upload). - Pipe stream from source to destination.
- Update Job progress in Redis.
- On success, create new VirtualNode and mark Job as
COMPLETED.
- Acquire source stream (
- Implement
Phase 7: Optimization and Production Readiness#
Objective: Prepare for scale.
- Rate Limiting:
- Implement Redis-based sliding window rate limiter for external API calls to prevent quota exhaustion.
- 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:
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"]