Comment Sushi SaaS est structuré
Comprendre les couches imposées, leurs compromis et comment ajouter une fonctionnalité sans créer une seconde architecture.
Ce guide aide les adoptants à placer leur première fonctionnalité produit. Sushi SaaS applique une architecture horizontale à tous les domaines et des tests en imposent les règles.
Le parcours d’une requête
src/app/** routes et pages — HTTP entrant et sortant
↓
src/services/** règles métier, orchestration, invariants
↓
src/models/** persistance typée ; seule couche appelant db()
↓
src/db/** schéma, migrations, connexionUne route analyse et répond. Un service décide si l’action est autorisée et coordonne les effets. Un modèle possède les lectures et écritures. Les contraintes de base restent la dernière protection contre les requêtes concurrentes.
Le navigateur suit une autre frontière :
Server Component → service directement
Client Component → src/api/** → client API partagé → /api/**Cela évite au serveur un appel HTTP vers lui-même et donne aux erreurs client un contrat unique. Les règles exactes figurent dans Architecture et contrats d’erreur.
Pourquoi des couches horizontales
Facturation, crédits, stockage, réservations et tâches ont tous besoin d’authentification, de scope tenant, d’erreurs et de persistance. Les mêmes couches rendent chaque responsabilité prévisible et permettent aux tests de détecter les raccourcis.
En contrepartie, une fonctionnalité se répartit entre plusieurs dossiers. Un dossier vertical par feature peut être plus lisible dans un grand produit ; mélanger les deux structures est toutefois pire, car chaque nouvelle requête ou règle a deux emplacements plausibles.
Vos options
- Garder la structure livrée pour une petite équipe qui veut des conventions fortes et une infrastructure commune.
- Passer entièrement aux tranches verticales si c’est la norme de l’équipe. Déplacez des domaines complets et adaptez
tests/unit/architecture.test.ts; n’ajoutez pas un îlotsrc/featuresà côté des règles actuelles. - Simplifier pour un prototype temporaire en acceptant une migration ultérieure. Si les routes écrivent directement en base, modifiez explicitement le test au lieu d’empiler des exceptions.
La tenancy est aussi un choix d’architecture
Chaque utilisateur reçoit une organisation personnelle. Un client seul et une équipe utilisent ainsi les mêmes facturation, crédits, fichiers et limites au scope organisation, sans deux chemins parallèles « utilisateur » et « équipe ».
Gardez ce modèle si des équipes sont possibles. Pour un produit toujours mono-utilisateur, retirer les organisations est valide, mais coordonne autorisation, schéma, modèles, facturation, stockage et tests ; ce n’est pas un simple toggle UI. Lisez Organisations et équipes avant de décider.
Pourquoi l’admin est séparé
apps/admin possède pages, APIs, accès aux données, barrière MFA et rôles opérateur. Il partage schéma et auth, mais peut tourner sur une autre origine. Le coût est un build et un déploiement supplémentaires ; le bénéfice, une frontière opérateur claire.
Vous pouvez le fusionner avec l’application client pour un déploiement unique. Conservez l’autorisation admin côté serveur et l’audit : masquer la navigation n’est pas une mesure de sécurité. Commencez par Configurer la console d’administration.
Un parcours vertical complet à travers les couches
La référence image montre l’intérêt de la structure. La route authentifie ; le service empreinte la requête, réserve une dépense déterministe de cinq crédits et distribue le job ; les modèles possèdent SQL ; les contraintes relient les enregistrements ; l’adaptateur reste remplaçable ; le worker stocke en privé ou compense le registre. Tests route, service, base, composant et Playwright prouvent chacun une frontière.
Lisez Pourquoi une tâche de cinq crédits teste tout le SaaS avant votre premier domaine payant.
Ajouter votre premier domaine
- Définissez vocabulaire et limites dans
src/typesetsrc/config. - Ajoutez schéma et migration expand-safe dans
src/db. - Placez le CRUD typé dans
src/models. - Placez autorisation, idempotence et effets dans
src/services. - Ajoutez route ou Server Component dans
src/app; utilisezsrc/apicôté client. - Testez la règle service, la barrière auth de la route et les replays pour argent ou crédits.
Testez les capabilities plutôt que le nom du plan et mettez à jour le runbook si le contrat change. Ce guide reflète le commit 2a1a04a.