Backend:
- password hashing via hashlib.scrypt
- stateless HMAC-SHA256 tokens (7-day expiry)
- POST /api/auth/login, /api/auth/register (admin), /api/auth/reset-password
- admin user created from NAT20_ADMIN_USERNAME/PASSWORD on first startup
- users table, campaign_shares table, created_by on campaigns
- require_user dependency on all routes except auth
- campaign sharing: GET/POST/DELETE /api/campaigns/{id}/shares
Frontend:
- AuthContext: user/token state, login/logout, global fetch Auth header
- Login page, Users page (admin user management)
- route protection, sidebar user info/sign out
Docker/CI:
- split backend/Dockerfile into thin app-only image
- backend/Dockerfile.deps builds the heavy WhisperX/PyTorch base
- CI builds deps only when requirements.txt changes
- docker compose pull now fetches ~100KB app layer instead of 3.5GB
3.9 KiB
Nat20 Notes — agent guide
Commands
make deps— one-time build of the heavy WhisperX/PyTorch layer (5-10 min)make build— fast app-only rebuild (seconds)docker compose pull && docker compose up -d— pull & run pre-built images from registrycd frontend && npm run dev— Vite dev server (proxies/api→localhost:8000)- No tests, no lint/typecheck scripts exist. Don't look for them.
Architecture
- Two Docker Compose services:
backend(Python 3.11, FastAPI, SQLite, WhisperX as lib) andfrontend(React 18 + Vite + Tailwind, served by nginx which proxies/api→ backend). - Data lives in Docker volume
app_dataat/data(SQLite DB +uploads/audio/transcripts/notessubdirs). No external DB. - Background jobs (transcribe, summarize) run via in-process
ThreadPoolExecutor(max_workers=2)— no Redis/Celery. - Frontend serves on port 8020 (d20 nod).
Critical convention: per-campaign settings schema
Settings are split into global (settings table, just onboarding_completed) and per-campaign (campaign_settings table, everything else). Every layer must share the exact same keys:
backend/app/config.py:CAMPAIGN_SETTINGS, frontend/src/api.ts:CampaignSettings, campaigns router, and Settings/Setup pages. New campaigns inherit settings from the "default" campaign on creation.
The settings router (/api/settings) only handles global; campaign settings live at /api/campaigns/{id}/settings.
When adding a setting key, add it to config.py:CAMPAIGN_SETTINGS, the frontend type, and both the backend router and frontend Settings page.
Docker / framework quirks
- Torch pinned to
2.3.1withcu121wheels (--extra-index-url https://download.pytorch.org/whl/cu121) — cuDNN ABI compat withctranslate2. Don't bump unpinned. - Backend has two Dockerfiles:
Dockerfile— thin, app-only. StartsFROM nat20-whisperx-base:latest. Used by CI for fast rebuilds and bymake build.Dockerfile.deps— full WhisperX base layer. Build once perrequirements.txtchange. Used by CI andmake deps.Makefile—make depsbuilds the heavy layer;make builddoes fast app-only rebuild.
- CI/CD pattern: Gitea runner builds & pushes
nat20-whisperx-base:latestonly whenrequirements.txtchanges, then builds & pushesbackend:latest(thin) on every push. Yourdocker compose pullonly downloads new app layers (~100 KB) — the 3 GB WhisperX layer stays cached. - ffmpeg required in runtime for audio extraction.
- nginx
client_max_body_size500M, proxy timeouts 3600s. Files >15MB auto-chunked by frontendcreateSession(). - Frontend changes in Compose mode require a rebuild (
docker compose up -d --build). Vite dev server is for local-only dev.
Optimised rebuild workflow
# One-time: build the heavy WhisperX/PyTorch layer
make deps
# Daily: rebuild only app code (seconds, not minutes)
make build
# Or with docker compose if you've done make deps first:
docker compose up -d --build
Auth
- First user is admin, created from
NAT20_ADMIN_USERNAME/NAT20_ADMIN_PASSWORDenv vars on first startup. - Admin can create users via the Users page. Users can share campaigns with other registered users.
- JWT tokens (HMAC‑SHA256, 7-day expiry) stored in localStorage. Global fetch interceptor adds
Authorization: Bearerto all/api/calls.
Tailwind theme
Custom colors (deep, panel, brass, ember, etc.) and fonts (Fraunces, Inter, IBM Plex Mono) in tailwind.config.js. Reusable component classes in frontend/src/styles.css (.card, .btn-primary, .btn-secondary, .input, .eyebrow) — use these over raw Tailwind utilities.
Constraints
- Requires NVIDIA Container Toolkit + HuggingFace token for speaker diarization.
- First run: setup wizard, then
onboarding_completedflag gates access to main UI. - Default Ollama endpoint:
http://localhost:11434.