fb0dd1753a
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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. |
||
|
|
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.
|
||
|
|
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>'
|