Vue d'ensemble de l'architecture¶
ikloze suit une architecture en couches stricte. Chaque couche a une seule responsabilité, et franchir une frontière est un point bloquant en revue.
┌─────────────────────────────────────────────────────────────┐
│ web/<module>/ HTTP uniquement │
│ Contrôleurs NestJS, DTO/Swagger, gardes, filtres │
│ → parse l'entrée → appelle le service → renvoie le résultat │
└───────────────┬─────────────────────────────────────────────┘
│ appelle
┌───────────────▼─────────────────────────────────────────────┐
│ app/<module>/ Logique métier (TypeScript sans framework) │
│ Services use-case : autorise → valide → logique → persiste │
└───────────────┬─────────────────────────────────────────────┘
┌───────┴───────────────────┐
│ utilise │ persiste via
┌───────▼──────────┐ ┌──────────▼──────────────────────────┐
│ domain/ │ │ database/sequelize/ │
│ Entités + erreurs│ │ Modèles, migrations, accesseurs │
│ fromRecord, pur │ │ typés, associations │
└──────────────────┘ └─────────────────────────────────────┘
│ I/O externe via
┌───────▼─────────────────────────────────────────────────────┐
│ adapters/ SMTP, paiement, stockage S3, géocodage, IA… │
└─────────────────────────────────────────────────────────────┘
Responsabilité de chaque couche¶
web/ — HTTP uniquement¶
Contrôleurs, DTO/schémas Swagger, gardes, filtres. Aucune logique métier, aucun appel Sequelize. Le corps d'un contrôleur doit être : parser l'entrée → appeler le service → renvoyer le résultat.
app/<module>/ — Logique métier¶
Classes TypeScript sans framework. Les services autorisent, valident, mutent, persistent. Aucun type HTTP (Request, Response, codes de statut), aucun décorateur Swagger. Les services accèdent à la base directement via les accesseurs typés de database/sequelize/models.ts.
domain/ — Données pures¶
Classes d'entités (données + mapper statique fromRecord) et classes d'erreurs de domaine. Aucune I/O, aucun Sequelize, aucun Nest.
database/sequelize/ — Persistance¶
Modèles, migrations, accesseurs et associations. Voir Accès aux données.
adapters/ — I/O externe¶
SMTP, géocodage HTTP, passerelles de paiement, stockage S3, IA. Encapsulés pour que les services dépendent d'une interface, pas du SDK du fournisseur.
Signal d'alerte
Si vous importez depuis @nestjs/* dans app/ ou domain/, ou si vous appelez un accesseur Sequelize dans web/ — arrêtez : vous êtes dans la mauvaise couche.
La recette de service en 6 étapes¶
Tout service use-case dans app/<module>/ suit le même squelette :
- Autoriser — vérifier
user.hasPerm(...)(voir Permissions). - Valider — parser l'entrée avec un schéma Zod.
- Logique — appliquer les règles métier.
- Persister — écrire via les accesseurs typés, en transaction si plusieurs écritures.
- Journaliser — historique / effets de bord.
- Retourner — une entité de domaine, jamais un record Sequelize brut.
Signature des méthodes de service
Les méthodes publiques de service prennent user: User en dernier paramètre positionnel, nommé user (jamais actor/caller).
La compétence ikloze-define-service du dépôt détaille cette recette (schémas Zod, scoping workspace anti-énumération, politique d'erreurs, transactions, effets de bord).
Conventions transverses¶
- Multi-tenant — le workspace est la frontière de toutes les données.
- Permissions (RBAC) — modèle User → Group → Permission.
- Accès aux données — accesseurs typés,
fromRecord,include. - Erreurs & i18n — erreurs de domaine, filtres HTTP, localisation.
- Style de code — naming, commentaires, DRY, KISS, SOC.