2.1 KiB
Hardening Fixes
Architectural Decisions
Canonical migration runner
server/plugins/migrate.ts is the canonical migration runner (Nitro plugin, runs on server start). server/db/migrate.ts is the standalone CLI script kept for manual use via npm run db:migrate, but the plugin is authoritative.
SQLite
Appropriate for single-user/small-team. For multi-user production, evaluate PostgreSQL with Drizzle's pg adapter.
Audio serving
Currently served from /public/audio. To complete the private audio migration:
- Move audio generation output directory from
public/audiotoprivate/audio - Update all
audioPathvalues stored in lesson content JSON — paths are stored as/audio/...and need to become/api/audio/... - This requires a one-time data migration script
inFlightCourses Set
In-process only — does not survive server restarts. For multi-process deployments, use a DB flag or Redis.
Per-topic mutex
Same limitation — in-process only.
.env git history
git log --all -- .env returned no output — .env has never been committed to this repository. No key rotation required.
Rate limiting
Not yet implemented. Marked for manual addition via a Nitro middleware using a simple Map-based token bucket.
Cost tracking
costAI and costAudio fields are estimated values based on API-reported costs. Reconcile against OpenRouter and TTS provider dashboards monthly.
Items that could NOT be fixed automatically
- Full audio path migration (public → private/audio + updating stored JSON paths): requires a one-time data migration script
- Drizzle migration for ON DELETE CASCADE on foreign keys: SQLite doesn't support
ALTER TABLE ... ADD FOREIGN KEY, so CASCADE would require recreating all tables. Recommend doing this on next schema version if needed. - Full composable extraction from
learn/[id]/index.vue(useLessonState,useFocusMode,useBranchPoll): architectural refactor deferred, not a correctness issue. - Prompt versioning (
server/prompts/directory): deferred, not a correctness issue. - Full consola migration: deferred tech debt.