Skip to content

Latest commit

 

History

History
130 lines (100 loc) · 5.1 KB

File metadata and controls

130 lines (100 loc) · 5.1 KB

Architecture

Components

  • apps/web/ — Next.js 16 frontend (App Router, Tailwind v4, shadcn/ui)
    • Dashboard with stats, upload chart, recent uploads
    • File upload with drag-and-drop, progress tracking
    • File browser with preview, download, delete
    • Dark mode via next-themes
  • services/api/ — FastAPI backend (layered architecture)
    • REST API for file upload, listing, deletion
    • B2 S3 integration via boto3
    • File metadata extraction (images, PDFs)
    • Health check endpoint with B2 connectivity verification
    • Structured JSON logging with request tracing
    • Prometheus-format metrics endpoint
  • packages/shared/ — TypeScript type definitions
    • Mirrors Pydantic models from the API
    • Consumed by apps/web/ as workspace dependency

Backend Layering

The API follows a strict layered architecture:

types/     Pydantic models — no logic, no imports from other layers
  |
config/    Settings (pydantic-settings) — depends only on types
  |
repo/      Data access (boto3 B2 client) — no business logic
  |
service/   Business logic — calls repo, returns types
  |
runtime/   FastAPI routes — calls service, never repo directly

Layering Rules

  1. Dependencies flow downward only: types -> config -> repo -> service -> runtime
  2. No backward imports (e.g., service must not import from runtime)
  3. boto3 only allowed in repo/ layer
  4. All boundary data uses Pydantic models (no raw dicts across layers)
  5. Each file stays under 300 lines

Directory Structure

services/api/
  main.py                  App entrypoint, middleware, router registration
  app/
    types/                 Pydantic models (FileMetadata, UploadStats, etc.)
    config/                Settings loaded from environment
    repo/                  B2 S3 client (data access layer)
    service/               Business logic (upload, files, metadata)
    runtime/               FastAPI route handlers
  tests/                   pytest tests (structural + integration)

Boundary Invariants

  • No external SDK leakage: boto3 is only imported in app/repo/. All other layers interact with B2 through the repo interface.
  • No raw dicts at boundaries: All data crossing layer boundaries uses typed Pydantic models.
  • No mutable globals: Configuration is read-only after init. No module-level mutable state shared between layers.
  • Validated inputs: All HTTP inputs validated by FastAPI/Pydantic. All file keys validated against prefix allowlist.

Deployment

  • Local devpnpm dev runs both services via concurrently
    • Web: localhost:3000
    • API: localhost:8000
  • Railway — two services from the same repo
    • See infra/railway/README.md for configuration

Data Stores

  • Backblaze B2 — object storage (S3-compatible API)
    • All uploaded files stored in a single bucket
    • File listing and metadata via S3 list_objects_v2 / head_object
    • No application database — B2 is the sole data store

External Services

  • Backblaze B2 S3 API — file storage, retrieval, deletion, presigned URLs

Trust Boundaries

See docs/SECURITY.md for full security documentation.

  • Frontend -> API — CORS-restricted to configured origins
  • API -> B2 — authenticated via application keys, signature v4
  • Client -> B2 — presigned URLs for download (10-min expiry, forced attachment)

Data Flows

  • Upload: Browser -> POST /upload (multipart) -> API validates -> service orchestrates -> repo writes to B2 -> metadata extracted -> response
  • List: Browser -> GET /files -> service calls repo -> returns file list
  • Download: Browser -> GET /files/{key}/download -> service validates key -> repo generates presigned URL -> browser downloads
  • Delete: Browser -> DELETE /files/{key} -> service validates key -> repo deletes from B2

Observability

  • Structured JSON logging on all requests with request_id
  • Request timing middleware (logs duration per request)
  • /metrics endpoint (Prometheus format: request count, latency, upload count)
  • /health endpoint (B2 connectivity check)

Canonical Files

  • Layered API handler: services/api/app/runtime/upload.py
  • Service orchestration: services/api/app/service/upload.py
  • B2 data access (repo layer): services/api/app/repo/b2_client.py
  • Pydantic models: services/api/app/types/ (files.py, upload.py, stats.py, formatting.py)
  • Config (pydantic-settings): services/api/app/config/settings.py
  • Structural tests: services/api/tests/test_structure.py
  • Frontend API client: apps/web/src/lib/api-client.ts
  • Shared TypeScript types: packages/shared/src/types.ts

Core Features

References