A full-stack file management application built with Turborepo, featuring a Next.js frontend and FastAPI backend.
- Node.js (v22 or higher)
- Python 3.13+
- Supabase account with a PostgreSQL database
- uv Python package manager (
brew install astral-sh/tap/uvorpip install uv)
git clone git@github.com:yingtung/file-manager.git
cd file-manager
# Install Node.js dependencies
npm install
# or
yarn install- Create a new project on Supabase and wait for provisioning
- Get your database connection string from Settings > Database (URI format)
- Create a storage bucket named
files(or your preferred name) in Storage settings - Get your API credentials from Settings > API:
- Project URL
anonpublic key (for frontend)service_rolekey (for backend)
cd apps/api
cp .env.example .envEdit .env and add:
DATABASE_URL=postgresql://postgres:[YOUR_PASSWORD]@db.[YOUR_PROJECT_REF].supabase.co:5432/postgres
SUPABASE_URL=https://[YOUR_PROJECT_REF].supabase.co
SUPABASE_SERVICE_ROLE_KEY=[YOUR_SERVICE_ROLE_KEY]
SUPABASE_BUCKET_NAME=filesInstall Python dependencies:
uv synccd ../webCreate .env.local:
NEXT_PUBLIC_SUPABASE_URL=https://[YOUR_PROJECT_REF].supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=[YOUR_ANON_KEY]
NEXT_PUBLIC_SUPABASE_BUCKET_NAME=files
NEXT_PUBLIC_API_URL=http://localhost:8000From the project root:
npm run dev
# or
yarn devThis starts:
- Frontend:
http://localhost:3000 - API:
http://localhost:8000(API docs athttp://localhost:8000/docs)
- Visit
http://localhost:3000 - Sign up for a new account
- Confirm your email (check Supabase dashboard or email inbox)
- Log in and upload files
The project uses Turborepo for managing a monorepo containing:
- Frontend (
apps/web): Next.js application with React Server Components - Backend (
apps/api): FastAPI Python application - Shared packages: TypeScript configs, ESLint configs, and UI components
Next.js with App Router:
- Uses React Server Components for initial rendering
- Client components for interactive features (file upload, table sorting)
- Server-side Supabase client for secure authentication checks
- Client-side Supabase client for user-initiated actions
State Management:
- Local React state for UI components
- TanStack Table for table state (sorting, pagination)
- No global state management (kept simple for MVP)
Rationale: Next.js App Router provides modern React patterns with built-in optimizations. Local state management is sufficient for current feature set.
FastAPI with SQLModel:
- SQLModel: Combines SQLAlchemy ORM with Pydantic validation
- Dependency Injection: Authentication, database sessions, and pagination via FastAPI dependencies
- RESTful API: Clear separation of concerns with route handlers
Authentication Flow:
- Frontend authenticates users via Supabase Auth (handles JWT generation)
- Frontend includes JWT access token in
Authorization: Bearer <token>header - Backend validates token via Supabase client's
auth.get_user()method - Backend extracts user ID from validated token for authorization
Rationale: Leverages Supabase's battle-tested authentication while keeping business logic in the backend.
PostgreSQL (Supabase):
- File metadata stored in PostgreSQL
- Actual files stored in Supabase Storage (object storage)
- Database stores references to storage paths
Rationale: Separates metadata queries (SQL) from file storage (object storage), enabling efficient queries while handling large files appropriately.
- Service Layer Pattern:
SupabaseServicesingleton manages Supabase client lifecycle - Dependency Injection: FastAPI dependencies for cross-cutting concerns (auth, DB sessions)
- Schema Separation: SQLModel/Pydantic schemas for validation (
FileCreate,FileRead,FileUpdate) - Repository-like Pattern: Database operations encapsulated in route handlers (could be extracted to repositories for larger scale)
-
No Authorization Checks: The API validates authentication but doesn't verify users can only access/modify their own files. The
owner_idfield exists but isn't enforced in update/delete operations. -
Storage Path Synchronization: If a file is deleted from Supabase Storage directly (outside the API), the database record remains, creating orphaned records.
-
Basic Error Handling: Error messages may expose internal details that should be sanitized in production.
-
Signed URL Expiration: Download links expire after 1 hour (hardcoded); no configurable expiration or refresh mechanism.
-
Supabase for Both Auth and Storage:
- ✅ Pros: Unified platform, managed infrastructure, built-in auth
- ❌ Cons: Vendor lock-in, potential cost scaling
-
Monorepo vs. Separate Repos:
- ✅ Pros: Shared code, unified tooling, atomic commits
- ❌ Cons: More complex initial setup, larger repository
-
Python Backend vs. TypeScript/Node.js:
- ✅ Pros: FastAPI performance, strong typing with Pydantic, mature ecosystem
- ❌ Cons: Two language ecosystems, requires Python knowledge
-
Client-Side File Upload Directly to Supabase:
- ✅ Pros: Reduces backend load, faster uploads, better scalability
- ❌ Cons: Less control over validation, requires careful security policies
- Add authorization checks in API endpoints (users can only modify their own files)
- File preview capabilities (images, PDFs, videos)
- File search functionality (full-text search on filenames/metadata)
- Version history for file updates
- Add database connection pooling optimization
- Add CI/CD pipeline with automated deployments
- Improve error logging and monitoring (Sentry, structured logging)
- Add database migrations management (Alembic setup)
- Add event-driven architecture for file processing workflows