Documentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
Status: Inert scaffolding committed; activation requires project-owner action
Owner: Platform Architecture (technical) + Jeremy Bloom (Vercel dashboard owner)
Phase: 3 of docs/recommendations/DEV_VELOCITY_AND_ARCHITECTURE_PLAN_2026-04-22.md (lands via PR #137)
ADRs: ADR-008 (preserved), ADR-013 (amendment proposed in ADR-017)
What this PR ships
microfrontends.json at the repo root — the proposed split. Two applications:
encoreos-app (default; receives every un-routed path; today this is the entire app)
encoreos-public (peeled off: /auth, /employee-setup, /pending-activation, /pm/kiosk/:siteId/*, /portal/*, /p/:token, /packet/:token, /gr/whistleblower-report, /chatbot/widget)
- Turborepo workspace mapping: Turborepo resolves
microfrontends.json application keys to npm workspace packages by matching the application key to package.json name. The keys encoreos-app / encoreos-public therefore have minimal placeholder packages at packages/encoreos-app and packages/encoreos-public (private, no source — the real app remains the root Vite SPA). When Phase 3 splits into real deployables, replace these placeholders with actual package roots or add packageName per the Turborepo microfrontends schema.
scripts/audit/validate-microfrontends-config.ts — fast structural validator (kebab-case names, single default app, paths start with /, literal-overlap detection, soft check that paths exist in src/App.tsx / src/routes/). Wired to npm run audit:microfrontends.
docs/architecture/decisions/ADR-017-microfrontends-pwa-scoping.md — formal ADR amending ADR-013 to handle per-zone PWA scopes.
- This runbook — step-by-step activation instructions, env-var layout, CI wiring, Playwright proxy invocation, rollback plan.
What is intentionally NOT shipped:
- The
@vercel/microfrontends Vite plugin is not installed and not wired into vite.config.ts. Adding it without a corresponding Vercel project + microfrontends group does nothing useful and would only add a transitive dep. The activation steps below cover the install.
- No new Vercel projects exist yet. Creation is a dashboard action only a project owner can perform.
- The
microfrontends.json file is inert until a Vercel Microfrontends Group exists in the Vercel team and the application names there match the names in this file.
This is intentional: by the time someone is ready to flip the switch, the design choices, validation, and PWA strategy are all already in code review.
⚠️ Editing microfrontends.json — strict-keys gotcha
Both Turborepo (turbo 2.9+) and the Vercel runtime parse microfrontends.json and reject any unknown keys — including JSON-comment-style fields like _comment, _comment_*, etc. If an unknown key slips in, turbo run … aborts with Unable to parse JSON: Found an unknown key … and every Turborepo task fails before it starts. This regression was introduced once already (PR #145, fixed in the verification PR) when this runbook’s author shipped Vercel-style _comment_* keys.
Allowed top-level keys: $schema, applications, options. Allowed per-application keys: routing, development, packageName, assetPrefix. Allowed per-routing-rule keys: group, paths, flag. Allowed development keys: fallback, local, task.
Keep narrative notes here (in this runbook), not in microfrontends.json. The npm run audit:microfrontends validator now hard-fails on unknown keys to prevent this from ever shipping again.
Activation overview (project-owner steps)
Activation is sequenced in five phases. Steps 1–2 are dashboard / infrastructure actions; steps 3–5 are code PRs.
| Step | Who | Time | Reversible? |
|---|
1. Create the second Vercel project (encoreos-public) | Project owner | ~5 min | trivially (delete project) |
| 2. Create the Microfrontends Group + add both projects | Project owner | ~5 min | trivially (delete group) |
| 3. Land the wiring PR (Vite plugin install + plugin registration) | Engineer + project owner | ~half-day | revert PR |
| 4. Promote a preview build with the new routing live | Project owner | ~10 min | Vercel Instant Rollback (one-click) |
| 5. Production cutover | Project owner | ~5 min after preview soak | Vercel Instant Rollback |
If anything looks off at any step, stop. The microfrontends.json file in prod does nothing until the Vercel Group is wired up; rolling forward in code is decoupled from rolling forward in production routing.
Step 1 — Create the second Vercel project
In the Vercel dashboard:
- Add New… → Project → Continue with this Repository (
Encore-OS/encoreos).
- Project name:
encoreos-public.
- Framework preset: Vite. Root directory:
. (same monorepo root).
- Build & Development Settings:
- Build command:
npm run build (same as the main project; the Vite plugin handles asset prefixing once installed).
- Output directory:
dist.
- Install command:
npm ci --legacy-peer-deps.
- Environment variables: none for now. Build-time Supabase URL/key are statically defined in
vite.config.ts per VERCEL_PROJECT_ID (see AGENTS.md § Cursor Cloud caveats and docs/development/VERCEL_ENV_REMOVAL_EXECUTION_2026-04-20.md).
- Important: before adding
encoreos-public’s prj_* ID to vite.config.ts’s VERCEL_PROJECT_TO_SUPABASE map, decide which Supabase target it points to. Recommend same as the parent project’s environment so encoreos_dev’s public zone hits dev Supabase, and encoreos_prod’s public zone hits prod Supabase.
- Do not deploy yet. Pause auto-deploy under Settings → Git → Deploy Hooks if the project tries to build immediately.
Repeat for any additional zones beyond the recommended split (the recommendations doc § 5.5 suggests a possible second wave: encoreos-clinical for /cl/* + /pm/* — only do this if Phase 1+2 measurements show it’s still needed).
Step 2 — Create the Microfrontends Group
In the Vercel dashboard:
- Team Settings → Microfrontends → Create Group.
- Group name:
encoreos.
- Default application:
encoreos-app (the original project).
- Add
encoreos-public to the group.
- Fallback environment:
Same Environment (so preview builds without a matching encoreos-public build fall back to the production deployment of encoreos-public rather than the production deployment of encoreos-app).
- Confirm pricing acknowledgement: 2 microfrontend projects per group are included on Pro; the proposed split fits in the free tier as long as we never add a third zone.
The group will not change behavior until the next deployment of the default application that contains a microfrontends.json file. Since this PR commits microfrontends.json already, the next merge to prod after activation will start routing.
⚠️ Sequence matters. Create the group before merging the wiring PR (step 3). If the wiring PR merges first while the group does not exist, Vercel logs a deployment warning but does no harm — the file is treated as inert.
Step 3 — Land the wiring PR
This is a small follow-up PR — open it once steps 1 and 2 are complete:
# Install the Vite plugin (one new dep)
npm install --save @vercel/microfrontends --legacy-peer-deps
Add to vite.config.ts:
import { microfrontends } from '@vercel/microfrontends/experimental/vite';
// inside the plugins array:
microfrontends({
// The Vite plugin auto-detects the application name from VERCEL_PROJECT_ID
// matched against the Vercel project names in microfrontends.json.
// No options needed for the basic case.
}),
Update package.json:
{
"scripts": {
"mf:proxy": "microfrontends proxy --local-apps encoreos-app encoreos-public",
"mf:port": "microfrontends port"
}
}
Verify locally:
npm run audit:microfrontends # validate the config
npm run build # confirm Vite plugin doesn't break the build
npm run mf:proxy # in one terminal
npm run dev # in another
# Visit the proxy URL printed by `mf:proxy` (typically http://localhost:3024)
# Try /, /auth, /pm/kiosk/test, /portal/login — all should resolve
The wiring PR should also:
- Update
.github/workflows/build.yml to run npm run audit:microfrontends as a blocking step.
- Update
.github/workflows/build.yml to set MFE_DISABLE_LOCAL_PROXY_REWRITE=1 so existing E2E tests that hit individual project URLs continue to work.
- Add
TURBO_TOKEN / TURBO_TEAM GitHub Actions secrets if you also want Vercel Remote Cache active for the encoreos-public project (see docs/development/TURBOREPO_USAGE.md).
Step 4 — Preview soak
- After the wiring PR merges, open a fresh PR (any small change). Vercel will build BOTH
encoreos-app AND encoreos-public for the preview commit.
- Visit the preview URL of
encoreos-app. You should see:
/ → main app (HR, etc.) — same as today.
/auth → routed to encoreos-public. Look for the small “M” badge on the deployment page (Vercel Microfrontends indicator).
/pm/kiosk/test → routed to encoreos-public.
- Open the Vercel Toolbar on the preview, expand the Microfrontends Panel, and confirm the routing table matches
microfrontends.json.
- Run the smoke E2E suite against the preview:
If any test asserts a hard navigation between
/auth and any authenticated route, expect it to still pass but to take an extra ~200 ms (the cross-zone hard-navigation cost). If any test relies on shared client state across zones, it will fail — those tests need to be rewritten or marked skip-on-microfrontends.
Soak the preview for at least 24 hours before proceeding. Watch the Vercel Speed Insights dashboard for the preview to confirm INP/LCP are not regressing on routes that cross zones.
Step 5 — Production cutover
- Promote the soaked preview deployment to production via the Vercel dashboard’s “Promote to Production” button.
- Watch Sentry for new error volume in the first 30 minutes — particularly:
- Hydration mismatches (none expected; Vite SPA, no SSR).
- Auth-redirect loops (the
/auth zone now lives behind microfrontends path routing; verify useCurrentUser still works after the hard-nav from /auth → /).
- PWA service worker registration errors (covered by ADR-017; both zones must agree on SW scope).
- If anything looks off, hit Vercel Instant Rollback on the default application (
encoreos-app). Microfrontends routing reverts to the previous microfrontends.json (which, before this whole rollout, was implicit — single app — so the old behavior is fully restored).
Local development
Once steps 1–3 are complete, the local DX is:
# Terminal 1: run the local proxy that knows about the routing config
npm run mf:proxy
# Terminal 2: run the dev server for the zone you're working on
npm run dev # encoreos-app
# OR
npm run dev # if you're working on encoreos-public, run the same; the
# plugin auto-targets based on VERCEL_PROJECT_ID, defaulting to encoreos-app
# Visit the proxy URL printed in terminal 1 (typically http://localhost:3024)
The proxy routes requests for zones you are NOT running locally to the production fallback — so you only need to run one zone at a time.
To hit the local zone directly, bypassing the proxy, set MFE_DISABLE_LOCAL_PROXY_REWRITE=1.
Environment variable layout
| Variable | Where set | Used for |
|---|
VERCEL_PROJECT_ID | Set automatically by Vercel at build time | vite.config.ts uses this to pick dev vs prod Supabase target. Must be added to VERCEL_PROJECT_TO_SUPABASE for the new encoreos-public project IDs (one for dev, one for prod) before the first deploy. |
MFE_DISABLE_LOCAL_PROXY_REWRITE | Local .env only | Bypasses the local proxy when set to 1. Useful for E2E tests that hit a specific zone directly. |
MFE_DEBUG | Local .env only | Verbose logging from the proxy and the Vite plugin. |
TURBO_TOKEN / TURBO_TEAM | GitHub Actions secrets + dashboard | Vercel Remote Cache for both encoreos-app and encoreos-public. Optional but recommended. |
AUTOMATION_BYPASS_ENCOREOS_PUBLIC | GitHub Actions secrets | If encoreos-public ends up behind Vercel Deployment Protection, this is the Protection-Bypass-for-Automation token. Documented in Vercel’s microfrontends local-development docs. |
Do not add new project-level environment variables in the Vercel dashboard for the public client config (Supabase URL, etc.). The constitution / AGENTS.md enforces that those stay in vite.config.ts per VERCEL_PROJECT_ID.
Rollback plan
| Scenario | Action |
|---|
| Bug in production routing | Vercel Instant Rollback on encoreos-app (or encoreos-public) — restores the routing of the previous deployment. |
| Need to roll back the entire microfrontends scheme | Vercel dashboard → Microfrontends → delete the group. The default app reverts to receiving every path, exactly as today. The microfrontends.json file in the repo becomes inert. |
| Need to revert the wiring PR | git revert <wiring-PR-merge-commit>; the Vite plugin disappears; subsequent builds of encoreos-app ignore microfrontends.json. The microfrontends group can be deleted at leisure. |
The whole stack is designed so each layer can be rolled back independently. The riskiest operation is the first promotion to production (step 5); after that, every change is incremental and well-contained.
What this scaffolding does NOT solve
The recommendations doc (§ 3.5–3.7) calls out four hard problems with microfrontends on a Vite SPA. They remain unsolved by this PR — they’re handled at activation time:
- Cross-zone shared state.
OrganizationProvider, QueryClientProvider, Sentry, Sonner, nuqs, and the PWA service worker all bootstrap per zone. A user moving between /auth and the authenticated app pays a cold cache penalty. Mitigations to evaluate at step 4: BroadcastChannel for cross-zone state sync, or accept the cold cache (the public→authenticated transition only happens at sign-in time anyway).
- PWA scope. Each Vercel project generates its own service worker. Only one can install at scope
/. ADR-017 (companion to this PR) defines the per-zone scope strategy: encoreos-app keeps scope: '/'; encoreos-public either uses sub-scopes (scope: '/portal/', etc.) or disables the SW for that zone entirely.
- Dependency duplication. Each zone bundles its own React, Radix, Supabase client. For a 2-zone split this adds ~300 KB of duplicate vendor code on first hard-nav between zones. Acceptable for the proposed split (the public zone is a thin set of pages); not acceptable for a 12-zone split.
- Cross-zone link prefetching. Vercel’s
PrefetchCrossZoneLinks is Next.js only. Any prefetch-on-hover behavior we want has to be implemented manually using Chromium Speculation Rules, the same way Vercel.com does it.
See also