PostgreSQL Database Runbook
This runbook is the operator reference for PostgreSQL health diagnostics, migrations, and incident handling across Stella Ops deployments. It is written for Platform on-call and the Database team, and every command, metric, and check below is grounded in source so it can be trusted in an incident.
Status: Reconciled against source — CLI surface in
src/Cli/StellaOps.Cli, migration host insrc/__Libraries/StellaOps.Infrastructure.Postgres, and Doctor Postgres checks insrc/Doctor/__Plugins/StellaOps.Doctor.Plugin.Postgres.
Reconciliation note (doc ↔ code): an earlier revision of this runbook documented a large
stella db/stella backup/stella service/stella network/stella secrets rotateCLI surface and a set ofstella_postgres_*metrics +StellaPostgres*Prometheus alerts. None of those commands, metrics, or alerts exist in the codebase. They have been replaced below with the commands and telemetry that are actually implemented, and the aspirational items are collected — clearly marked — under “Roadmap / not yet implemented” so the operator intent is not lost.
Scope
PostgreSQL database operations including health diagnostics, migrations, and common incident handling for Stella Ops deployments.
Persistence model invariant (see repo CLAUDE.md §2.7 and ADR-004): every service that owns a PostgreSQL schema auto-migrates its embedded SQL on startup via AddStartupMigrations(...) (StellaOps.Infrastructure.Postgres.Migrations.StartupMigrationHost). Startup (idempotent schema) migrations run automatically and block startup if pending release/data migrations exist; seed migrations remain operator-invoked. There is no manual init step in steady state — postgres-init/ scripts are first-run bootstrap fallbacks only.
Pre-flight Checklist
Required scopes
The diagnostic commands below are gated by Authority Doctor scopes (src/Authority/StellaOps.Authority/StellaOps.Auth.Abstractions/StellaOpsScopes.cs):
doctor:run— run standard diagnostic checks (stella doctor/stella doctor run)doctor:run:full— run the full/slow check set (stella doctor --mode full)doctor:export— generate a diagnostic support bundle (stella doctor export)doctor:admin— administrative Doctor operations
There is no dedicated database or backup scope in the catalog.
Environment Verification
# Connectivity + schema + pool, in one check (PostgreSQL Doctor plugin)
stella doctor --check check.postgres.connectivity
stella doctor --check check.postgres.pool
# Migration status for every module (uses STELLAOPS_POSTGRES_* env vars)
stella system migrations-status --module all
The Doctor
--checkoption takes a single check ID. Run it once per check (or use--category databaseto run all database checks together) — comma-separated lists are not parsed.
Metrics to Watch
The stella-ops-performance Grafana dashboard (devops/telemetry/dashboards/stella-ops-performance.json) charts connection-pool / query telemetry under the stella_db_* prefix:
stella_db_connections_active— active connections (compare againststella_db_connections_max)stella_db_connections_idle— idle connections in the poolstella_db_connections_max— configured pool ceilingstella_db_query_duration_seconds_bucket— query-latency histogram (e.g.histogram_quantile(0.95, sum(rate(stella_db_query_duration_seconds_bucket[5m])) by (le, query_type)))
Verify before relying on these panels. As of this writing the
stella_db_*names appear only in the dashboard JSON — no Stella service insrc/registers a meter that emits them (the only DB-connection gauge actually emitted in source isledger_db_connections_active, scoped to Findings.Ledger). Treat the fourstella_db_*series as the dashboard’s intended contract: the panels will read empty unless an exporter publishing those names is wired into your deployment. Confirm withcurl <service>/metrics | grep stella_db_against a running service before treating an empty panel as an incident.The earlier
stella_postgres_connections_active,stella_postgres_query_duration_seconds, andstella_postgres_pool_waitingmetric names are not referenced anywhere in the codebase (not even in the dashboard). There is no exported gauge for “connections waiting for the pool”.
Standard Procedures
SP-001: Daily Health Check
Frequency: Daily or on-demand Duration: ~5 minutes
Run all database-category diagnostic checks and capture the report:
stella doctor --category database --format json --output /tmp/db-health-$(date +%Y%m%d).json(
--outputwrites the formatted report to a file; the formatter honourstext|json|markdown.)Confirm migrations are converged (no pending release/data migrations, no checksum drift):
stella system migrations-status --module all --verboseReview platform dependency readiness (includes PostgreSQL among required dependencies):
stella admin diagnostics health --detail
Replication status, slow-query reports, and backup status do not have CLI commands today. See “Roadmap / not yet implemented” below.
SP-002: Connection Pool Tuning
When: Pool saturation observed in stella_db_connections_active approaching stella_db_connections_max.
Inspect pool state via the Doctor pool check:
stella doctor --check check.postgres.pool --verboseWatch pool/connection metrics on the
stella-ops-performanceGrafana dashboard (Connection pool utilization panel:stella_db_connections_active/_idle/_max).Adjust pool size by changing the owning service’s PostgreSQL options (
StellaOps.Infrastructure.Postgres.Options.PostgresOptions) through the service’s configuration/environment, then redeploy/restart the service through your normal compose/orchestration tooling.
There is no
stella config get/set Database:MaxPoolSize, nostella db pool ..., and nostella service restartcommand.stella configexposesshow/listplus the notify/integrations/feeds/registry/sources/signals/identity-providers subgroups — it does not set arbitrary key/value config.
SP-003: Backup and Restore
Backup/restore is not driven by a Stella CLI command today (no stella backup command group exists). The shipped backup/restore mechanism is a set of DevOps shell scripts plus the product-native stellaops-backup-crypto encryptor — see the companion Backup and Restore Operations runbook for the canonical procedure. Recovery from a bad migration is by PostgreSQL snapshot restore — see the migration-recovery runbook — consistent with the forward-only migration policy (ADR-004).
Operationally, take and restore backups with native PostgreSQL tooling (pg_dump / pg_basebackup / volume snapshots) against the database your deployment uses. After a restore, re-verify schema state:
stella system migrations-status --module all
stella system migrations-verify --module all
SP-004: Migration Execution
Startup migrations apply automatically when services boot. To drive migrations manually (for example during a controlled upgrade), use the stella system migration commands. These read the connection from STELLAOPS_POSTGRES_* environment variables unless --connection is supplied.
Preview pending migrations (dry run):
stella system migrations-run --module all --dry-run --verboseApply startup migrations:
stella system migrations-run --module all --category startupApply release migrations (gated — requires explicit approval):
# Release migrations refuse to run without --dry-run or --force: stella system migrations-run --module <module> --category release --dry-run stella system migrations-run --module <module> --category release --forceVerify migration success:
stella system migrations-status --module all stella system migrations-verify --module all # checksum verification stella doctor --check check.postgres.migrations
Module names come from
MigrationModuleRegistry; pass--module allfor every module or a single module name.stella admin seed-demo --confirmapplies demoseed-category data (development/demo only).
Incident Procedures
INC-001: Connection Pool Saturation
Symptoms:
stella_db_connections_activeat or nearstella_db_connections_max- Increased request latency; services logging connection-acquisition timeouts
Investigation:
# Pool health check (active/idle/max, with remediation hints)
stella doctor --check check.postgres.pool --verbose
# Confirm the database itself is reachable
stella doctor --check check.postgres.connectivity
Cross-reference the Connection-pool and Query-latency panels in the stella-ops-performance Grafana dashboard.
Resolution:
Identify load source — use server-side PostgreSQL inspection (
pg_stat_activity) to find long-running or stuck queries; terminate withpg_terminate_backend(pid)on the database server. (There is nostella db queries/stella db query terminateCLI command.)Scale the pool — raise the pool ceiling via the owning service’s
PostgresOptionsconfiguration/environment, then redeploy the service.Fix leaks — review application logs for unclosed connections and deploy a fix to the affected service.
INC-002: Slow Query Performance
Symptoms:
- P95 query latency rising on
histogram_quantile(0.95, sum(rate(stella_db_query_duration_seconds_bucket[5m])) by (le, query_type))
Investigation: Use server-side PostgreSQL tooling — pg_stat_statements, EXPLAIN (ANALYZE, BUFFERS) ..., and pg_stat_user_tables for bloat/dead-tuple counts. The CLI does not expose slow-query reports, EXPLAIN, index suggestions, or table statistics.
Resolution:
- Index optimization — add/adjust indexes via a forward-only migration in the owning service’s persistence library (embedded SQL;
CREATE INDEX IF NOT EXISTS ..., and preferCONCURRENTLYfor large tables). Migrations apply on the next service startup or viastella system migrations-run. - Vacuum / analyze — run
VACUUM/ANALYZEon the database server. - Query optimization — review and rewrite the offending query.
INC-003: Database Connectivity Loss
Symptoms:
- Services reporting database connection errors
check.postgres.connectivityfailing
Investigation:
# Targeted connectivity check (reports reason code + remediation)
stella doctor --check check.postgres.connectivity --verbose
# Platform dependency readiness (PostgreSQL appears as a required dependency)
stella admin diagnostics health --detail
For DNS/firewall/network reachability, use standard tooling (Test-NetConnection, nc, psql) against the database host/port — there is no stella network command group.
Resolution:
- Network issue — verify firewall rules, host routing, and DNS resolution of the database host.
- Database server issue — check the PostgreSQL service status, server logs, and disk space.
- Credential issue — verify the
STELLAOPS_POSTGRES_*connection settings the services use. (There is nostella db verify-credentialsorstella secrets rotatecommand;stella secretsmanages secret-detection rule bundles, not connection secrets.)
INC-004: Disk Space Pressure
Symptoms:
- Database write failures; PostgreSQL “no space left on device” errors
Investigation: Inspect on the database server with native tooling: pg_database_size(), the pg_total_relation_size() of the largest tables, and pg_stat_user_tables dead-tuple counts. The CLI does not expose disk-usage, table-size, or bloat reports.
Resolution:
- Immediate relief —
VACUUM(andVACUUM FULLon a maintenance window) to reclaim space on the server. - Retention — apply any module-level data-retention/pruning that the owning service supports through its own configuration (there is no generic
stella db prune/stella db archive). - Expand storage — grow the underlying volume per your deployment’s storage procedure and resize the filesystem.
Diagnostics & Evidence Capture
Generate a support bundle (Doctor report + optional logs + config snapshot):
stella doctor export --output /tmp/db-diag-$(date +%Y%m%dT%H%M%S).zip
# Optional: --include-logs (default true), --log-duration 4h, --no-config
Apply non-destructive fixes suggested by a Doctor report (dry-run by default; only commands whose first token is stella/./stella/stella.exe and that contain no {PLACEHOLDER} tokens are classed “safe” and executed when --apply is passed — see IsStellaCommand/ContainsPlaceholders in DoctorCommandGroup):
stella doctor fix --from /tmp/db-diag-report.json # preview
stella doctor fix --from /tmp/db-diag-report.json --apply # execute safe fixes
Caveat for the PostgreSQL checks:
PostgresConnectionPoolCheckemits remediation steps that callstella db queries …,stella db pool stats …,stella db config set …, andstella db pool reset …. Thosestella dbsub-commands are not implemented (see “Roadmap” — the registeredstella dbonly triggers Concelier jobs). They have no placeholders, sodoctor fix --applywill classify them “safe” and attempt them — each will fail with an unknown-command error rather than fix anything. Until that command tree ships, treat the pool check’s remediation block as advisory text, not executable fixes.
List the database checks available in this build:
stella doctor list --category database --verbose
Monitoring Dashboard
Grafana dashboard: devops/telemetry/dashboards/stella-ops-performance.json (“Stella Ops Performance”).
Relevant panels:
- Database query latency —
stella_db_query_duration_seconds_bucket - Connection pool —
stella_db_connections_active/stella_db_connections_idle/stella_db_connections_max
These panels query the
stella_db_*series, which are not emitted by any service insrc/today (see “Metrics to Watch” above). Until an exporter publishing those metric names is wired into the deployment, the panels render empty — this is a telemetry gap, not a database fault.There is also no dedicated PostgreSQL alert ruleset under
devops/telemetry/alerts/. TheStellaPostgresPoolExhausted/StellaPostgresQueryLatencyHigh/StellaPostgresConnectionFailed/StellaPostgresDiskSpaceWarningalerts referenced in earlier revisions of this runbook are not implemented as Prometheus rules. See “Roadmap” below.
Roadmap / not yet implemented
The following operator conveniences are commonly requested but do not exist in the codebase today. They are recorded here so the intent is preserved; do not reference them in procedures as if they ship:
- A rich operational
stella dbcommand tree (ping,migrations status,queries,pool stats,connections,query terminate/explain,vacuum,analyze,index suggest/create,stats tables,disk-usage,prune,archive,reindex,cleanup,replication status,diagnostics,verify-credentials). The wiredstella dbcommand today only triggers Concelier connector jobs (stella db fetch|merge|export). A separateDbCommandGroup(stella db status/db connectors …) exists in source but is not registered in the CLI root and returns synthetic data when the backend is unavailable. Note: thePostgresConnectionPoolCheckDoctor plugin already emits remediation steps that callstella db queries,stella db pool stats,stella db config set, andstella db pool reset— none of which are wired — so those steps are dead until this command tree ships. - A
stella backupcommand group (create/verify/list/restore). Backup/restore today is delivered by DevOps scripts +stellaops-backup-crypto, not a CLI verb — see backup-restore-ops.md. stella service restartandstella network(dns-lookup / test) helpers.stella config get/set <key>for arbitrary keys (currentstella configonlyshows resolved config andlists known config paths).- A PostgreSQL Prometheus alert ruleset (pool exhaustion, query-latency, connectivity, disk-space).
- A service-side exporter that actually emits the
stella_db_*metric family thestella-ops-performancedashboard charts. Today those names exist only as PromQL in the dashboard JSON; no meter insrc/registers them (the sole real DB-connection gauge isledger_db_connections_active, scoped to Findings.Ledger). - A gauge for “connections waiting for pool”.
Escalation Path
- L1 (On-call): Run Doctor checks, generate a support bundle, restart services via the deployment’s orchestration tooling.
- L2 (Database team): Query optimization, migration authoring, schema changes.
- L3 (Platform/infra support): Storage/host/network issues.
Source-reconciled. Verify the live CLI surface with stella --help, stella doctor list, and stella system --help before relying on any command above.
