docs(generic): document default Postgres cluster and cert-CN mapping flow

Call out magrathea (primary) / frankie (standby) as the default Postgres
cluster and document the concrete steps to grant an app access: create
roles on the primary, drop a pg_ident.conf.d file on both servers, and
reload postgresql-18. The both-servers detail is easy to miss and costs
the app during a failover.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-22 14:13:17 +03:00
parent 2bc1a08055
commit c5ea03b026

View File

@@ -177,8 +177,26 @@ Tauri. Consumes the same `<app>-api` as the web client. Shares types via the `<a
### Central database: Postgres
Default for any app with a central data store.
- **Default server: `magrathea.kosherinata.internal:5432`**, with `frankie.hanzalova.internal` as a streaming standby. Unless a project explicitly specifies otherwise, assume a new app uses this cluster. Postgres 18 (path: `/var/lib/pgsql/18/data/`).
- Connection is **mTLS with passwordless auth**. Host-level client certificates issued by the internal step-ca, with cert CN → pg role mapping via `pg_ident.conf`.
- No passwords in config files, ever. Connection strings reference cert paths.
- No passwords in config files, ever. Connection strings reference cert paths (§11 TLS / PKI).
**Granting an app access to the database:**
1. Create the Postgres role(s) the app needs (e.g., `<app>_rw`, `<app>_ro`) on the **primary only** — replication carries them to the standby.
2. Map the app host's cert CN to the Postgres role by dropping a file at `/var/lib/pgsql/18/data/pg_ident.conf.d/<app-host-fqdn>.conf` with one line per mapping:
```
cert_cn <app-host-fqdn> <db-username>
```
Multiple lines if the host connects as more than one role.
3. Deploy the **same** ident drop-in to **both** `magrathea` and `frankie` — standbys don't replicate `pg_ident.conf` contents, and a failover to a server missing the mapping will lock the app out.
4. On each server, reload Postgres to pick up the change (no restart needed):
```
sudo systemctl reload postgresql-18
```
5. Verify from the app host by connecting with its host cert and confirming the role resolves as expected.
`deploy.sh` should handle steps 24 idempotently when an app is being deployed to a new host (or when a host's cert CN changes).
- Migrations via `sqlx-cli` or `refinery`; migration files live in `crates/<app>-data/migrations/`.
- **Migrations are sequentially versioned and immutable once committed.** File naming follows the tool's convention (`V0001__init.sql`, `V0002__add_users.sql`, … for refinery; `0001_init.sql`, `0002_add_users.sql`, … for sqlx). Each new schema change lands as a **new** file with the next sequence number — **never** edit a migration that has already been committed, even if it hasn't been deployed yet, because checksums diverge and the migration runner will refuse to start (or worse, leave production out of sync with dev).
- Schema changes are forward-only in production. Destructive migrations require a dedicated maintenance window and an explicit plan.