The generation worker and request handlers race on the database —
enough that orphan-recovery code exists in two places to clean up
after 'database is locked' failures. WAL lets readers proceed during a
write, synchronous=NORMAL is the recommended pairing, and the 30s
sqlite3 timeout waits on a locked database instead of raising
immediately.
Split the 2,578-line main.py (90 routes) into 12 domain-specific router
modules under routes/. main.py is now a 45-line entry point.
New structure:
- app.py: FastAPI instance, CORS, startup/shutdown, safe_content_disposition
- routes/: health, profiles, channels, generations, history, transcription,
stories, effects, audio, models, tasks, cuda
- services/cuda.py: moved from cuda_download.py
Also includes Phase 5 database/ package (from parallel agent):
- database/__init__.py re-exports all symbols for backward compat
- database/models.py, session.py, migrations.py, seed.py
All 90 routes verified registered and app imports cleanly.