PostgreSQL Service
Purpose: Primary database for Fulcrum state, users, policies, and audit logs Audience: Backend Engineers, DevOps Source of Truth: TRUTH_MAP.md
Last Updated: February 1, 2026
Purpose
PostgreSQL serves as Fulcrum's primary database, storing: - User accounts and tenant information - Policies and policy evaluations - Execution envelopes and state - Audit trail events - Budget allocations and usage
Key Feature: Row Level Security (RLS) provides automatic tenant isolation.
Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
POSTGRES_CONN_STR |
Yes | - | Full connection string |
DATABASE_URL |
Yes | - | Alternative connection string |
POSTGRES_USER |
No | fulcrum |
Database username |
POSTGRES_PASSWORD |
No | fulcrum |
Database password |
POSTGRES_DB |
No | fulcrum |
Database name |
Connection String Format
Connection
| Environment | Connection |
|---|---|
| Local (Docker) | postgresql://fulcrum:fulcrum@localhost:5432/fulcrum |
| Railway (Production) | timescaledb-docker.railway.internal:5432 |
| Database Name | fulcrum_metrics |
| App Schema | fulcrum |
| Metrics Schema | metrics |
Note: Production uses POSTGRES_CONN_STR from Doppler/Railway secrets.
Health Check
# Local
pg_isready -h localhost -p 5432 -U fulcrum
# With psql
psql "$POSTGRES_CONN_STR" -c "SELECT 1;"
# Check RLS is enabled
psql "$POSTGRES_CONN_STR" -c "SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';"
Schema Overview
Core Tables
| Table | Purpose | RLS |
|---|---|---|
tenants |
Tenant accounts | No (superuser only) |
users |
User accounts | Yes |
policies |
Policy definitions | Yes |
envelopes |
Execution envelopes | Yes |
events |
Audit trail | Yes |
budgets |
Budget allocations | Yes |
TimescaleDB Hypertables
| Table | Purpose | Retention |
|---|---|---|
metrics |
Time-series metrics | 90 days |
cost_events |
Token/cost tracking | 90 days |
Row Level Security
Every table with tenant_id has RLS policies:
-- Enable RLS
ALTER TABLE envelopes ENABLE ROW LEVEL SECURITY;
-- Create policy
CREATE POLICY tenant_isolation ON envelopes
USING (tenant_id = current_setting('fulcrum.current_tenant')::uuid);
-- Set tenant context (done by application)
SET fulcrum.current_tenant = 'tenant-uuid';
Failure Modes
| Failure | Impact | Detection | Recovery |
|---|---|---|---|
| Connection timeout | API returns 503 | Health check fails | Restart connection pool |
| Disk full | Writes fail | Monitoring alert | Expand storage |
| RLS bypassed | Data leak | Audit log review | Immediate patch |
| Connection exhaustion | New requests fail | Pool metrics | Increase pool size |
Backup & Recovery
Railway Managed
- Automatic daily backups (7-day retention)
- Point-in-time recovery available
- Access via Railway dashboard
Manual Backup
Performance Tuning
-- Check slow queries
SELECT query, calls, mean_time, total_time
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 10;
-- Check index usage
SELECT relname, idx_scan, seq_scan
FROM pg_stat_user_tables
WHERE seq_scan > idx_scan;
Related Documents
- DEPLOYMENT_GUIDE.md - Setup instructions
- Data Architecture - Database design
Back to Runbooks | Documentation