ADR-01 — Séparation apps PWA et Dashboard
Deux Next.js séparés (apps/pwa + apps/dashboard) plutôt qu'un seul avec route groups
Statut : Accepté Date : 2026-04 Sujet : Structure monorepo — combien d'apps web
Contexte
Bell a deux interfaces :
- Une PWA Guest accessible par lien unique envoyé par mail, contrainte 430px, mobile-first, service worker, check-in flow
- Un Dashboard Staff/Admin desktop-first avec sidebars, tables denses, graphiques analytics
Elles partagent la base (Better Auth, packages/api via Eden Treaty, packages/ui, packages/db) mais ont des besoins UX radicalement différents.
Dans l'ancien projet, le front guest était en Expo React Native Web (apps/native) et le dashboard en Next.js (apps/web) — deux stacks complètement différentes. On garde le principe de deux fronts séparés, mais cette fois sur la même stack Next.js.
Alternatives considérées
Option 1 — Un seul apps/web avec route groups
Une seule app Next.js avec (pwa), (dashboard), (admin), (auth) dans le même src/app/.
Pour :
- Un seul
package.json, un seulnext.config, un seul middleware - Code 100 % colocalisé
- Déploiement unique
Contre :
- Bundle commun qui charge des deps PWA (vaul, service worker, manifest) aussi dans le dashboard, et l'inverse
- Middleware auth qui doit jongler entre role=guest (redirect vers check-in flow) et role=staff (redirect vers
/dashboard) avec beaucoup de cas spéciaux - Cycles de déploiement couplés — un hotfix dashboard bloque une feature guest
- PWA service worker scope s'étale sur tout le domaine, ce qui complique la mise en cache
- Performance Lighthouse dégradée sur la PWA (code dashboard embarqué via chunks lazy mais toujours dans le bundle)
Option 2 — Deux apps séparées (retenu)
apps/pwa (guest) + apps/dashboard (staff/admin). Partage via packages/*.
Pour :
- Bundles séparés et optimaux pour chaque cible
- Middleware auth simple : chacun vérifie un role précis et redirige vers son propre
/auth - Déploiements indépendants — on peut hotfix l'un sans toucher l'autre
- Service worker PWA scope sur
bell-app.hoaiy.comuniquement, dashboard surbell-staff.hoaiy.com - Tooling PWA (Vaul, manifest, meta tags iOS) n'impacte pas le dashboard
- DX meilleure : équipe guest / équipe staff peuvent bosser sans se marcher dessus
Contre :
- Deux
package.json, deuxnext.config, deux déploiements - Duplication mineure de la glue (providers React, theme, layout root) — négligeable
Décision
Deux apps Next.js 15 séparées :
apps/pwa— PWA Guest, mobile-first, contrainte 430px, Vaul pour les modals natif-likeapps/dashboard— Staff + Admin, desktop-first, sidebar, tables, charts
Partage via le monorepo :
packages/
├── api → Eden Treaty app (Elysia) + types TypeBox partagés
├── auth → Better Auth config + mail templates
├── db → Drizzle schema + migrations
├── ui → shadcn components + design tokens Bell
├── env → Validation env vars (Zod)
└── config → tsconfig/biome partagésClient Eden Treaty setup dans chaque app (apps/pwa/src/lib/eden.ts, apps/dashboard/src/lib/eden.ts) avec le même packages/api importé.
Routing et domaines
| App | Dev | Prod |
|---|---|---|
apps/pwa | localhost:3001 | bell-app.hoaiy.com |
apps/dashboard | localhost:3002 | bell-staff.hoaiy.com |
apps/server (Elysia) | localhost:3000 | bell-api.hoaiy.com |
apps/fumadocs | localhost:4000 | bell-docs.hoaiy.com (privé) |
En dev, chaque app web utilise un proxy Next.js rewrites vers l'Elysia (/api/* → localhost:3000/*) pour éviter le cross-origin. Voir ADR-02.
En prod, cookies signés avec domain: .hoaiy.com pour SSO entre les subdomains app et staff.
Conséquences
Positives :
- Chaque app est optimisée pour son usage, pas de compromis
- Déploiement sélectif (canary staff sans impact guest)
- Onboarding dev plus simple — on dit "tu bosses sur guest" et la zone de code est claire
- Service worker PWA propre
Négatives :
- Maintenance de deux
next.config.ts, deuxmiddleware.ts— mineur - Si on ajoute un composant partagé, il doit aller dans
packages/uiet pas dansapps/*/components— discipline à tenir
Métriques à surveiller
- Taille du bundle JS initial de chaque app (cible PWA : < 200 KB gzipped, dashboard : < 400 KB)
- Lighthouse PWA Mobile (cible : > 90 sur tous les axes)
- Temps de build de chaque app (cible : < 60 s en prod)
- Nombre de composants dupliqués entre les deux apps (cible : 0 — si on dup, on refactor vers
packages/ui)