--- name: architecture-decisions description: Key architecture choices for the SDK + BFF + workspace and the reasons metadata: type: project --- **pnpm workspace, two packages.** `packages/messaging-inbox-sdk` (the shareable SDK) and `apps/web` (the demo). The app depends on the SDK via `workspace:*` and Next `transpilePackages` transpiles the SDK's TS source directly (SDK `main`/`types` point at `src/index.ts`, no build step). This mirrors the IIOS layout (packages + apps) and keeps the SDK genuinely reusable. **BFF pattern (explicit client requirement).** The UI/SDK only ever calls `BffClient`, which hits `/api/bff/**` (Next route handlers). Every route calls `getBackend()` (a formal `Backend` interface in `apps/web/lib/backend/`), never the store directly. `BFF_BACKEND` env picks the impl: `mock` (default, wraps `lib/mock/store.ts`) or `iios` (`lib/backend/iios.ts` → real IIOS via `lib/iios/client.ts` + `map.ts`). Messages/inbox/tickets are wired to IIOS; bootstrap/channels/ reactions/search/notifications delegate to mock until IIOS exposes those endpoints. Flipping to live IIOS is one env var (needs the IIOS service + Docker/Postgres running — see `docs/IIOS_INTEGRATION.md`). This is the single swap seam; the SDK and components never change. **Config resolved on the server.** `getServerConfig()` runs in the root layout (server component), reads `NEXT_PUBLIC_*` from `process.env`, returns a plain `SdkConfig`, and passes it to the client ``. Avoids the Next.js gotcha that dynamic `process.env[key]` doesn't work in the browser bundle. Theme vars are also inlined into `` on first paint to prevent a flash. **Theme = CSS variables + Tailwind mapping.** All Tailwind colors resolve to `--c-*` vars set on `` at runtime by the provider. Light/dark and brand re-skin are just different variable values; nothing is hard-coded. `darkMode: 'class'`. **Feature flags are data, not conditionals scattered around.** One `FeatureFlags` interface; `NEXT_PUBLIC_FEATURE_` overrides each. Components call `useFeature("x")`. **Why not build the NestJS/DB backend?** The ask was a static demo with everything working. A NestJS BFF + Postgres adds setup cost with no demo benefit; it's documented as the production path instead (`docs/IIOS_INTEGRATION.md`, `docs/BFF.md`). Related: [[design-system]], [[conventions]], [[iios-relationship]].