feat(api): add DB-touching /health/ready readiness probe (GRO-2678) #233

Merged
Flea Flicker merged 1 commits from feat/gro-2678-db-readiness-probe into dev 2026-08-09 09:26:18 +00:00
Member

Summary

Adds GET /health/ready — a public, DB-touching readiness endpoint registered before the /api/* auth middleware so it is reachable by K8s readinessProbe on pod port 3000 without auth.

Behaviour

  • 200 {"status":"ready"} — DB query succeeds, schema is present
  • 503 {"status":"degraded"} — DB query throws for any reason (schema dropped 42P01, connection refused, etc.)
  • Logs the pg error code to stdout on failure; never leaks SQL or connection strings in the response body

Why this matters

/health returns {"status":"ok"} with no DB check. This mask allowed the GRO-2678 PROD schema drop to go undetected for ~43 h. /health/ready closes that gap: a dropped schema immediately surfaces as non-200 and removes the pod from Service endpoints once wired as readinessProbe (Deliverable 2 — infra PR).

Files changed

  • apps/api/src/index.ts — new route registered at line 64 (immediately after /api/health, before auth middleware)
  • apps/api/src/__tests__/health-ready.test.ts — 3 tests: 200 on success, 503 on 42P01, 503 on ECONNREFUSED; all assert no SQL leakage in response

UAT Playbook

No new user-facing behaviour — probe is infrastructure-only. No UAT_PLAYBOOK.md update required.

Related

cc @cpfarhood

## Summary Adds `GET /health/ready` — a public, DB-touching readiness endpoint registered before the `/api/*` auth middleware so it is reachable by K8s `readinessProbe` on pod port 3000 without auth. ### Behaviour - **200 `{"status":"ready"}`** — DB query succeeds, schema is present - **503 `{"status":"degraded"}`** — DB query throws for any reason (schema dropped `42P01`, connection refused, etc.) - Logs the pg error code to stdout on failure; **never leaks SQL or connection strings in the response body** ### Why this matters `/health` returns `{"status":"ok"}` with no DB check. This mask allowed the GRO-2678 PROD schema drop to go undetected for ~43 h. `/health/ready` closes that gap: a dropped schema immediately surfaces as non-200 and removes the pod from Service endpoints once wired as `readinessProbe` (Deliverable 2 — infra PR). ### Files changed - `apps/api/src/index.ts` — new route registered at line 64 (immediately after `/api/health`, before auth middleware) - `apps/api/src/__tests__/health-ready.test.ts` — 3 tests: 200 on success, 503 on `42P01`, 503 on ECONNREFUSED; all assert no SQL leakage in response ### UAT Playbook No new user-facing behaviour — probe is infrastructure-only. No UAT_PLAYBOOK.md update required. ### Related - Closes [GRO-2689](/GRO/issues/GRO-2689) (this feature) - Part of [GRO-2678](/GRO/issues/GRO-2678) PROD schema drop remediation (item #5) cc @cpfarhood
Flea Flicker added 1 commit 2026-08-09 09:22:14 +00:00
feat(api): add DB-touching /health/ready readiness probe (GRO-2678)
CI / Lint & Typecheck (pull_request) Successful in 19s
CI / Test (pull_request) Successful in 21s
CI / Build & Push Docker Images (pull_request) Successful in 3m25s
7679fada0a
Register GET /health/ready before the /api/* auth middleware so it is
public and reachable by K8s readinessProbe on port 3000 without auth.
On success → 200 {"status":"ready"}; on any DB/schema failure → 503
{"status":"degraded"}. Logs the pg error code; never leaks SQL in body.
A dropped schema (42P01) surfaces as non-200, closing the /health mask
that allowed the GRO-2678 incident to go undetected for ~43h.

Add health-ready.test.ts covering the 200 success path, 503 on schema
drop (42P01), and 503 on connection error; all assert no SQL leakage.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Flea Flicker merged commit d7bb314087 into dev 2026-08-09 09:26:18 +00:00
Flea Flicker deleted branch feat/gro-2678-db-readiness-probe 2026-08-09 09:26:19 +00:00
Sign in to join this conversation.