M5: Docker image, Railway deploy ADR and image smoke test (ENG-267) #22

Merged demi.dev
targeting main from stoopkidddd/eng-267-m5-docker-image-railwayjson-and-image-smoke-test
Merged opened by and assigned to demi.dev
targeting main from stoopkidddd/eng-267-m5-docker-image-railwayjson-and-image-smoke-test

Linear: https://linear.app/engineereddev/issue/ENG-267

What's in this PR:

  • Dockerfile: multi-stage; pnpm 11.28.10 with pnpm fetch layer caching; builds protocol, crypto, web and server; production deps via pnpm deploy; runtime node:26-slim as non-root pneumo (uid 10001), WEB_DIST_DIR set, EXPOSE 8080, CMD ["node","apps/server/dist/index.js"]. ARG VERSION sets the OCI version label and the version /api/health reports. .dockerignore keeps node_modules, Android, .git, test outputs and .env* (except .env.example) out.
  • docker-compose.yml: the server profile builds the image and runs it against minio/minio-init.
  • mise run e2e:docker (scripts/e2e/docker.ts): builds the image, starts a harness MinIO, runs the container on a private Docker network in direct then proxy mode, runs the dev-client smoke beside it, and asserts health version, web assets, non-root uid, SIGTERM shutdown and image size.
  • check:infra runs hadolint on the Dockerfile (scripts/ci/check.sh, pinned in mise.toml).
  • ADR 0001 (lead decision): no railway.json. Railway Config as Code is deprecated: new services can't opt in, and existing files stop being read on 2026-12-01. Deploy settings move to ENG-271 (Railway IaC) and ENG-273 (template). Recommended overlap 0 s, draining 15 s. SPEC §4, §16.3 and §18.2 updated.
  • ADR 0002 (lead commit): the image cap is raised from 250 MB to 300 MB uncompressed. The spec-mandated node:26-slim base alone is 272 MB; Pneumo adds about 19 MB. SPEC §16.1 updated.

Verify (lead, rebased on e5f90f2):

  • mise run check:infra → exit 0 (hadolint, shellcheck, biome, workflow validation)
  • mise run e2e:docker → exit 0. Image 290,785,357 bytes. Direct and proxy: health version, web assets, non-root uid 10001, smoke 7/7 PASS each (authentication, pair+claim, note, link, 2 MB file, push_deleted, revoke 4401), SIGTERM shutdown.
  • docker images: pneumo:eng-267 291MB; no containers left.
  • Implementer also checked the Compose server profile (MinIO init, /api/health, web dist).

Deviations:

  • No railway.json (ADR 0001); the image cap is 300 MB (ADR 0002).
  • pnpm deploy needs registry metadata access (offline deploy fails on optional fsevents metadata); the pnpm fetch cache and the frozen offline install remain.

🤖 Generated with Claude Code

Commits 0