v0.1.1 · ARCHITECTURE.md
System Architecture · saas archetype

PatchLAB architecture

Prompt → deterministic DSP → downloadable WAV / Vital preset / ZIP pack. A Next.js 16 frontend and a layered FastAPI backend sit behind an nginx TLS proxy, over PostgreSQL and a disk asset store. Generation is local, offline, and reproducible — no external AI dependency.

Frontend / edge Backend service Data / storage Security control ↓ request / data flow
Deployment topology — single docker compose up (db · api · web · proxy)
Browser

Next.js client — Studio / Library / Packs / Presets / Settings. Session via HttpOnly cookies; mutating requests carry X-Requested-With: patchlab.

HTTPS only
nginx — reverse proxy & TLS termination infra/nginx

Terminates TLS · forces HTTP→HTTPS 301 · HSTS · large header buffers (16k/8×32k) · security headers · trusts X-Real-IP from itself only. Routes / → web, /v1 & /api → api.

web — Next.js 16
App Router · React 19 · Tailwind v4 · Zustand 5

Standalone server. Token-only styling (globals.css), typed API client mapping RFC 9457 errors to fields, SVG waveform preview, dark-default theme.

api — FastAPI 0.137
Python 3.13 · uvicorn · SQLAlchemy 2.0 async

REST under /v1, health at /api/health. Runs alembic upgrade head on boot. Layered router → service → repository.

PostgreSQL 18
asyncpg · Alembic migrations

users · refresh_tokens · sounds · packs. SQLite used for tests/dev.

Asset store (volume)
ASSET_ROOT · UUID paths

Generated WAV / ZIP files. Traversal-safe resolver; per-user quota; anon TTL cleanup.

Backend layering — dependencies point downward only (backend/app/)
Routers api/v1/ · deps.py
HTTP I/O, Pydantic validation, auth dependencies, rate-limit & CSRF guards. Never touch the DB session.auth · sounds · packs
Services services/
Business logic + ALL DB writes — the scoped-write & ownership chokepoint (assert_owner). Owns transactions/commits.INV-12
Repositories repositories/
Read-only query construction over AsyncSession — parameterized SQLAlchemy selects, no string SQL.INV-1
Models models/
SQLAlchemy 2.0 declarative entities with the UNIQUE constraints the auth flow depends on.INV-5 · INV-6
Audio engine app/audio · pure DSP, no DB/HTTP
prompt_parser

Allow-list keyword → params. Untrusted text, never eval'd. INV-2

synth → render

NumPy/SciPy oscillators, ADSR, filter, distortion, reverb → soundfile PCM WAV. Seeded & reproducible; caps before allocation.

variations · preset · pack

N seeded takes · Vital .vital JSON · bounded-budget ZIP (zip-bomb guard).

Cross-cutting core app/core

security

  • Argon2id hashing
  • PyJWT, alg pinned
  • cookie sessions + rotation

ratelimit

  • slowapi per-route
  • auth before hash
  • per-IP downloads

storage

  • UUID paths only
  • realpath confinement
  • INV-11

config · logging · errors

  • pydantic-settings
  • JSON logs, redaction
  • RFC 9457 problem+json
Data model PostgreSQL · SQLAlchemy 2.0
users 1 → ∞ sounds, packs
idUUID PK
emailUNIQUE · INV-5
password_hashargon2id
display_name · is_active
refresh_tokens ∞ → 1 user
idUUID PK
user_idFK → users
jtiUNIQUE · INV-6
expires_at · revokedrotation + reuse
sounds ∞ → user · pack · parent
idUUID PK
owner_idFK · NULL = anon
pack_id · parent_idFK (refine lineage)
prompt · params · seedreproducible
file_path · expires_atasset + TTL
packs 1 → ∞ sounds
idUUID PK
owner_idFK → users
name · theme
file_path · size_bytesZIP on download
Request flow — POST /v1/sounds/generate (workflow W1)
Browser → nginx over HTTPSprompt + X-Requested-With header; HTTP→HTTPS redirect + HSTS
nginx → FastAPI router /v1/sounds/generaterate-limit (per-user / per-IP) · CSRF guard · optional auth dependency
Router → Pydantic validationprompt 1–500 chars · variations 1–8 · sample_rate/bit_depth enum · aggregate sample cap
SoundService (business logic + writes)quota check · prompt_parser (allow-list) · seeded variations
Audio engine renders each takesynth → soundfile WAV bytes; written via traversal-safe resolver
Persist + commit in the service layersounds rows (owner or anon+TTL) · INV-12 scoped write
201 response → variation table rendersdownload_url / preset_url per take; FileResponse streams the WAV on download
Architectural invariants — machine-checked by invariants.json
INV-1No string-interpolated SQL — parameterized queries only
INV-2No eval/exec of dynamic strings (prompt-injection guard)
INV-5/6UNIQUE on users.email & refresh_tokens.jti
INV-7Color only from the token layer — no ad-hoc hex
INV-10UI coverage — every screen, endpoint & workflow wired + e2e
INV-11Asset paths built only by the traversal-safe resolver
INV-12All DB writes live in services/ — routers never mutate
INV-13JWT decode pins the algorithm; secret from config
INV-14nginx enforces HTTPS redirect + HSTS + header buffers
+ more14 total · 12 machine-checkable · 2 manual
\← Gallery