Live-stack debugging caught this: Auth.js v5 builds the OAuth
redirect_uri from AUTH_URL, NOT from the request Host header, even
with AUTH_TRUST_HOST=true. If you visit http://acme.localhost:3000
with AUTH_URL=http://localhost:3000, Keycloak rejects the token
exchange because the PKCE cookie was set on acme.localhost but the
callback URL Auth.js sent was localhost.
Fix in dev: pin AUTH_URL to the subdomain you're testing on. In prod,
orca-proxy passes the right host via X-Forwarded-Host and AUTH_URL
is set to the apex.
Updates .env.example with a long-form note + sets AUTH_URL to the
acme tenant so a copy/paste-and-go workflow Just Works. Adds a
'AUTH_URL gotcha' callout to the local-dev section in README.
Refs: M5.1
playwright.config.ts + tests/e2e/{apex,tenant,health}.spec.ts. make e2e for local. CI e2e job opt-in via RUN_E2E repo variable. OIDC click-through deferred to when stage is up.
Refs: M5.3
10 route shells under /[slug]/, role-filtered Nav, backstage stub at /__backstage__, dashboard reads session.products to render tiles. src/lib/session.ts is the canonical role × surface matrix; canSee() is the only RBAC primitive in the portal (real enforcement remains at the API layer). 24 vitest tests; 100% src/lib coverage.
Refs: M5.2
Next.js 16 + Auth.js v5 skeleton: host→slug middleware, tenant-context layout, OIDC sign-in flow against breakpilot-dev realm. 100% coverage on src/lib. Bumps next to 16.2.6 to clear trivy CVEs in 15.0.3.