Skip to content

app-registry read/write store split: self-registered MFEs (picker) never appear in the shell #533

Description

@izzywdev

@claude — cross-repo delegation from FuzePicker (tracking: FuzePicker Jira FPK-7, epic FPK-6). Please fix the host-backend app-registry split-brain described below and open a PR.

Why

FuzePicker's module-federation remote (picker-app, https://picker.prod.fuzefront.com/remoteEntry.js) is healthy but never renders in the FuzeFront portal — because the shell's app list doesn't contain picker. This is a host-backend registry bug and affects every self-registering MFE, not just picker.

Root cause (in this repo)

Two routers are mounted at /api/v1/app-registry (backend/src/index.ts:287-293): a local-DB adapter (backend/src/routes/appRegistry.ts) first, then a proxy to the applications-service (backend/src/routes/app-registry.ts). The mount comment says the adapter should pass unmatched requests through to the proxy via next() — but the adapter's GET /apps (backend/src/routes/appRegistry.ts:53-73) answers unconditionally from the local apps table and never calls next(). So in prod it shadows the proxy for the one read the shell uses.

Meanwhile MFE self-registration (e.g. FuzePicker's init container: POST /apps, PUT /apps/<slug>, POST /apps/<slug>/activate) only defines GET /apps on the adapter, so those verbs fall through to the proxy → the applications-service registry.

Net: writes land in the applications-service store; the read (frontend/src/platform/appRegistry.tsx:86client.listApps({status:'activated'})GET /api/v1/app-registry/apps) is served from the host backend's local apps table. Two different stores → self-registered apps are active in the applications-service but absent from what the shell reads → getBySlug('picker') undefined → FederatedAppLoader (frontend/src/components/FederatedAppLoader.tsx:98) errors "App 'picker' not found or not activated" → no UI.

Proposed fix

In backend/src/routes/appRegistry.ts, make GET /apps (and any other reads the shell uses) return next() when the applications-service is configured (e.g. process.env.APPLICATIONS_SERVICE_URL present), so the read path proxies to the same store the write path targets. Keep the local adapter as the CI / no-applications-service fallback only (an explicit flag like APP_REGISTRY_LOCAL_ADAPTER is also fine). This realizes the pass-through the mount comment already promises.

Acceptance criteria

  1. With the applications-service configured, GET /api/v1/app-registry/apps returns the applications-service registry contents, not the host backend's local apps table.
  2. A self-registered MFE (registered via an init-container to the applications-service, not seeded into the local table) appears in the shell's activated-apps list and mounts at /app/<slug>.
  3. Picker renders in the portal at /app/picker.
  4. Regression coverage: a unit test asserting the adapter delegates to the proxy when APPLICATIONS_SERVICE_URL is set; an e2e asserting a self-registered remote mounts in the shell.
  5. The CI path (no applications-service) still works via the local adapter.

STATE

  • Originator: FuzePicker, Jira FPK-7 (epic FPK-6). FuzePicker's half (removing a non-contract nav field from its registration manifest) is already merged: izzywdev/FuzePicker#46.
  • Done when: the 5 acceptance criteria pass and a PR is merged here; then picker (and other self-registered MFEs) render in the portal.
  • Verify note: live store contents couldn't be inspected externally (registry list is auth-gated 401) — the split is proven from code paths above.
  • If blocked, reply here with BLOCKED: <question> + an updated STATE block.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions