Commit Graph

4 Commits

Author SHA1 Message Date
d4ebcfcfbe Add collaboration token issuance and connection authentication (#34)
All checks were successful
CD / Build and push images (push) Successful in 2m45s
CI / Lint, typecheck, test (push) Successful in 1m56s
CI / Auth e2e pack (push) Successful in 2m1s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m9s
CD / Promote to Int (push) Successful in 12s
The api mints a short-lived (60 s) HS256 JWT per page open after an interim
permission check; the collab server authenticates every connection with it
(ADR 0003/0007 — the only JWTs in the system).

- packages/shared: browser-safe token schema/types in `collab-token`, and the
  Node `crypto` sign/verify in `token-crypto` behind its own subpath export
  (`@dorfteich/shared/token-crypto`) so the web bundle never pulls in
  `node:crypto`. Only HS256 is produced/accepted; the signature is checked in
  constant time before any untrusted field is read.
- api: `GET /pages/:id/collab-token` (auth-required) returns
  {token, mode, expiresInSeconds}; `mode` is rw/ro via the interim access
  service; issuance is logged at debug level without the token value.
- collab: `onAuthenticate` verifies the token, checks the pageId matches the
  document name, stores {userId, mode} context, and enforces `ro` via
  Hocuspocus' read-only connection flag. Hocuspocus' own signal handling is
  disabled so index.ts remains the single shutdown owner.
- Shared COLLAB_TOKEN_SECRET env for api + collab (compose, dev overlay,
  .env.example, stage docs); a dev default keeps native dev/test/CI running.

Tests: shared token round-trip/rejection; api endpoint e2e (auth required,
claims, 404 for non-members/unknown ids); collab integration via
HocuspocusProvider (valid token connects; expired/tampered/mismatched-page/
wrong-secret rejected; read-only writes dropped, verified with two clients).

Closes #34

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 15:52:19 +02:00
8316c617d2 Add collaboration server skeleton (Hocuspocus) with health, container, and CI/CD (#33)
All checks were successful
CD / Build and push images (push) Successful in 2m36s
CI / Lint, typecheck, test (push) Successful in 1m50s
CI / Auth e2e pack (push) Successful in 1m58s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m13s
CD / Promote to Int (push) Successful in 11s
Bootstrap apps/collab as a Hocuspocus WebSocket server (ADR 0003):
- pino JSON logging (service=collab) and shared Zod env validation
  (collabEnvSchema); structured connection open/close logs.
- /healthz endpoint (process liveness + PostgreSQL ping) served via the
  onRequest hook, matching the container-internal path and the proxied
  /collab/healthz path; any WebSocket handshake is accepted for now
  (authentication arrives with #34, persistence with #35).
- Dockerfile (ESM workspace build) and a compose service on the frontend
  and internal networks with a healthcheck; dev overlay service and a new
  COLLAB_PORT variable.
- CD builds, pushes, and promotes the collab image; CI builds it on PRs;
  the smoke suite asserts /collab/healthz through the reverse proxy.
- deployment.md/stages.md: proxy routing, per-stage COLLAB_PORT, checklist.

Closes #33

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 14:53:44 +02:00
bef6d8e4dc Make stage mail + base URL configurable; seed password overrides
All checks were successful
CD / Build and push images (push) Successful in 1m49s
CI / Lint, typecheck, test (push) Successful in 1m15s
CI / Auth e2e pack (push) Successful in 1m41s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 7s
CD / Smoke tests against Test (push) Successful in 1m5s
CD / Promote to Int (push) Successful in 9s
- compose: pass APP_BASE_URL and SMTP_* through to the api container so
  stages can use a real relay (defaults still match the dev Mailpit
  overlay); document the new keys in .env.example and stages.md
- seed: FIXTURE_ADMIN_PASSWORD / FIXTURE_USER_PASSWORD env overrides so
  shared stages get non-public fixture passwords; credential is re-hashed
  on every run so re-seeding applies a changed password

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpQz6ypHJsLfMf4S6fyQEB
2026-07-05 10:42:32 +02:00
6e5a632c31 Add production Dockerfiles and the Compose stack with dev overlay
Multi-stage images: web (workspace build baked into unprivileged
nginx with SPA fallback, asset caching, /healthz) and api (pnpm deploy
bundle with the prisma CLI for migrate-on-start, non-root, node-based
healthcheck). deploy/compose/docker-compose.yml defines the stage
stack (web, api, db) with frontend/internal networks, localhost-only
published ports for the host reverse proxy, log rotation, and named
volumes; .env.example documents every variable. compose.dev.yml layers
hot-reloading dev containers (or database-only usage) over the same
definition. Verified locally: full stack healthy, SPA fallback, readyz
green after automatic migration, db not reachable from outside.

Closes #6

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:30:21 +02:00