Skip to content

docs(planning): design for Locked App Mode (white-label own-domain web + per-product native app) - #252

Merged
izzywdev merged 4 commits into
masterfrom
claude/laughing-hypatia-w1fobr
Jul 14, 2026
Merged

docs(planning): design for Locked App Mode (white-label own-domain web + per-product native app)#252
izzywdev merged 4 commits into
masterfrom
claude/laughing-hypatia-w1fobr

Conversation

@izzywdev

Copy link
Copy Markdown
Owner

📋 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

  • 📝 Documentation update

🧪 Testing

  • Manual testing (doc renders; every referenced file / agent / contract field verified to exist in the repo)

Test Instructions

Review docs/planning/locked-app-mode.md. It mirrors the section order of the existing exemplar docs/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

  • New doc: docs/planning/locked-app-mode.md.

Key design content:

  • Extends the frozen app-registry contract, does not reinvent. The AppManifest already has mode: portal|standalone, routing.host (own-domain hook), chrome, and infra opt-in; the doc adds a third mode: locked plus branding and native manifest blocks.
  • Reuses what exists: the chrome-less StandaloneAppSurface render path, appManifest.ts host routing, and the shopify-nav/ precedent — already a complete, independently-signed second TWA in the repo — which proves per-product APKs are a CI matrix, not a rebuild.
  • Phase 0 (contract-freeze gate)Phase 1 (web white-label domain)Phase 2 (per-product native app), each phase a single-responsibility-agent fan-out gated on the frozen contract; wrapped in the fuzefront.platform.locked-app-mode release flag (default OFF).
  • Per-domain TLS/ingress/Cloudflare-tunnel work is flagged as a FuzeInfra @claude delegation, 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):

  1. Model locked mode as a new mode: locked (vs overloading standalone, which must keep a return-to-portal anti-trap control).
  2. Runtime Host-header lookup (single shared build, registry-driven) vs per-domain builds.
  3. First deliverable = this design doc only.

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

  • Documentation added (docs/planning/locked-app-mode.md)

📋 Checklist

  • I have performed a self-review
  • My changes generate no new warnings or errors (docs-only)
  • Only real, verified files/agents/contract fields are referenced

📝 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

…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
@github-actions
github-actions Bot enabled auto-merge (squash) July 14, 2026 18:12
@github-actions

Copy link
Copy Markdown
Contributor

CI Fix: package-lock.json updated with backend/security ajv@8.20.0

Branch: claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29356910849

Root Cause

backend/security/package.json had ajv@^8.17.1, ajv-formats@^3.0.1, js-yaml@^4.1.0, and @types/js-yaml@^4.0.9 as devDependencies, but package-lock.json was never regenerated to include them. npm ci failed with:

Missing: ajv@8.20.0 from lock file

The lock file's backend/security packages entry still tracked only the old dep set.

Fix

Ran npm install --package-lock-only at the root to sync the lock file. This added backend/security/node_modules/ajv@8.20.0 (isolated from the root's ajv@6.x) plus the other missing deps.

The fix is committed to claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29356910849 — please merge or cherry-pick it into this PR.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix: package-lock.json out of sync

Root cause: The backend/security workspace recently added three devDependencies (@types/js-yaml@^4.0.9, ajv@^8.17.1, ajv-formats@^3.0.1) but the root package-lock.json was never regenerated. The Playwright sign-in flow CI job runs npm ci which requires the lock file to be in sync, so it failed with:

npm error Missing: @types/js-yaml@4.0.9 from lock file
npm error Missing: ajv@8.20.0 from lock file
npm error Missing: ajv-formats@3.0.1 from lock file

Fix: Ran npm install at the workspace root to add the missing entries to package-lock.json. The fix is committed to branch claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29356926489 (commit 8e8e046).

A PR could not be opened automatically (Actions lacks pull_requests: write permission). To apply the fix, merge or cherry-pick the commit from that branch into claude/laughing-hypatia-w1fobr.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix Applied

Branch: claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29356968345
Commit: 15863e6

Root cause

gate-frontend-build failed because the backend/security workspace added ajv@^8.17.1, ajv-formats@^3.0.1, and @types/js-yaml@^4.0.9 to its package.json, but the root package-lock.json was never regenerated to include those resolved package versions. npm ci enforces that the lock file must be complete, so it fails with:

Missing: @types/js-yaml@4.0.9 from lock file
Missing: ajv@8.20.0 from lock file
Missing: ajv-formats@3.0.1 from lock file

Fix

Ran npm install --package-lock-only from the repo root to sync package-lock.json with all workspace package.json files. Verified npm ci passes after the update.

The fix is on branch claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29356968345 — please merge it into this PR's branch (claude/laughing-hypatia-w1fobr) to unblock CI.

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
@github-actions

Copy link
Copy Markdown
Contributor

CI Fix: Lock file out of sync

Root cause: backend/security/package.json added four dev dependencies (ajv@^8.17.1, ajv-formats@^3.0.1, @types/js-yaml@^4.0.9, js-yaml@^4.1.0) but the root package-lock.json was never regenerated. Every CI job failed at npm ci with:

npm error Missing: @types/js-yaml@4.0.9 from lock file
npm error Missing: ajv@8.20.0 from lock file
npm error Missing: ajv-formats@3.0.1 from lock file

This caused all subsequent steps (jest, coverage, Permit integration) to fail with jest: not found since npm ci aborted before installing anything.

Fix: Regenerated the lock file with npm install --package-lock-only from the workspace root. The fix is on branch claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29356921974 (commit fd21446).

The missing entries now added to package-lock.json:

  • node_modules/@types/js-yaml@4.0.9
  • backend/security/node_modules/ajv@8.20.0 (nested due to conflict with hoisted ajv@6)
  • backend/node_modules/ajv-formats@3.0.1

To apply this fix, merge or cherry-pick from claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29356921974 into this branch. A PR could not be opened automatically (Actions lacks pull_requests:write).

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix for Backend tests (Node 24.x) — root cause + fix

Root cause: npm ci fails on Node 24 (npm v11) because two optionalDependencies declared in packages/feature-flags/package.json cannot be resolved from npm, and are therefore absent from package-lock.json:

  • unleash-openfeature-provider-server@^1.4.0does not exist on npm (HTTP 404)
  • @openfeature/unleash-web-provider@^0.3.4 — only v0.1.1 is published

npm v11 (Node 24) enforces that all declared optional deps have a resolved lock entry; npm v10 (Node 22) silently skipped them. Since npm ci aborted before installing anything, every subsequent step failed with sh: 1: jest: not found.

Fix applied in branch claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29357489593:

  1. Removed unleash-openfeature-provider-server (non-existent package; server.ts uses dynamic import() with full try-catch graceful degradation so this is safe)
  2. Fixed @openfeature/unleash-web-provider range ^0.3.4^0.1.1 (published version)
  3. Regenerated package-lock.json with the resolved entry for @openfeature/unleash-web-provider@0.1.1

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: claude-auto-fix-ci-claude/laughing-hypatia-w1fobr-29357489593claude/laughing-hypatia-w1fobr.

claude added 2 commits July 14, 2026 18:34
…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
@github-actions

Copy link
Copy Markdown
Contributor

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:

```
npm error Missing: @openfeature/unleash-web-provider@ from lock file
npm error Missing: unleash-openfeature-provider-server@ from lock file
```

`packages/feature-flags/package.json` declares two `optionalDependencies` that don't exist on npm:

  • `unleash-openfeature-provider-server@^1.4.0` — does not exist on npm (HTTP 404)
  • `@openfeature/unleash-web-provider@^0.3.4` — only v0.1.1 is published

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):

  • Remove `unleash-openfeature-provider-server` from `optionalDependencies` (source uses dynamic import with graceful degradation — no runtime effect)
  • Downgrade `@openfeature/unleash-web-provider` range `^0.3.4` → `^0.1.1`
  • Regenerate `package-lock.json` with the resolved 0.1.1 entry

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.

@izzywdev
izzywdev merged commit 1723cba into master Jul 14, 2026
50 checks passed
@izzywdev
izzywdev deleted the claude/laughing-hypatia-w1fobr branch July 14, 2026 20:57
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.

2 participants