Skip to content

feat: BFF topology, @craftainer/bff 0.2.0 and crud-sdk 0.8.0 (BF2-BF5c) - #27

Merged
crazyracer98 merged 21 commits into
mainfrom
wip/bff
Nov 4, 2026
Merged

crazyracer98 merged 21 commits into
mainfrom
wip/bff

Conversation

@crazyracer98

@crazyracer98 crazyracer98 commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Moves the template to a backend-for-frontend (BFF) topology (plan items BF2 to BF5c).

  • Topology: the SPA no longer talks OIDC itself (oidc-client-ts / react-oidc-context removed). A thin Node bff/ workspace member built on @craftainer/bff runs the confidential OIDC client, keeps sessions in Valkey, serves the built SPA with a per-request CSP nonce, and proxies /api and /.well-known. The runner image is Node (no nginx, no config.js); the dev stack gains Valkey and a dev BFF on 8787 that Vite proxies to.
  • Libraries: @craftainer/bff 0.2.0 and @craftainer/crud-sdk 0.8.0.
  • Analytics: page views from the URL adapter, a consent hook, and the admin's default resource published once (BF5a, BF5b).
  • CSP: Vite html.cspNonce and an Emotion cache using the BFF nonce. index.html is served Cache-Control: no-store on purpose, since each response carries its own nonce.
  • E2E (BF5/BF5c): the suite drives the BFF through a real Keycloak login, Valkey and the API. Local full lane: 36/36 passed, plus 5/5 on a repeat of the gone-session logout test.
  • Docs: BFF docs (bff/README.md, root README sections) and ADRs, with ADR 0007 superseding the browser-side OIDC and nginx ADRs (0001, 0002).

Notes for merge

  • Devcontainer rebuild required after merge (.devcontainer/ gained the Valkey service and dev BFF settings); only the user can trigger it.
  • main merged in at 53e0be8; the lockfile was regenerated from main's (d5cf353), so source-map-js 1.2.2 and undici 8.12.3 clear the osv-scanner advisories.
  • A final e2e verification on d5cf353 is pending.
  • Review (/code-review high) fix: safeReturnTo rejects paths that normalise to protocol-relative (/a/..//evil.com).

… (BF1)

- src/auth/: GET /bff/user, login by navigation to /bff/login?returnTo=<same-origin path>, POST /bff/logout with X-CSRF then navigate to logoutUrl, /bff/config runtime config

- SDK 0.7.0 on /api/crud: credentials include, X-CSRF middleware, cacheScope from sub, onUnauthorized navigates to login; roles from /bff/user for UI only

- drop oidc-client-ts and react-oidc-context; Vite dev proxy for /bff, /api and /.well-known to the dev BFF on :8787; stories, stubs and tests follow
- @craftainer/bff ^0.1.0 dependency, lockfile updated

- dev:bff, start:bff, typecheck:bff scripts (paths created by BF3)
- bff/ is a private pnpm workspace member; root deps no longer carry the library
… (BF4)

- Dockerfile: builder + bff-deploy (pnpm deploy --prod) + runner on digest-pinned node:24.22.1-trixie-slim, USER node, 8080
- delete nginx config and envsubst entrypoint
- image.mk smoke on /health/live with dummy required env
- .devcontainer/stack/valkey fragment, include and depends_on, plaintext dev opt-out
- forward 8081 and 8787; sync manifest: bff/ and stack/ ignore; typecheck:bff hook
…k (AN5)

- track() posts to /bff/analytics with X-CSRF, fire-and-forget, cool-down on failure
- page views derived from the crud-views UrlAdapter state (no ids or filters)
- useConsent over /bff/consent; unknown or failed state is treated as not granted
- Trivy HIGH findings were in npm's vendored brace-expansion and undici; the BFF only needs the node binary
…te a choice (AN5)

- usePageViews keeps one default adapter so re-renders do not resend the view
- useConsent ignores a slow mount GET after choose() and guards unmounted setState
- tests for both
…ite the BFF docs (BF5a)

- App calls usePageViews() once; no consent UI
- Remove /config.js script and template; .env.example documents the dev BFF vars
- Runner FROM derives from NODE_VERSION/DEBIAN_VERSION (digest kept); bff tests out of the image
- compose.instance.yml: dev BFF env (PUBLIC_ORIGIN, OIDC_*, BFF_UPSTREAMS); 8081 port label
- ADR 0007 (supersedes 0001, 0002), ADR 0008, FR-0001, docs/architecture.md; README, scripts docs, 0003/0006 notes
…I (BF5)

Session cookie, CSRF/Origin, logout, back-channel logout, refresh CAS, idle/absolute expiry, well-known, analytics, admin journey; lane.sh/run.sh/lane.compose.yml; docs
…I (BF5)

Mark the two known failures with test.fail; wider expect timeout
…s none (BF5b)

- viewPath takes a default resource; the admin publishes resources[0] via src/analytics/defaultResource.ts
- usePageViews keeps the last path in a ref so the late default does not duplicate a view
- remove the trash test.fail marker and its Known-failures entry; README e2e line points at lane.sh
…-request nonce (BF5c phase A)

- vite.config.ts: html.cspNonce __CSP_NONCE__
- src/theme/emotionCache.ts: nonce from meta[property=csp-nonce].nonce, cache key mui, prepend; ThemeProvider wraps in CacheProvider
- @emotion/cache 11.14.0 as a direct dependency (lockfile version)
- ADR 0007 amendment; e2e Known failures note
… and undici 8.12.3 replace the osv-flagged versions
@crazyracer98 crazyracer98 self-assigned this Nov 4, 2026
@crazyracer98
crazyracer98 merged commit 3c33f5d into main Nov 4, 2026
6 checks passed
@crazyracer98
crazyracer98 deleted the wip/bff branch November 4, 2026 11:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant