Files
member-console/openspec/specs/postgres-database/spec.md
T
cgalo5758 715404500a Archive the runtime database user and the boot that serves first
serve-before-dependencies (#141) and runtime-database-user (#23) move to
the archive, and their deltas are synced into openspec/specs. The two
Purpose edits a delta cannot make are made here: temporal-connection's
Purpose says start connects in the background and retries for the life
of the process, and error-pages' names the 503.

What the two investigations learned beyond each decision moves into the
docs:

- go-conventions.md: a new section on code that reaches a service that
  answers after the listener opens (holders, per-request reads, the
  refused write, retryloop, viper writes before the listener).
- production-deployment.md: what a liveness probe requests, and why it
  must not wait on Temporal or the identity provider.
- building-an-integration.md: declared paths skip the session layer;
  a completed workflow id runs again, and the guarded first update.
- models/payments-billing.md: invariant 14 states the 503 and
  Discourse's failed rows; invariant 15 states the guarded update.
- operator-ux-conventions.md: an error answer carries no HX- header.
- database-management.md: why writers hold only the four DML
  privileges, identity columns and sequences, the qualified SQL the
  migration user runs, and sqlc alias lists for set-returning functions.
- database-locks.md: rule 9, a row lock on a table the writer cannot
  update is taken in a SECURITY DEFINER function.
- testing.md: privilege tests drop to console_runtime, race-only breaks
  as command records, the race run's -p 1, synctest for timer loops,
  and test workers off the console's task queue.

Both archived design.md files gain the options weighed and the drafts
the approved copy replaced.
2026-10-24 02:00:58 -04:00

4.0 KiB

postgres-database

Purpose

Defines PostgreSQL as the application database: connection via pgx, migrations via goose, and code generation via sqlc.

Requirements

Requirement: PostgreSQL connection via pgx driver

The system SHALL connect to PostgreSQL using the pgx/v5 driver with stdlib compatibility mode (pgx/v5/stdlib). After establishing the connection, the system SHALL ensure search_path = core, public so domain tables resolve without schema qualification.

Scenario: Successful connection

  • WHEN the application starts with a valid PostgreSQL DSN
  • THEN a database connection pool is established and ready for queries
  • AND the connection's search_path SHALL be set to core, public

Scenario: Connection failure

  • WHEN the application starts with an invalid or unreachable PostgreSQL DSN
  • THEN the application fails to start with a descriptive error message

Scenario: search_path failure

  • WHEN the connection succeeds but SET search_path fails
  • THEN the connection SHALL be closed
  • AND the application SHALL fail to start with a descriptive error message

Requirement: PostgreSQL connection string configuration

The system SHALL accept a PostgreSQL connection string via the --db-dsn flag in the format postgres://user:password@host:port/dbname?sslmode=disable.

Scenario: DSN from command line flag

  • WHEN the application is started with --db-dsn "postgres://user:pass@localhost:5432/mydb"
  • THEN the application connects to the specified PostgreSQL database

Scenario: DSN with SSL mode

  • WHEN the DSN includes ?sslmode=require
  • THEN the connection uses SSL/TLS encryption

Requirement: Connection pool configuration

The system SHALL configure the connection pool with sensible defaults for PostgreSQL (max open connections, max idle connections, connection lifetime).

Scenario: Default pool settings applied

  • WHEN the application connects to PostgreSQL
  • THEN the connection pool is configured with max open connections, max idle connections, and connection lifetime limits

Requirement: Database migrations via goose

The system SHALL use goose to manage PostgreSQL database migrations with embedded migration files. Migrations SHALL run on the migration user's connection (db-migrate-dsn), at startup when it is set and through the migration CLI commands, and never on the runtime user's connection (db-dsn).

Scenario: Migrations run on startup

  • WHEN the application starts with db-migrate-dsn set and connects to PostgreSQL
  • THEN pending migrations are automatically applied on the migration user's connection

Scenario: No migrations without the migration connection string

  • WHEN the application starts with db-migrate-dsn unset
  • THEN no migration is applied

Scenario: Migration CLI commands

  • WHEN the user runs migrate up, migrate down, or migrate status
  • THEN the corresponding goose operation is executed against the PostgreSQL database named by db-migrate-dsn

Requirement: sqlc code generation for PostgreSQL

The system SHALL use sqlc configured with engine: "postgresql" to generate type-safe Go code from SQL queries.

Scenario: Query generation

  • WHEN sqlc generate is run
  • THEN Go code is generated using PostgreSQL syntax and types

Requirement: Schema with users, sites, and payments tables

The system SHALL maintain the existing data model with users, sites, and payments tables using PostgreSQL data types.

Scenario: Tables created by migration

  • WHEN migrations are applied to a fresh database
  • THEN the users, sites, and payments tables exist with appropriate columns, constraints, and indexes

Scenario: Foreign key constraints enforced

  • WHEN a site or payment references a non-existent user
  • THEN the database rejects the operation with a foreign key violation error

Scenario: Cascading deletes

  • WHEN a user is deleted
  • THEN their associated sites and payments are automatically deleted