Commit Graph

5 Commits

Author SHA1 Message Date
saravanakumardb1
5687e5ace1 fix(docker): clean up compose advisory warnings (Phase D follow-up)
Mechanical fixes to address remaining docker-doctor advisory warnings:
  - Add GITEA_NPM_OWNER to existing build.args block (or full args block
    if missing) so Dockerfile receives the build arg explicitly
  - Add start_period: 30s to healthcheck blocks where missing
    (prevents false cold-start failures)

Both are advisory checks — neither blocks builds — but cleaning them up
eliminates noise from CI logs.

Refs: docker-build-optimization-roadmap.md \xc2\xa7Phase D follow-ups
2026-05-27 04:25:19 -07:00
saravanakumardb1
b23a601431 fix(docker): apply Phase D.2 Dockerfile/compose fixes
Mechanical fixes per docker-build-optimization-roadmap.md §6.D.2:

- Dockerfile: add # syntax=docker/dockerfile:1.7 directive (A2)
- Dockerfile: declare ARG GITEA_NPM_OWNER alongside GITEA_NPM_HOST (F14)
- Dockerfile: wildcard COPY .docker-deps* (A5-2, B3)
- Dockerfile (web): glob enumerated config COPYs (F11/F13) where applicable
- docker-compose.yml: healthcheck localhost → 127.0.0.1 (F12) where applicable
- docker-compose.yml: pass GITEA_NPM_OWNER build arg (F14) where applicable
- .npmrc.docker: rewrite with canonical ${GITEA_NPM_HOST}/${GITEA_NPM_OWNER}
  template (F4/F14) if hardcoded
- .gitignore: ensure *.bak rule (B3)
- .docker-deps/.gitkeep: ensure exists for wildcard COPY

Verified: docker-doctor exits PASS (warnings only, ADR-0001 expected).

Refs: docker-build-optimization-roadmap.md §Phase D.2
2026-05-27 04:12:19 -07:00
saravanakumardb1
91b859746b fix(docker): bake NEXT_PUBLIC_* values at build time, drop hardcoded api.bytelyst.com
Root cause: docker-compose.yml hardcoded NEXT_PUBLIC_NOTES_API_URL to
https://api.bytelyst.com/notelett — a production URL that doesn't
exist on this network — as the *build arg* for the web image. The
docker-compose.override.yml correctly set localhost:4016/api but only
on the runtime environment, which has no effect because NEXT_PUBLIC_*
values are baked into the Next.js bundle at build time (pnpm run build
inside the Dockerfile), not read at runtime.

Symptom: every authenticated client-side fetch from the deployed web
container went to https://api.bytelyst.com/notelett/... which the
corporate proxy intercepted with a blockpage. The saved-views client
in particular fired on every (app)/ layout mount, surfacing a
'Failed to fetch' toast on dashboard load. 4 release-flows.spec
tests failed because page.route('**/api/**') couldn't match the
api.bytelyst.com URLs at all.

Discovery: inspected the deployed bundle inside the running container.
'grep -oE "api.bytelyst.com" /app/web/web/.next/static/chunks/*.js'
returned multiple hits across the (app)/ layout, (auth)/ pages, and
share page. The string was absent from the source tree, which proved
it had been injected at build time via the broken arg default.

Discovery debug pattern (kept for future use):
  page.on('requestfailed', r => console.log(r.method(), r.url()));
  page.route('**/api/**', route => route.fulfill({status:200,body:'{}'}));
  await page.goto('/dashboard');
  // FAILED REQUESTS will list any URL not under /api/** that the SPA
  // attempted, exposing baked-in production URLs immediately.

Fix (three layers, defense in depth):

1. docker-compose.yml — replace hardcoded
   'NEXT_PUBLIC_NOTES_API_URL: https://api.bytelyst.com/notelett'
   in the build.args block with
   '${NEXT_PUBLIC_NOTES_API_URL:-http://localhost:4016/api}'.
   Same treatment for the runtime environment block. Add build args
   for the four other NEXT_PUBLIC_* values (extraction, MCP,
   diagnostics, product name/id, telemetry transport) so a single env
   var on the host controls both build and runtime layers.

2. web/Dockerfile — declare ARG and ENV lines for all seven
   NEXT_PUBLIC_* values so the build args reach 'pnpm run build'.
   Previously only NOTES_API_URL and PLATFORM_SERVICE_URL were
   declared, which meant overriding extraction/MCP/diagnostics via
   docker compose silently had no effect on the bundle.

3. docker-compose.override.yml — add a build.args block mirroring the
   four URL overrides so the local-only override also reaches build
   time, not just runtime. Comment block explains the bake-time vs
   runtime distinction so future contributors don't repeat the bug.

Verified end-to-end after the fix:
  - docker compose build --no-cache web + up -d → grep of bundle now
    shows 'localhost:4016/api', api.bytelyst.com fully gone.
  - Debug interception test: zero requestfailed events on /dashboard.
  - Playwright release-flows.spec.ts: 4 failed → 4 passed (after URL
    fix; no test code changed for these four tests).
  - Full Playwright suite (--ignore-snapshots): 43 passed.
  - scripts/e2e-docker-test.sh: 9/9 backend API lifecycle steps pass.
  - pnpm run verify: backend 380/380, web 96/96, mobile 97/97.
2026-05-23 10:04:36 -07:00
saravanakumardb1
d5e857dbf7 test(e2e): docker compose E2E test + seed scripts + 9-step verification
Implements the full E2E flow against the deployed docker stack and
documents it as a repeatable test playbook.

Surfaced and fixed three real issues while building the E2E:

1. JWT secret mismatch — docker-compose.override.yml backend was using
   a NoteLett-only JWT_SECRET that platform-service did not share, so
   every Authorization: Bearer call returned 'Invalid or expired token'.
   Aligned the override to use platform-service's actual secret
   (dev-ecosystem-secret-do-not-use-in-production).

2. CORS preflight missing PATCH/DELETE — @bytelyst/fastify-core registers
   @fastify/cors with only { origin }, which leaves Access-Control-Allow-
   Methods at the @fastify/cors default of 'GET,HEAD,POST'. Real browser
   PATCH/DELETE preflights would fail. Added an onSend hook in
   backend/src/server.ts that rewrites the header to
   'GET,HEAD,POST,PATCH,PUT,DELETE,OPTIONS' on CORS preflight responses.

3. Product 'notelett' wasn't registered with platform-service — auth
   register/login both error with 'Unknown or disabled product: notelett'.
   The seed script now POSTs to /api/products idempotently.

Deliverables:

- scripts/e2e-docker-seed.sh — idempotent: registers the notelett product
  and creates two test users (admin@notelett.app with role=admin who can
  write, user@notelett.app with role=user who is read-only). Re-runs are
  no-ops once seeded.

- scripts/e2e-docker-test.sh — 9-step E2E that drives the deployed stack
  via HTTP only (no browser): login → CORS preflight for PATCH →
  workspace create → note create → note read → note PATCH (status:
  draft→active) → note list → note delete → workspace delete.

- docs/testing/E2E_DOCKER_TESTING.md — full playbook covering prereqs,
  seed, automated E2E, manual UI smoke, stack architecture diagram,
  troubleshooting (JWT mismatch, unknown product, role rejection,
  CORS, port conflict, data loss), tear-down, CI wiring guidance.

- package.json — pnpm e2e:docker:seed and pnpm e2e:docker:test
  shortcuts.

Verified live on this host's deployed stack:

  $ bash scripts/e2e-docker-seed.sh
  ↷ product 'notelett' already exists
  ↷ admin user already registered + login works
  ✓ user created
  🟢 Seed complete.

  $ bash scripts/e2e-docker-test.sh
  ✓ user=usr_e094e0c2-... role=admin
  ✓ CORS allows PATCH
  ✓ workspace created
  ✓ note created
  ✓ note read matches
  ✓ note patched (status: draft → active)
  ✓ note list returned (1 item)
  ✓ note deleted (HTTP 204)
  ✓ workspace deleted (HTTP 204)
  🟢 All 9 E2E steps passed.

Backend regression suite still green: 380/380.
2026-05-23 01:16:19 -07:00
saravanakumardb1
e5221afb87 feat(deploy): backend Docker corp-proxy support + local compose override
Two changes that make 'docker compose up' actually work on this host
(and on any corporate network with TLS interception of npmjs.org):

1. backend/Dockerfile gains the same NODE_TLS_REJECT_UNAUTHORIZED=0 +
   NPM_CONFIG_STRICT_SSL=false envs and 'npm config set strict-ssl false'
   step that web/Dockerfile already had. Without this, the 'npm install
   -g pnpm@10.6.5' step failed with UNABLE_TO_GET_ISSUER_CERT_LOCALLY
   on corp networks. Build-time-only; production runtime image is
   unaffected.

2. docker-compose.override.yml (new) is picked up automatically by
   'docker compose up' and:
   - remaps the web container's host port from 3000 to 3050 (port 3000
     on this host is held by Grafana). Uses 'ports: !override' so the
     base port mapping is replaced rather than appended.
   - points the backend at the sibling platform-service (4003),
     extraction-service (4005), and mcp-server (4007) running on the
     host network via host.docker.internal.
   - sets DB_PROVIDER=memory and a 32+ char JWT_SECRET so the backend
     starts in dev mode without Cosmos credentials.

Verified live on this host:
  docker compose up -d → both notelett-backend (healthy) and
  notelett-web running.
  curl http://localhost:4016/health → {status:ok,service:notelett-backend}
  curl http://localhost:3050/dashboard → HTTP 200, '<title>NoteLett</title>'
2026-05-23 01:04:18 -07:00