Postgres¶
A single infra-postgres container hosts most databases. Each application connects with its own role and is constrained to its own DB.
Databases¶
| Database | Size |
|---|---|
down_rabbit_hole |
25 GB |
litellm |
2914 MB |
jb2b |
1267 MB |
gamine_brain |
382 MB |
ghrepos |
220 MB |
vikunja |
12 MB |
expense_report |
8263 kB |
darah |
8231 kB |
dashboard |
7679 kB |
Gamine has its own Postgres container (gamine-db) because of its volume of writes and its independent backup/restore lifecycle. Odoo has its own (sandbox-odoo-db) for the same reason.
Extensions¶
pgvector— enabled onjb_brain,jb2b,geopolitics,obsidian_brainfor embedding searchpgcrypto— enabled where field-level encryption is needed (MedVault will use this when deployed)pg_stat_statements— enabled on all DBs for query profiling
Embedding dimensions¶
All vector columns use 768 dims (Gemini embedding via LiteLLM, free tier). Older 3072-dim columns are being migrated — tracked at Vikunja #491.
Access patterns¶
- Apps connect via Docker network using
infra-postgres:5432 - No public exposure
- Read replicas: none (not justified at this scale)
- Connection pooling: each app uses its own
asyncpgpool, sized to its worker count
Migrations¶
- Alembic per project, never raw SQL in code
- Every migration must have
up()ANDdown()— irreversible migrations are rejected at review - Migrations run on container start in dev; explicitly invoked in prod
Backups¶
See backups.md. pg_dump per DB, retained 30 days.