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.
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_pathSHALL be set tocore, 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_pathfails - 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-dsnset 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-dsnunset - THEN no migration is applied
Scenario: Migration CLI commands
- WHEN the user runs
migrate up,migrate down, ormigrate 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 generateis 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