Le problème
La plupart des MVPs démarrent avec tout dans les routes : validation, logique métier, requêtes DB, envoi d'emails. Ça marche au début. Ça devient un cauchemar à 10 000 lignes.
La solution : séparer les responsabilités
On utilise une architecture en couches inspirée de la clean architecture / hexagonale :
Domain
Les types, les règles métier pures. Pas de dépendance externe.
- "Un drop ne peut pas avoir un prix négatif"
- "Une raffle ne peut pas être tirée avant la fin des inscriptions"
Application (Use Cases)
La logique métier orchestrée. Chaque use case fait une chose.
CreateDrop: valide les données, crée le drop, envoie un eventProcessPayment: vérifie le stock, crée la commande, décrémenteRegisterUser: hash le password, crée le user, envoie l'email
Infrastructure (Adapters)
Les implémentations concrètes : base de données (Drizzle), emails (Resend), paiement (Stripe), stockage (R2).
Pourquoi dès le MVP ?
- Testabilité : on peut tester un use case sans base de données
- Lisibilité : chaque fichier fait une chose, nommé clairement
- Maintenabilité : changer de DB ou de provider email ne touche qu'un adapter
- Onboarding : un nouveau dev comprend la structure en 5 minutes
En pratique
Structure d'un module
domain/— types, interfacesapplication/— use casesinfrastructure/— adapters (DB, services externes)routes/— endpoints HTTP (mince couche Hono)
Règle d'or
Les routes appellent les use cases. Les use cases appellent les ports (interfaces). Les adapters implémentent les ports. Les flèches de dépendance pointent toujours vers le centre (domain).
Le coût
Un peu plus de fichiers, un peu plus de structure. Mais le retour sur investissement arrive vite — dès qu'on a 5+ modules, la clarté paie.
En résumé
Domain → Application → Infrastructure. Chaque couche a une responsabilité claire. Le code est testable, lisible, maintenable dès le jour 1.