Skip to content

Latest commit

 

History

54 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Google Drive Clone

This repository is the answer to the Google Drive Clone Challenge: a portfolio-grade cloud storage application built with a Rust backend, a TypeScript frontend, and a Railway-first deployment target.

The goal is to build a real product experience first, then document how the system can grow toward the larger system-design targets from the challenge.

Product Direction

The first version should be a working personal cloud drive. Current implemented scope:

  • Sign up and log in.
  • Upload files through resumable multipart uploads, with the direct single-object upload flow kept for compatibility.
  • Browse files and folders.
  • Download files.
  • Rename, move, delete, and restore items.
  • See storage usage.
  • Share files with another registered user by email.
  • Search files by name.

Future extensions:

  • Revocable share links.
  • Cursor-based sync API.
  • Local desktop or CLI sync client.

The MVP should feel usable by one real person. The architecture should still be explicit about how it would scale toward 20 million registered users, 50 MB of free storage per user, 50 MB max files, and 3 million uploads per day.

Proposed Architecture

Use a services-first architecture:

  • frontend: TypeScript/Next.js frontend.
  • backend: Rust HTTP API plus the worker binary entrypoint under src/bin.
  • docs: architecture notes, API docs, and deployment notes.

The backend owns metadata, authorization, direct and resumable upload completion, quota enforcement, sync change logs, public share links, and cleanup jobs. File bytes live in S3-compatible object storage. PostgreSQL stores durable metadata.

Repository Structure

Current structure:

frontend/
backend/
docs/
  api/
    bruno/

Current deployable services:

  • backend: Rust API and worker binaries with auth, direct/resumable upload, sharing, share links, sync, trash purge, folders, rename, move, and filename search.
  • frontend: Next.js app with auth, /drive, folder browsing, file actions, sharing, share links, trash, resumable recovery, and command-palette search.

API documentation and runnable Bruno requests live in docs/api.

Run locally:

cd backend
cargo test
PORT=8080 cargo run
curl http://127.0.0.1:8080/health

Core Components

Backend API:

  • Authentication and sessions.
  • File and folder metadata.
  • Direct upload creation and completion.
  • Resumable multipart upload sessions, parts, status, finalization, expiration, and cleanup.
  • Download authorization.
  • User-to-user sharing by email.
  • Search.
  • Quota enforcement.
  • Health checks and metrics.

Frontend:

  • Login and signup screens.
  • Drive browser.
  • Folder navigation.
  • Upload progress for resumable multipart uploads, with local session memory for continuing after selecting the same file again.
  • File actions.
  • Trash and restore flows.
  • User-to-user sharing controls.
  • Search.
  • Storage usage display.

Data stores:

  • PostgreSQL for metadata.
  • S3-compatible object storage for file bytes.
  • Redis or a queue only if background jobs need it.

Suggested Tech Stack

Backend:

  • Rust.
  • Axum for HTTP routing.
  • Tokio for async runtime.
  • SQLx for PostgreSQL.
  • Serde for JSON.
  • tower-http for tracing, CORS, and middleware.
  • An S3-compatible Rust client for object storage.

Frontend:

  • TypeScript.
  • React.
  • Next.js (App Router).
  • Tailwind CSS.
  • shadcn/ui.

Infrastructure:

  • Railway backend service.
  • Railway frontend service.
  • Railway PostgreSQL.
  • Railway S3-compatible bucket for the first deployment.
  • Railway worker service for cleanup jobs.

The storage interface must stay S3-compatible so the project can move from Railway buckets to another object storage provider later without changing the public API.

Data Model

Current metadata concepts:

  • users: account identity and storage quota.
  • folders: user-owned folder tree.
  • files: file-specific metadata, parent folder, object key, checksum, size, upload state, and trash state.
  • upload_parts: confirmed object-storage parts for resumable uploads.
  • file_shares: user-to-user file grants by registered account.

Future metadata concepts:

  • share_links: revocable private sharing tokens.
  • change_log: ordered events for sync clients.

Only completed files appear in the normal drive view. The current direct upload flow creates a pending file row, uploads one object through a presigned PUT URL, then verifies object length before marking the file complete.

Upload Design

Current implementation supports two upload paths.

Compatibility direct upload:

  1. Client calls POST /files/uploads with filename, size, parent folder, content type, and optional checksum metadata.
  2. API checks parent-folder ownership, quota, and file-size limits.
  3. API stores pending file metadata and returns a short-lived presigned PUT URL.
  4. Client uploads the full object directly to S3-compatible object storage.
  5. Client calls POST /files/{file_id}/complete.
  6. API verifies the stored object length, marks the file complete, and increments storage usage exactly once.

Resumable multipart upload:

  1. Client calls POST /files/uploads/resumable with file metadata.
  2. API checks quota and limits, starts an object-storage multipart upload, and stores the pending session.
  3. Client calls GET /files/uploads/{file_id}/status to discover confirmed parts.
  4. Client signs each missing part through POST /files/uploads/{file_id}/parts.
  5. Client uploads that byte range directly to object storage and reads the ETag response header.
  6. Client records the part with POST /files/uploads/{file_id}/parts/{part_number}.
  7. Client calls POST /files/uploads/{file_id}/finalize.
  8. API completes the multipart upload, verifies final object length, marks the file complete, and increments storage usage exactly once.

Resumable uploads use an explicit state machine:

  • pending
  • complete
  • expired

Measurable outcomes:

  • Failed uploads do not become visible files.
  • Completed uploads produce one metadata record and one stored object.
  • Resume state can be queried deterministically.
  • The backend never needs to load a 50 MB file into memory.

Download Design

Every download must be authorized before bytes are returned.

The API can either:

  • Return a short-lived signed object-storage URL.
  • Proxy the stream from object storage.

The signed URL path is preferred for scale because the application service avoids streaming large files through its own compute layer.

Measurable outcomes:

  • Authorized users can download exactly the bytes they uploaded.
  • Unauthorized users cannot download private files.
  • Download errors are tracked by reason.

Sharing Design

The current MVP uses private user-to-user sharing by email:

  • Owners can grant view/download access to a registered user's email.
  • Owners can revoke that grantee's access.
  • Shared downloads still pass through authorization logic.
  • Files remain private by default.

Revocable share links remain a later product extension.

Measurable outcomes:

  • Revoked grants stop working immediately.
  • Search and browse endpoints do not expose private files to other users.

Sync Design

Sync is a future contract milestone, not part of the current HTTP API. The intended first sync deliverable is a cursor-based API that can be tested before a full desktop client exists.

Minimum endpoint:

GET /sync/changes?cursor=<cursor>

Each change should include:

  • Item ID.
  • Change type.
  • Revision.
  • Timestamp.
  • Parent folder.
  • Relevant metadata.
  • Tombstone data for deletes.

Conflict default:

  • The server is the source of truth.
  • If local and remote edits conflict, preserve both versions.
  • The client-uploaded conflicting version becomes a conflict copy.

Measurable outcomes:

  • A client can fetch changes since a cursor and converge to server state.
  • Conflict behavior is deterministic and tested.

Railway Deployment Plan

Recommended Railway resources:

  • Backend service: Rust API.
  • Frontend service: TypeScript web app.
  • PostgreSQL service: metadata database.
  • Bucket: S3-compatible file storage.
  • Worker service: resumable upload expiry, trash purge, orphan cleanup, and quota reconciliation.
  • Optional Redis service: future queues or short-lived coordination.

Required deployment behavior:

  • /health returns healthy only when required dependencies are reachable.
  • Frontend reads the deployed API base URL from configuration.
  • Backend reads all configuration from environment variables.
  • Object storage credentials are injected through Railway variables.
  • Database migrations run through a controlled command.
  • Every release gets a smoke test: sign in, upload a small file, download it, delete it, restore it.

Initial deployment status:

  • Project: drive-clone.
  • API URL: https://api-production-bcad4.up.railway.app.
  • Web URL: https://web-production-c3311.up.railway.app.
  • API service source: IsraelAraujo70/drive-clone, branch google-drive-clone-challenge, root /backend.
  • Web service source: IsraelAraujo70/drive-clone, branch google-drive-clone-challenge, root /frontend.
  • Latest verified API deployment: 86164b07-f605-4724-9efb-32e3464baf9c.
  • Latest verified web deployment: ef2f4843-f122-400b-92ff-ec0157329d67.
  • Product resources for Postgres, buckets, API, web, and worker live in Railway.

Roadmap By Status

Implemented: MVP Web Drive

Delivered:

  • Rust API.
  • TypeScript web app.
  • User auth.
  • Direct file upload.
  • File download.
  • Folder browsing.
  • Rename, move, delete, and restore.
  • Storage quota display.
  • PostgreSQL metadata.
  • S3-compatible object storage.
  • Railway deployment.

Done: a user can sign up, upload a file, see it in the drive, download it, delete it, restore it, and see accurate storage usage.

Implemented: Sharing and Search

Delivered:

  • User-to-user sharing by email.
  • Shared download authorization.
  • Filename search.
  • Search indexes.
  • Access-control tests.

Done: users can share a file with another registered user, revoke that access, and search accessible files without leaking private files.

Implemented: Resumable Uploads

Delivered:

  • Upload session API.
  • Part tracking.
  • Resume status endpoint.
  • Frontend resume behavior.
  • Worker-owned expiration cleanup job.
  • Tests for interrupted uploads.

Done: selecting the same file again can resume from server-confirmed parts instead of restarting the full upload.

Implemented: Sync API, Share Links, and Worker Jobs

Delivered:

  • Per-owner change_log with gap-free cursors.
  • GET /sync/changes with upserts and tombstones.
  • Revocable public share links with hashed tokens.
  • Background worker for resumable expiry, trash purge, orphan cleanup, and quota reconciliation.

Done: clients can page a deterministic change feed, share files by public link, and rely on worker jobs to keep cleanup and quota state correct.

Done when the CLI can sync a local folder from remote changes and handle conflicts deterministically.

Future: Scale and Reliability Hardening

Deliver:

  • Load tests for metadata APIs.
  • Upload throughput tests.
  • Quota reconciliation job.
  • Object cleanup job.
  • Metrics dashboard.
  • Architecture diagram.
  • Failure-mode documentation.
  • Production-readiness checklist.

Done when the repo can explain and demonstrate how the design moves from portfolio deployment toward the stated scale targets.

Tests

Gate tests should be deterministic, local, fast, and run on every meaningful change.

Required gate test coverage:

  • Quota enforcement.
  • File ownership authorization.
  • User-to-user share authorization and revocation.
  • Folder tree integrity.
  • Search scoping.
  • Direct upload completion idempotency and object length validation.
  • Upload session state transitions.
  • Part resume logic.
  • Sync cursor ordering.

Cypress full-stack tests cover:

  • Upload metadata plus object storage write.
  • Resumable multipart upload against MinIO.
  • Download authorization plus object storage read.
  • Delete and restore lifecycle.
  • Worker-owned expired upload cleanup, trash purge, orphan cleanup, and quota reconciliation.
  • Browser-to-API-to-object-storage behavior with Docker services matching the local deploy topology.

CI and end-to-end tests should keep covering:

  • 50 MB upload design review: the upload path sends file bytes directly to object storage and never requires the full file in API memory.
  • Direct upload correctness: upload bytes through the signed URL, complete the file, request a download URL, and byte-compare the result.
  • Resume correctness: upload one part, query status, continue from recorded progress, finalize, and byte-compare the result.
  • Quota behavior: fill an account near 50 MB and reject the next upload with a clear error.
  • Future sync convergence: apply remote changes, fetch from a cursor, and verify client state.
  • Access control: attempt cross-user reads, downloads, and searches.
  • Deploy health: verify Railway health and a small upload/download smoke test.

Observability

Track:

  • Upload success rate.
  • Upload failure rate by reason.
  • Resume success rate.
  • Download success and error rates.
  • Storage used per user.
  • Quota rejection count.
  • User-to-user share grant and revoke counts.
  • Future share-link access count.
  • Background job retry count.
  • Deployment health checks.

Demo Script

  1. Sign up.
  2. Upload a file.
  3. Create a folder.
  4. Move the file into the folder.
  5. Download the file.
  6. Delete and restore the file.
  7. Start a resumable upload, confirm status after the first part, and finish it.
  8. Create and revoke a user share.
  9. Search for the file.
  10. Show deployment health and test results.

Local Development

Requirements: Docker with Compose Watch support. Rust and Node are only required when running services directly on the host.

# Full stack with file watching:
make dev

# Full stack in the background:
make up

# URLs:
# Web: http://localhost:3000
# API: http://localhost:8080/health
# MinIO console: http://localhost:9001

make dev runs docker compose up --watch --build. The web container syncs source files into the Next.js dev server for hot reload. The API container syncs Rust source and migration files, then restarts cargo run so code changes recompile inside the container. Dependency manifest changes rebuild the affected image.

Useful commands:

make logs
make ps
make down
make test
make clean

Direct host-run commands still work when needed:

# 1. Start only the dependencies
docker compose up -d postgres minio minio-create-bucket

# 2. Run the API (migrations run automatically on boot)
cd backend
DATABASE_URL=postgres://postgres:postgres@localhost:5433/drive_clone \
S3_ENDPOINT_URL=http://localhost:9000 \
S3_PUBLIC_ENDPOINT_URL=http://localhost:9000 \
S3_BUCKET=drive-clone \
S3_REGION=us-east-1 \
S3_URL_STYLE=path \
S3_ACCESS_KEY_ID=minioadmin \
S3_SECRET_ACCESS_KEY=minioadmin \
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000 \
PUBLIC_WEB_URL=http://localhost:3000 \
RESEND_FROM_EMAIL='Drive Clone <onboarding@resend.dev>' \
cargo run

# 3. Run the web app (in another terminal)
cd frontend
npm install
npm run dev

Environment examples live in backend/.env.example and frontend/.env.example. If the web dev server uses another port, add that exact origin to CORS_ALLOWED_ORIGINS, for example http://localhost:3100. Set RESEND_API_KEY in the API environment to send password reset emails through Resend. Without it, local reset links are logged by the API for development.

Tests

# Fast gate: Rust unit/use-case/domain tests plus Vitest
make test

# Product integration: Cypress browser -> Next.js -> Rust API -> Postgres -> MinIO
make test-e2e

# Everything
make test-all

Cypress is the product-level integration suite. It runs through the real Docker stack and covers authentication, resumable upload, download byte comparison, sharing, ACL-scoped search, trash restore/purge, and upload recovery. Backend Rust tests remain focused on fast unit, use-case, domain, and storage-helper coverage.

Current Status

Implemented so far:

  • Landing page, signup, login, forgot-password, and reset-password screens (English UI) with a protected /drive shell, built on Next.js + Tailwind CSS + shadcn/ui.
  • Rust API on Axum + SQLx + PostgreSQL: POST /auth/signup, POST /auth/login, POST /auth/password/forgot, POST /auth/password/reset, POST /auth/logout, GET /auth/me, and a DB-aware GET /health.
  • File upload/download backend: direct upload compatibility plus resumable multipart upload sessions, part signing, status, finalization, GET /files, and GET /files/{file_id}/download.
  • Folder organization backend and UI: POST /folders, GET /drive, GET /folders, PATCH /files/{file_id}, PATCH /folders/{folder_id}, recursive folder trash/restore, and /drive folder browsing.
  • Soft delete/trash/restore for files and folders.
  • User-to-user file sharing by email, shared-with-me, and revoke.
  • Public revocable share links with uniform 404 for invalid, revoked, expired, or trashed targets.
  • Filename search with owned/shared ACL scoping, trash excluded by default, PostgreSQL search indexes, and command-palette UI.
  • Sync change feed with tombstones and pagination.
  • Worker binary for expired resumable uploads, trash purge with quota decrement, orphan object cleanup, and quota reconciliation.
  • Argon2 password hashing; opaque bearer session tokens and reset tokens stored hashed (SHA-256), with reset tokens expiring after one hour and revoking existing sessions on use.
  • API docs in docs/api/README.md; migrations in backend/migrations.
  • Gate tests: fast Rust unit/use-case/domain/storage-helper tests plus web Vitest tests. Cypress owns product-level HTTP integration through the real Docker stack.
  • Repo-connected Railway deployments for the API and web services.

Next milestone: a local Rust sync client can consume the implemented sync API.

About

Production-grade cloud storage with Rust, Next.js, PostgreSQL, S3, resumable uploads, sharing, sync, background jobs, and Railway.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages