docs(planning): design for Locked App Mode (white-label own-domain web + per-product native app) - #252
Conversation
…b + per-product native app) ADLC-structured architecture plan for serving a single product (e.g. FuzeSocial) white-label on its own domain with FuzeFront hidden, plus one signed native app per product. Extends the frozen app-registry contract (new mode: locked + branding/native manifest blocks) rather than reinventing; sequences a Phase-0 contract-freeze gate then a contract-first fan-out. Mirrors the provider-agnostic-security-layer planning doc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PmPk3wq4fDcQqxJkoye6Ek
CI Fix: package-lock.json updated with backend/security ajv@8.20.0Branch: Root Cause
The lock file's FixRan The fix is committed to |
CI Fix: package-lock.json out of syncRoot cause: The Fix: Ran A PR could not be opened automatically (Actions lacks |
CI Fix AppliedBranch: Root cause
FixRan The fix is on branch |
backend/security/package.json added ajv@^8.17.1, ajv-formats@^3.0.1,
@types/js-yaml@^4.0.9, and js-yaml@^4.1.0 but the root lock file was never
regenerated, so `npm ci` failed ("Missing: ajv@8.20.0 from lock file") across
every CI job. Regenerated the lock (package-lock only) to unblock CI. Applies
the CI-autofix bot's proposed lockfile fix (no PR could be auto-opened —
Actions lacks pull_requests:write).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PmPk3wq4fDcQqxJkoye6Ek
CI Fix: Lock file out of syncRoot cause: This caused all subsequent steps ( Fix: Regenerated the lock file with The missing entries now added to
To apply this fix, merge or cherry-pick from |
CI Fix for Backend tests (Node 24.x) — root cause + fixRoot cause:
npm v11 (Node 24) enforces that all declared optional deps have a resolved lock entry; npm v10 (Node 22) silently skipped them. Since Fix applied in branch
A PR from the fix branch could not be auto-created due to GitHub Actions permissions. Please merge the fix branch manually or create the PR: |
…s-gate Adds the design-review UX artifacts for Locked App Mode under design/frames/locked-app-mode/ (white-label login, locked product shell, 375px locked mobile, separate-native-apps home) with DESIGN.md + manifest.json, built in fuse-seam DS tokens. Adds frontend/tests/locked-app-mode-frames.spec.ts — a self-contained (file://, no stack) Playwright gate that validates the built UI against the committed frames. Asserts the white-label invariant (no "FuzeFront" string and no launcher / org-switcher / return-to-portal inside the product surface), the 375px mobile surface, and distinct per-product packageIds. Wired into the root playwright.config.ts alongside the federated-apps gate (testMatch: *-frames). All 5 tests pass locally against the frames. Links the frames + gate from the planning doc's verification section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PmPk3wq4fDcQqxJkoye6Ek
… on Node 24 packages/feature-flags declared two optionalDependencies that cannot resolve: unleash-openfeature-provider-server@^1.4.0 (404 — not published to npm) and @openfeature/unleash-web-provider@^0.3.4 (only 0.1.1 is published). npm 11 (Node 24) enforces a resolved lock entry for every declared optional dep and aborts `npm ci`, failing every Node-24 job before install; npm 10 silently skipped them. Removed the phantom package and pinned the web provider to its published ^0.1.1; both are loaded via guarded `await import()` in server.ts (graceful degradation), so runtime behavior is unchanged. Regenerated the lock. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PmPk3wq4fDcQqxJkoye6Ek
CI fix pushed — branch `claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29358554341`Root cause: The Backend tests (Node 24.x) job fails at the `npm ci` step (before jest is even installed) with: ``` `packages/feature-flags/package.json` declares two `optionalDependencies` that don't exist on npm:
npm v10 (Node 22) silently skips unresolvable optional deps; npm v11 (Node 24) enforces they must be in the lock file. Since `npm ci` fails before installing anything, `jest` is never available → all test steps exit with `jest: not found` (exit code 127). Fix (commit a2ccf95):
Note: a previous fix attempt made the same change (commit `1385cd2`) but it was on a separate branch and the subsequent `test(locked-app-mode)` commit regenerated the lock file from the unfixed `package.json`, reverting it. |
📋 Description
Adds an ADLC-structured design/architecture plan —
docs/planning/locked-app-mode.md— for Locked App Mode: serving a single product (worked example: FuzeSocial) white-label on its own domain (www.fuzesocial.com) with no indication FuzeFront is underneath, while the product transparently keeps consuming FuzeFront's authN, authZ, billing, payments, notifications, sockets, and app registry. The mobile arm publishes one signed native app per product (the Google/Zoho/Atlassian pattern) since app stores forbid dynamic app loading.Docs-only. No contract or code changes here — the doc sequences those as the follow-up ADLC steps.
🔄 Type of Change
🧪 Testing
Test Instructions
Review
docs/planning/locked-app-mode.md. It mirrors the section order of the existing exemplardocs/planning/provider-agnostic-security-layer.md(Context → Target architecture → Phase 0 contract-freeze gate → fan-out phases → Feature flag → Migration & risk → Critical files → Verification).🔧 Implementation Details
Changes Made
docs/planning/locked-app-mode.md.Key design content:
AppManifestalready hasmode: portal|standalone,routing.host(own-domain hook),chrome, andinfraopt-in; the doc adds a thirdmode: lockedplusbrandingandnativemanifest blocks.StandaloneAppSurfacerender path,appManifest.tshost routing, and theshopify-nav/precedent — already a complete, independently-signed second TWA in the repo — which proves per-product APKs are a CI matrix, not a rebuild.fuzefront.platform.locked-app-moderelease flag (default OFF).@claudedelegation, not edited here.Decisions flagged for owner review
The doc adopts three defaults and calls them out as revisitable in the eventual contract-freeze PR (an interactive confirmation could not be delivered while authoring):
mode: locked(vs overloadingstandalone, which must keep a return-to-portal anti-trap control).One genuinely open product question is raised in the doc for the owner +
billing-payments-engineer: white-label billing depth — whose brand appears on Stripe checkout/invoices (Stripe Connect / custom domain vs neutral pages). Default assumption: neutral, non-FuzeFront surfaces.Documentation
docs/planning/locked-app-mode.md)📋 Checklist
📝 Additional Notes
Follows the ADLC contract-first governance: this doc is the design artifact; the contract change, the code fan-out, and the
design-review-labeled gate issue are the sequenced follow-ups it lays out.Generated by Claude Code