This service uses PostgreSQL. Schema and seed scripts are in:
services/api/database/migrations/services/api/database/seeds/
newsletter_subscribers— email opt-in list with double-opt-in confirmationcontact_form_submissionswaitlist_entriesanalytics_eventscontent_managementaudit_logs— general audit trail (UUID primary key)audit_log— append-only admin-operation audit log (bigserial primary key)email_jobs— async email queue tracking
001_enable_pgcrypto.sql002_create_newsletter_subscriptions.sql— createsnewsletter_subscriberstable003_create_contact_form_submissions.sql004_create_waitlist_entries.sql005_create_content_management.sql006_create_analytics_events.sql007_create_audit_logs.sql008_create_email_tracking.sql009_add_newsletter_indexes.sql— performance indexes onnewsletter_subscribers010_create_audit_log.sql— append-onlyaudit_logtable for admin operations010_add_soft_delete_newsletter.sql— addsdeleted_attonewsletter_subscribers
Note: Two migration files share the
010_prefix. Apply them in lexicographic order (010_add_soft_delete_newsletter.sqlbefore010_create_audit_log.sql) or rename one to011_to avoid ambiguity with migration runners that sort by filename.
Pool sizing and timeouts are fully env-configurable — no code changes needed for different deployment sizes.
| Variable | Default | Description |
|---|---|---|
DB_POOL_MIN_CONNECTIONS |
5 |
Minimum idle connections kept open |
DB_POOL_MAX_CONNECTIONS |
25 |
Maximum concurrent connections |
DB_POOL_ACQUIRE_TIMEOUT_SECS |
5 |
Seconds to wait for a free connection before error |
DB_POOL_IDLE_TIMEOUT_SECS |
(sqlx default) | Seconds before idle connections are reaped (0 = disabled) |
DB_POOL_MAX_LIFETIME_SECS |
(sqlx default) | Max lifetime of a connection in seconds (0 = disabled) |
DB_QUERY_TIMEOUT_SECS |
30 |
Per-query execution timeout; queries exceeding this return an error |
Sizing guidance:
- Small / dev:
DB_POOL_MIN_CONNECTIONS=2 DB_POOL_MAX_CONNECTIONS=5 - Medium:
DB_POOL_MIN_CONNECTIONS=5 DB_POOL_MAX_CONNECTIONS=25(default) - Large / high-traffic:
DB_POOL_MIN_CONNECTIONS=10 DB_POOL_MAX_CONNECTIONS=100
Pool metrics are exposed on the /metrics Prometheus endpoint under the db_pool_* family.
Run from the workspace root:
for f in services/api/database/migrations/*.sql; do
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f "$f"
doneOr use the provided script:
bash services/api/scripts/run_migrations.shThis repository uses forward-only SQL migrations. For rollback:
- Write explicit reverse scripts before production rollout.
- Restore from backup/snapshot for emergency rollback.
for f in services/api/database/seeds/*.sql; do
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f "$f"
done- Daily logical backups with
pg_dump, 30-day retention. - Weekly full snapshot, 90-day retention.
- Quarterly restore drills in staging.
- Encrypt backup storage at rest.
analytics_events: 13 months raw, then archive/aggregate.audit_logs/audit_log: 24 months minimum for compliance.contact_form_submissions: 12 months unless legal hold.newsletter_subscribers/waitlist_entries: retain active records; hard-delete on GDPR request.
- UUID primary keys via
gen_random_uuid()(most tables);audit_logusesBIGSERIAL. - All tables include
created_at/updated_attimestamps. - Soft deletes via
deleted_atincontent_management,audit_logs, andnewsletter_subscribers. - Indexes on high-frequency query fields (
email,status,created_at).