You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@claude — The built-in Clock federated app does NOT mount in prod (infinite "Loading application…" spinner). #129 shipped the platform but it has integration bugs that passed the gates yet break at runtime. Fix end-to-end and VERIFY with Playwright that Clock actually mounts. Land via PR (master is deploy-on-push).
Verified diagnostics (already done on prod — build on these, don't re-investigate)
Clock MF remote BUILDS (now in release.yml matrix) + is DEPLOYED + SERVES: https://app.fuzefront.com/apps/clock/assets/remoteEntry.js returns 200 application/javascript. (Note the real path is under /assets/.)
Clock is REGISTERED (applications-service ensureBuiltins): DB row is correct — remote_url/url = …/apps/clock/assets/remoteEntry.js, integration_type = module-federation, scope = clockApp, module = ./ClockApp, is_active true, visibility public, status activated.
ROOT CAUSE of the spinner: the frontend FederatedAppLoader (frontend/src/components/FederatedAppLoader.tsx) reads app.manifest.integration.{type,remoteEntry,scope,module}, but the apps the shell receives come from the host legacy /api/apps, whose objects have NO manifest field (keys: integrationType, remoteUrl, scope, module, url, …). So app.manifest is undefined → the loader can't resolve the remote → infinite spinner. Clock shows in the menu (from /api/apps) but never mounts.
Consistent data source + shape: Either (preferred) add a host-backend proxy mounting /api/v1/app-registry/* → applications-service (same pattern as the billing proxy / apps.ts), and make the shell's app menu + FederatedAppLoader use the manifest-shaped@fuzefront/app-registry-client consistently; OR include the manifest object in /api/apps and adapt the loader. The menu and the loader MUST read the same shape.
MF dynamic remote loading: verify loadFederatedAppFromManifest actually loads a RUNTIME/dynamic remote (registered at runtime, not in the host's build-time vite.config remotes). The host shell uses @originjs/vite-plugin-federation with a static billing remote; loading Clock by URL at runtime needs proper dynamic-remote handling (__federation_method_* / @module-federation/runtime). Ensure React/react-dom are shared singletons between the host shell and the clock-app remote (clock-app/vite.config.tsshared), or the remote will fail/hang. Confirm the exposed module name (./ClockApp) + scope (clockApp) match.
DB durability:ensureBuiltins does INSERT … ON CONFLICT (slug) DO NOTHING, but apps.slug only had a PARTIAL unique index (WHERE slug IS NOT NULL), which Postgres can't use for ON CONFLICT — it failed until I manually added a NON-partial apps_slug_key unique index in prod. Add a knex migration (backend/applications) creating a non-partial unique index/constraint on apps.slug so fresh DBs + future deploys work.
Verify with Playwright (frontend-test-engineer): an e2e that logs in, opens the app menu, selects Clock, and asserts it actually renders (a clock UI, not the spinner) — run against prod and/or the approved frames in design/frames/federated-apps/. Also the register FuzeMarket → "Market" appears + loads path.
STATE
done = remote built+served+registered, CI matrix wired, applications-service build fixed (Zod), slug index added manually; remaining = host /api/v1/app-registry proxy + frontend menu/loader manifest-shape consistency + MF dynamic-remote/shared-React + slug migration + e2e that Clock mounts. decisions = manifest is the single contract (#107).
End with DONE: <PR link> + confirmation Clock mounts. @izzywdev BLOCKED: <q> + STATE if blocked.
@claude — The built-in Clock federated app does NOT mount in prod (infinite "Loading application…" spinner). #129 shipped the platform but it has integration bugs that passed the gates yet break at runtime. Fix end-to-end and VERIFY with Playwright that Clock actually mounts. Land via PR (master is deploy-on-push).
Verified diagnostics (already done on prod — build on these, don't re-investigate)
release.ymlmatrix) + is DEPLOYED + SERVES:https://app.fuzefront.com/apps/clock/assets/remoteEntry.jsreturns 200 application/javascript. (Note the real path is under/assets/.)ensureBuiltins): DB row is correct —remote_url/url=…/apps/clock/assets/remoteEntry.js,integration_type=module-federation,scope=clockApp,module=./ClockApp,is_activetrue,visibilitypublic,statusactivated.FederatedAppLoader(frontend/src/components/FederatedAppLoader.tsx) readsapp.manifest.integration.{type,remoteEntry,scope,module}, but the apps the shell receives come from the host legacy/api/apps, whose objects have NOmanifestfield (keys:integrationType, remoteUrl, scope, module, url, …). Soapp.manifestis undefined → the loader can't resolve the remote → infinite spinner. Clock shows in the menu (from/api/apps) but never mounts.backend/src/index.ts) only mounts/api/apps; it never proxies/api/v1/app-registry(the new manifest-shaped API feat: Federated App Platform impl (registry+menu-sub+Clock+e2e+standalone) #129 added to applications-service). So the frontend's@fuzefront/app-registry-clientis 404 same-origin.Required fix (make Clock mount)
/api/v1/app-registry/*→ applications-service (same pattern as the billing proxy /apps.ts), and make the shell's app menu +FederatedAppLoaderuse the manifest-shaped@fuzefront/app-registry-clientconsistently; OR include themanifestobject in/api/appsand adapt the loader. The menu and the loader MUST read the same shape.loadFederatedAppFromManifestactually loads a RUNTIME/dynamic remote (registered at runtime, not in the host's build-timevite.configremotes). The host shell uses@originjs/vite-plugin-federationwith a staticbillingremote; loading Clock by URL at runtime needs proper dynamic-remote handling (__federation_method_*/@module-federation/runtime). Ensure React/react-dom are shared singletons between the host shell and the clock-app remote (clock-app/vite.config.tsshared), or the remote will fail/hang. Confirm the exposed module name (./ClockApp) + scope (clockApp) match.ensureBuiltinsdoesINSERT … ON CONFLICT (slug) DO NOTHING, butapps.slugonly had a PARTIAL unique index (WHERE slug IS NOT NULL), which Postgres can't use for ON CONFLICT — it failed until I manually added a NON-partialapps_slug_keyunique index in prod. Add a knex migration (backend/applications) creating a non-partial unique index/constraint onapps.slugso fresh DBs + future deploys work.design/frames/federated-apps/. Also theregister FuzeMarket → "Market" appears + loadspath.STATE
done = remote built+served+registered, CI matrix wired, applications-service build fixed (Zod), slug index added manually; remaining = host
/api/v1/app-registryproxy + frontend menu/loader manifest-shape consistency + MF dynamic-remote/shared-React + slug migration + e2e that Clock mounts. decisions = manifest is the single contract (#107).End with
DONE: <PR link>+ confirmation Clock mounts.@izzywdev BLOCKED: <q>+ STATE if blocked.