[E00-S02-T03] App health endpoint succeeds #384
No Reviewers
Labels
Clear labels
agent/analyst-drafted
agent/analyst-drafted
needs/human-decision
needs/human-decision
needs/security-review
needs/security-review
tier/t0
tier/t1
tier/t2
tier/t3
kind
bug
kind
bug
kind
epic
kind
epic
kind
initiative
EPPP programme initiative
kind
story
kind
story
kind
task
EPPP engineering card/task decomposed from a story
kind
toil
kind
toil
loop
1
loop
1
loop
2
loop
2
loop
3
loop
3
risk
agent-full
risk
agent-full
risk
human-gated
risk
human-gated
risk
human-only
risk
human-only
size
l
size
l
size
m
size
m
size
s
size
s
status
blocked
status
blocked
status
done
Workflow: Done
status
in-progress
status
in-progress
status
proposed
status
proposed
status
ready
status
ready
status
review
status
review
stream
checkout
stream
checkout
stream
onboarding
stream
onboarding
stream
platform
stream
platform
trivial — implementer only, auto-merge
standard — implementer + reviewer + tester
complex — security if triggered, human merge
critical — full chain + security, human merge
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Fabrika/PersonalBlog#384
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What changed
Implements the [E00-S02-T03] app health endpoint (#170) on top of the [E00-S02-T01/T02] Compose baseline (#59): the application now serves
GET /healthand stays up.apps/server/src/index.ts— replaces the bootstrap placeholder (export {};) with a minimal serving process built on Node's built-innode:http(no runtime dependencies, lockfile untouched except the type-definitions devDependency below): an HTTP server that answersGET /healthwith HTTP 200 and{"status":"ok"}(reports a healthy application), 404 for anything else, listens on port 3000 (default,PORT-overridable — matching DockerfileEXPOSE 3000/ compose:3000), and closes cleanly on SIGTERM/SIGINT sodocker compose down/docker stopare graceful. The Fastify 5 application shell (and the real HTTP API) remains a later story (ADR E01-S01-T03).apps/server/package.json+pnpm-lock.yaml— adds the exact devDependency@types/node@24.13.3(newest 24.x type-definition line, matchingengines.node: 24.x) so the server type-checks; the lockfile is regenerated with the pinned pnpm 11.23.0. This is the lockfile's first scoped package ('@types/node@24.13.3':).apps/server/tsconfig.json— adds"types": ["node"]: TypeScript 6.0.3 no longer auto-includes@typespackages, so the server package must declare its type roots explicitly (scoped to the server package only — core/extension placeholders use no Node APIs).apps/server/Dockerfile+compose.yaml— header comments updated: T03 health endpoint no longer out of scope; the app container now stays up serving the health endpoint.docs/development/non-container.md— the Run/Troubleshooting text that described the server as an exiting placeholder now documents the health endpoint (doc-accuracy follow-up to the behavior change).tests/health-endpoint.test.mjs(new) — locks in both acceptance criteria: static assertions on the committed entrypoint, non-vacuous mutation probes, and a real HTTP smoke test that boots the committed server source (Node type stripping, no build step) and assertsGET /health→ 200 +{"status":"ok"}.tests/compose-config.test.mjs— the Docker-gated real-stack probe now asserts theappcontainer stays running (instead of tolerating an exit-0 placeholder) and probesGET /healthinside the container (200 + healthy body).tests/frozen-install.test.mjs— helper fix:lockedPackageKeysnow strips pnpm's YAML quoting on scoped package keys (e.g.'@types/node@24.13.3':) so the lockfile↔virtual-store exact-match probe works with the lockfile's first scoped dependency. Probe semantics unchanged (still fails on any drift) plus a new non-vacuous case for quoted-key extraction.Explicitly out of scope per the brief, not touched: PostgreSQL health gate (E00-S02-T02 — unchanged behavior), DB volume persistence (E00-S02-T04), non-root execution (E00-S02-T05), Fastify 5 application shell.
Criterion → test table
tests/health-endpoint.test.mjs— "the app health endpoint succeeds (committed entrypoint answers GET /health with HTTP 200)": the committedapps/server/src/index.tscreates an HTTP server (createServer), routesGET /health, answers with HTTP 200, and listens on the application port (3000 default). Non-vacuous: mutation probes removing the/healthroute / changing the 200 to 500 / a placeholder entrypoint all fail the assertion. "an HTTP smoke test against the booted server succeeds for GET /health (200 + healthy body)" boots the committed server source on an ephemeral port and asserts a real 2xx response (issue test plan "HTTP smoke test passes against the health endpoint"). Docker-gated:tests/compose-config.test.mjs"docker compose up -d starts the database and application containers" asserts theappcontainer stays running andGET /healthanswers 2xx inside the containertests/health-endpoint.test.mjs— "the endpoint reports a healthy application (committed health payload is {"status":"ok"})": the committed health payload reportsstatus: 'ok'. The HTTP smoke test asserts the booted endpoint's body is exactly{"status":"ok"}. Non-vacuous: mutation probe changing the payload to'nope'fails. Docker-gated compose-config probe additionally asserts"status":"ok"in the container responseTest plan executed
pnpm run typecheck→ 3/3 packagesDoneon Node 24.20.0 ✓ (includestsc --noEmitfor the server with the newtypes: ["node"]config)pnpm run build→ 3/3 packages emitdist/✓; the compiledapps/server/dist/index.jswas booted and answeredGET /health→ 200{"status":"ok"}(manual probe) ✓pnpm test(full suite, Node 24.20.0) → 71/71 pass, 0 fail, 2 skipped (the two Docker-gated probes skip where no daemon exists) ✓ — the one intermediate failure (frozen-install virtual-store probe) was the quoted-scoped-key helper limitation, fixed in the third commit and re-verified greennode --test tests/health-endpoint.test.mjs→ 7/7 pass including the real HTTP smoke test (server booted on an ephemeral port,GET /health→ 200{"status":"ok"}) ✓node --test tests/compose-config.test.mjs→ 13 pass / 2 skip (Docker probes skip cleanly — no daemon in this sandbox) ✓@types/node@24.13.3+undici-types@7.18.2additions; the frozen-install path (clean clone →pnpm install --frozen-lockfile→ exact virtual-store match) passes locally ✓Risks / notes
"types"entry for@typespackages; the fix is scoped toapps/server/tsconfig.jsononly.@types/node@24.13.3is exact-pinned per workspace convention (same style astypescript@6.0.3); it is the newest 24.x line available in the registry.{"status":"ok"}); richer health reporting (DB connectivity, uptime) belongs to later stories — the container-level PostgreSQL health gate is already T02's.skipwithout a daemon, so the suite stays green everywhere while giving real container-level validation where Docker exists.Refs #170