Monorepo showcasing microfrontend architecture for user role management and permission visualization.
The apps are:
apps/nuxt-host: Nuxt 3 host, API owner, and authoritative workflow.apps/svelte-visualizer: Svelte/Vite auxiliary permission visualizer, exposed as a federated remote and runnable alone.apps/
nuxt-host/ Nuxt 3 host UI, Nitro API routes, in-memory server state
svelte-visualizer/ Independent Svelte visualizer app and federated widget
packages/
contracts/ Zod schemas, inferred TypeScript types, API DTOs, event contracts
headless/ Pure permission analysis logic
design-system/ Shared CSS tokens and lightweight UI conventions
event-bus/ Browser event adapter with runtime validation and failure simulation
sdk/ Typed API client that validates responses with Zod
eslint-config/ Shared ESLint presets
typescript-config/ Shared TypeScript baselines
tooling/
eslint/ Tooling boundary notes
tsconfig/ Tooling boundary notes
pnpm install
pnpm dev
Then open:
http://localhost:3000http://localhost:5173Useful checks:
pnpm check-types:role-demo
pnpm turbo run lint --filter=nuxt-host --filter=svelte-visualizer --filter=@repo/contracts --filter=@repo/headless --filter=@repo/design-system --filter=@repo/event-bus --filter=@repo/sdk
pnpm turbo run build --filter=nuxt-host --filter=svelte-visualizer
remoteEntry.js.This split is useful because role assignment is core workflow and belongs with the API owner, while permission analysis can evolve independently into a richer sidebar, embeddable widget, or operational console.
The API is the source of truth. Events are only a fast sync path.
Initial and recovery flow:
/api/state./api/users/:id/permissions for the selected user.USER_SELECTED and USER_ROLES_UPDATED.The host page has two visible demo toggles:
@repo/event-bus. Nuxt still updates roles through the API, and Svelte shows degraded mode with an API rehydrate path.Svelte also has a manual Rehydrate from API button so recovery is visible during demos.
packages/contracts defines Zod schemas and inferred types for:
Validation is applied at the boundaries:
packages/headless contains pure TypeScript functions for:
packages/design-system shares CSS variables and primitive style conventions only. There are no cross-framework components, keeping Vue/Nuxt and Svelte concerns separate.
Seeded roles:
admin: broad access, including high-sensitivity permissionseditor: user/report editing without publish accessviewer: read-only accessbilling: invoice and billing operations without report contextExample findings:
admin + viewer is redundanteditor + viewer overlapsbilling + editor needs reviewbilling without read_reports gets a missing recommended permission note