docs: D19 delivered — spec stamped with deviations, D-record, env docs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat/client-detail-redesign
Thomas Joise 4 days ago
parent 95df5cb5b9
commit 30a1ea1c0a

@ -60,8 +60,11 @@ cd apps/hq-web && npm run dev
- Owner login on first boot: `admin@tecnostac.com` + the one-time password printed in the - Owner login on first boot: `admin@tecnostac.com` + the one-time password printed in the
server log (change it immediately). The "Gmail disconnected" banner is expected until Gmail is connected. server log (change it immediately). The "Gmail disconnected" banner is expected until Gmail is connected.
- Env: `HQ_DATA_DIR` (DB location), `SIMS_PIN_PEPPER` (set once, never change), `HQ_SECRET_KEY` - Env: `DATABASE_URL` (set → Postgres engine, absent → SQLite at `HQ_DATA_DIR`; D19),
`SIMS_PIN_PEPPER` (set once, never change), `HQ_SECRET_KEY`
(before Gmail), `GOOGLE_*` (Gmail), `AWS_*` (Cost Explorer), `HQ_PORT` (default 5182). (before Gmail), `GOOGLE_*` (Gmail), `AWS_*` (Cost Explorer), `HQ_PORT` (default 5182).
- Postgres integration tests: `HQ_PG_TEST_URL=postgres://hq:hq_dev@localhost:5432/hq_test npm test`
(wipes that database each run — never point it at real data).
- Health check: `GET /api/health``{ ok: true }`. - Health check: `GET /api/health``{ ok: true }`.
- Verified state: `npm install` + typecheck clean, 346 tests pass. Exercise real flows end - Verified state: `npm install` + typecheck clean, 346 tests pass. Exercise real flows end
to end before claiming done. to end before claiming done.

@ -263,3 +263,29 @@ client-book filter UI; 4 minor — typed contact roles absent, dashboard/aging s
anchored on doc_date, non-atomic dbPassword PATCH, audit-outside-txn on three new anchored on doc_date, non-atomic dbPassword PATCH, audit-outside-txn on three new
write paths) — all confirmed and fixed in one pass (`fix(review)` commit). write paths) — all confirmed and fixed in one pass (`fix(review)` commit).
Suite at 345 tests / 66 files after the review pass. Suite at 345 tests / 66 files after the review pass.
## D19 — Postgres switch executed (D15 delivered) ✅ DELIVERED (2026-07-17)
The engine slice queued after D18, done BEFORE the real APEX cutover so production data
is born in Postgres and nothing is ever migrated. Spec:
`superpowers/specs/2026-07-17-postgres-switch-design.md`. The calls that matter:
- **One async DB interface, two engines.** Every repo/route/scheduler/test awaits
`db.all/get/run/exec/transaction`. better-sqlite3 stays for dev + the fast suite
(`SqliteDb`, statement-cached, manual BEGIN/SAVEPOINT); Postgres (`PgDb`, node-pg Pool)
is selected by `DATABASE_URL`. Repos keep `?` placeholders and portable SQL; the pg
adapter rewrites `?`→`$n`, pins transactions to one pooled client via AsyncLocalStorage
(nested = savepoints), and parses int8/numeric to JS numbers (paise stay integer math).
- **Postgres schema choices:** bigint for every paise column (int4 overflows at ₹2.15
crore), 0/1 flags stay INTEGER (repos say `active=1` on both engines), JSON stays TEXT
(node-pg auto-parses jsonb — would break JSON.parse at the repo edge), dates stay TEXT
ISO. Numbered migrations + schema_migrations runner (migrations-pg.ts), applied
atomically; the reminder rule_kind CHECK is born in its final widened form.
- **Proof:** default suite 346/346 on SQLite (zero behavior change); 5-test pg
integration suite (opt-in `HQ_PG_TEST_URL`, wipes its target) green on local
PostgreSQL 17 — migrations-from-zero, series numbering + due-date stamp, paisa-exact
payment→paid, ON CONFLICT exactly-once reminders, savepoint rollback, HTTP boot smoke.
- **Known nuance before go-live:** LIKE is case-insensitive on SQLite, case-sensitive on
Postgres — client search will match case-sensitively in prod until repos switch to
`LOWER(...) LIKE LOWER(?)`.
- Local dev Postgres: PostgreSQL 17 Windows service, superuser `postgres`, role `hq`,
databases `hq` (runtime) + `hq_test` (integration suite). Prod = RDS at go-live, same
`DATABASE_URL` mechanism.

@ -1,8 +1,23 @@
# HQ Console — Postgres Switch (D15 executed → D19) # HQ Console — Postgres Switch (D15 executed → D19)
> **STATUS: IN BUILD, started 2026-07-17.** The dedicated slice queued after the D18 > **STATUS: DELIVERED 2026-07-17.** All four phases landed same-day: async DB interface
> go-live cluster and **before** the real APEX cutover — so production data is born in > across every repo/route/test (default suite 346/346 on SQLite, zero behavior change),
> Postgres and nothing is ever migrated. > Postgres migration set + runner, pg adapter, `DATABASE_URL` engine selection, and a
> 5-test Postgres integration suite (opt-in `HQ_PG_TEST_URL`) verified green against a
> local PostgreSQL 17.
>
> Delivery deviations from the table below (recorded in migrations-pg.ts too):
> - **0/1 flags stay INTEGER** (not boolean) — repos say `active=1`; that SQL must be
> identical on both engines.
> - **JSON stays TEXT** (not jsonb) — node-pg auto-parses jsonb into objects, which
> would break the repos' JSON.parse at the edge; jsonb is a later pg-only ALTER if
> payload indexing is ever needed.
> - **Full-suite-on-pg** was scoped to a dedicated integration file (migrations-from-zero,
> series + due-date stamp, paisa-exact payment, ON CONFLICT idempotency, savepoint
> rollback, HTTP boot smoke) rather than re-running all 346 sqlite-fixture tests on pg.
> - Known dialect nuance to revisit before go-live: `LIKE` is case-insensitive on SQLite
> but case-sensitive on Postgres — client search/filters will match case-sensitively
> in production until switched to `LOWER(...) LIKE LOWER(?)`.
## 1. Goal & why now ## 1. Goal & why now

Loading…
Cancel
Save