ddd-ts-kit
Domain-Driven Design (DDD), Clean Architecture (hexagonale, ports et adaptateurs) et Clean Code pour les backends TypeScript et Node.js, tenus par des outils plutôt que par de bonnes intentions, pour les développeurs et pour les agents de code avec lesquels ils travaillent : Claude Code, Codex et GitHub Copilot.
Pourquoi ddd-ts-kit
Section intitulée « Pourquoi ddd-ts-kit »Le Domain-Driven Design et la Clean Architecture s'érodent un raccourci à la fois : un
new Date() dans un gestionnaire, un import entre deux contextes, une règle vérifiée dans un
contrôleur. Sous la pression d'une échéance, et plus encore avec un agent d'IA qui écrit cent
fichiers à l'heure, une consigne dans un wiki ne tient pas. ddd-ts-kit fait de l'architecture
des règles à identifiant, et les vérifie à chaque écriture de fichier, avant chaque fusion et à
chaque push.
- Des règles, pas des consignes. Chaque règle a un identifiant, une raison et une correction
(
npx ddd-ts-kit explain <rule-id>), vérifiées par une CLI sans dépendance, un plugin ESLint et dependency-cruiser. - Générer, pas taper.
ddd-ts-kit generateécrit 36 types de briques avec leur spec, leur fake et leur enregistrement, et laisse unTODO(domain)là où une décision métier est attendue. - Fait pour les agents de code. Un plugin pour Claude Code, Codex et GitHub Copilot : des skills qui conduisent le travail étape par étape, des agents pour le travail en parallèle et la revue, et un hook qui refuse une écriture qui enfreint une règle.
- Votre stack, pas la nôtre. Express, Fastify, Hono ou NestJS ; zod, class-validator, TypeBox ou toute bibliothèque Standard Schema ; tsyringe, NestJS ou un câblage manuel ; Drizzle, Knex, Prisma ou TypeORM ; RabbitMQ, Kafka, NATS JetStream ou Redis Streams ; JWT ou Keycloak ; rôles, attributs ou relations.
- Les exigences de la production, intégrées. Outbox transactionnelle et consommateurs idempotents, une permission par cas d'usage, journal d'audit, OpenTelemetry, multitenancy, contrats OpenAPI et AsyncAPI, un pipeline de CI pour GitHub et GitLab.
- Prêt à être découpé. Chaque contexte délimité possède ses données et parle aux autres par des événements : il peut tourner comme son propre service le jour où l'équipe en a besoin.
L'histoire derrière le projet, sur Medium : Votre IA code vite. Votre architecture décide si ça tiendra. (en anglais).
La documentation est aussi un site web, avec une recherche, en français et en anglais : https://gbourgeat.github.io/ddd-ts-kit/fr/. Chaque page a sa traduction à côté d'elle, à laquelle mène le lien de sa première ligne.
Démarrage rapide
Section intitulée « Démarrage rapide »mkdir orders-api && cd orders-apinpx ddd-ts-kit initpnpm installpnpm run verify # types, lint, format, tests, e2e, architecture, graphe des imports, code mort, dérive de la documentationinit sans option prend Express, zod, tsyringe, Drizzle sur PostgreSQL, Vitest et pnpm, que
corepack fournit à la version qu'épingle le package.json (corepack enable, une fois par
machine). Le projet est vert dès ce premier verify, avant une ligne de code métier, et le
reste à chaque étape. Ensuite, le langage omniprésent d'abord, le code ensuite :
pnpm exec ddd-ts-kit generate context ordering --classification core \ --term "Order=A customer's request to buy products" --term "Place=To submit an order for fulfilment"pnpm exec ddd-ts-kit generate context billing --classification supporting --upstream ordering:customer-supplierpnpm exec ddd-ts-kit generate aggregate ordering Orderpnpm exec ddd-ts-kit generate repository ordering Orderpnpm exec ddd-ts-kit generate command ordering PlaceOrder --permission order.place --grant customer --aggregate Orderpnpm exec ddd-ts-kit generate route ordering PlaceOrder --method POST --path /orderspnpm run docs:generate # le contrat OpenAPI suit la nouvelle routepnpm run verifypnpm exec ddd-ts-kit status # ce qui reste : TODO(domain), TODO(platform) et it.todo par contexteCes deux blocs sont exécutés tels qu'ils sont écrits, ligne par ligne, par la suite de bout en
bout de ce dépôt, sur pnpm et sur npm. Avec npx ddd-ts-kit init --package-manager npm, les
mêmes lignes se lisent npm install, npm run <script> et npx ddd-ts-kit <command>. Pour
voir l'application tourner : cp .env.example .env, pnpm run infra:up (PostgreSQL, dans
Docker), pnpm run db:generate initial, pnpm run db:migrate, puis pnpm run dev
(rechargement automatique ; documentation de l'API sur /docs).
Un nom absent du glossaire du contexte est refusé, tout comme une commande ou une requête qui ne
déclare ni permission ni --public. Une tranche, de bout en bout
suit la requête HTTP POST /orders à travers les quatre couches et montre le code une fois les
endroits TODO(domain) remplis.
Démarrer un projet
Section intitulée « Démarrer un projet »Suivez ces étapes dans l'ordre : c'est le chemin pris en charge, et les outils sont faits pour
le tenir. Chaque étape est une skill du plugin (/ddd-ts-kit:<skill>), ou une commande, et
laisse un fichier que la suivante lit. /ddd-ts-kit:start conduit les étapes 1 à 7 une à une,
et npx ddd-ts-kit status dit à tout moment quelle étape vient ensuite.
| # | Étape | Skill ou commande | Produit |
|---|---|---|---|
| 1 | Découvrir le domaine | discover-domain |
docs/architecture/discovery.md : acteurs, commandes, événements, politiques |
| 2 | Trouver les contextes délimités | bounded-contexts |
docs/architecture/contexts.md : chaque frontière et sa raison |
| 3 | Écrire les glossaires | glossary |
le langage omniprésent de chaque contexte |
| 4 | Dessiner la carte des contextes | context-map |
qui est en amont de qui, et selon quel patron |
| 5 | Choisir la stack et démarrer | bootstrap, ddd-ts-kit init, generate context |
le projet, vert sur verify, un CONTEXT.md par contexte |
| 6 | Planifier les tranches | plan-slices |
docs/architecture/slices.md : un cas d'usage par tranche, dans l'ordre |
| 7 | Construire tranche par tranche | use-case (parallel-work pour plusieurs workers) |
le code et ses tests, un commit par tranche |
| 8 | Passer la porte de qualité | quality-gate, npm run verify |
une porte verte avant chaque fusion |
| 9 | Documenter | document, npm run docs:generate |
des contrats, une carte des contextes et des enregistrements de décision à jour |
La méthodologie est la référence de chaque étape et dit ce que coûte d'en sauter une ; quelle commande, quand donne la commande de chaque moment d'un projet.
Ce qui est imposé
Section intitulée « Ce qui est imposé »Un gestionnaire écrit à la va-vite enfreint quatre règles d'un coup, et chaque constat nomme sa règle :
// application/commands/place-order/place-order.handler.ts, écrit à la va-viteimport { CommandHandler } from '@ddd-ts-kit/kernel/declarations';import { PlaceOrderCommand } from '@/contexts/ordering/application/commands/place-order/place-order.command';import { db, orders } from '@/contexts/ordering/infrastructure/database'; // layer/application-inward
@CommandHandler(PlaceOrderCommand)export class PlaceOrderHandler implements CommandHandler<PlaceOrderCommand> { async execute({ customerId, productIds }: PlaceOrderCommand): Promise<string> { if (productIds.length === 0) { throw new Error('Empty order'); // domain/no-generic-error }
const id = crypto.randomUUID(); // purity/no-ambient-randomness
await db.insert(orders).values({ id, customerId, productIds, placedAt: new Date() }); // purity/no-system-clock
return id; }}| Au lieu de | Écrivez | Règle |
|---|---|---|
new Date() |
this.clock.now(), le port Clock reçu dans le constructeur |
purity/no-system-clock |
crypto.randomUUID() |
this.ids.next(), le port IdGenerator |
purity/no-ambient-randomness |
throw new Error('Empty order') |
throw OrderError.empty(), un refus avec un code stable |
domain/no-generic-error |
un import de infrastructure/ dans un gestionnaire |
le port OrderRepository, lié à son adaptateur par la plateforme |
layer/application-inward |
un import du domain/ d'un autre contexte |
le published-language/ de ce contexte, ou un événement d'intégration |
context/published-language-only |
Le même cas d'usage écrit dans les règles se trouve dans Une tranche, de bout en bout. Les règles couvrent, entre autres :
- Couches et contextes (
layer/*,context/*,tree/*) : le domaine n'importe rien d'autre que lui-même et le kernel ; un autre contexte n'est atteint que par son langage publié ; aucun cycle. - Langage omniprésent (
language/*) : les classes du domaine et les cas d'usage sont nommés avec les termes du glossaire du contexte. - DDD tactique et pureté (
domain/*,application/*,events/*,purity/*) : des agrégats encapsulés, des objets-valeurs immuables, des erreurs spécifiques, le temps et les identifiants par des ports. - Ports et câblage (
ports/*,declarations/*,composition/*) : un port est une classe abstraite et son propre jeton d'injection, assemblé en un seul endroit. - Contrôle d'accès (
authz/*) : chaque cas d'usage déclare sa permission ou dit qu'il est public, décidée dans la couche application, avec un acteur explicite. - Clean code et tests (
clean/*,test/*) : de petites fonctions en ordre d'escalier, aucune échappatoire, une spec pour chaque unité de comportement, aucun mock.
npx ddd-ts-kit rules liste chaque identifiant avec sa sévérité ; la
référence de l'architecture les définit.
Le plugin pour agents de code
Section intitulée « Le plugin pour agents de code »Ce dépôt est la marketplace du plugin pour Claude Code, Codex et GitHub Copilot :
| Agent | Installation | Une skill s'appelle |
|---|---|---|
| Claude Code | /plugin marketplace add gbourgeat/ddd-ts-kit, puis /plugin install ddd-ts-kit@ddd-ts-kit |
/ddd-ts-kit:start |
| Codex | codex plugin marketplace add gbourgeat/ddd-ts-kit, puis installer ddd-ts-kit depuis /plugins et approuver ses hooks dans /hooks |
$start |
| Copilot CLI | copilot plugin marketplace add gbourgeat/ddd-ts-kit, puis copilot plugin install ddd-ts-kit@ddd-ts-kit |
par son nom, start |
| Agent cloud de Copilot, VS Code | déclaré par le .github/copilot/settings.json qu'écrit init |
par son nom, start |
Vingt-deux skills conduisent un projet d'une expression des besoins jusqu'à des contextes qui
fonctionnent, quatre agents explorent, construisent un contexte dans son propre worktree,
écrivent les specs et relisent, et le hook refuse un fichier écrit à la main là où un générateur
existe et vérifie chaque fichier écrit. Même sans plugin, l'AGENTS.md et les règles par couche
qu'écrit init guident chaque agent. Le plugin pour agents de code
liste les skills et dit ce que chaque hôte exécute.
Packages
Section intitulée « Packages »| Package | Ce qu'il apporte |
|---|---|
ddd-ts-kit |
la CLI : init, generate, check, docs, sdk, status, rules, explain et d'autres |
@ddd-ts-kit/kernel |
entités, agrégats, objets-valeurs, erreurs, ports, les déclarations, bus de commandes, de requêtes et d'événements, les interfaces standard ; aucune dépendance |
@ddd-ts-kit/events |
événements d'intégration typés, outbox transactionnelle et relais, AsyncAPI et catalogue d'événements |
@ddd-ts-kit/rabbitmq, kafka, nats, redis/event-bus |
fournisseurs de brokers derrière un seul contrat : publication acquittée, abonnements durables, nouvelles tentatives, files de rejet |
@ddd-ts-kit/scheduling |
des jobs lancés par le temps qui ne font que déclencher des cas d'usage, une seule exécution sur l'ensemble des instances |
@ddd-ts-kit/auth |
acteurs, une permission par cas d'usage, refus par défaut ; autoriseurs par rôles, par attributs et par relations ; JWT |
@ddd-ts-kit/openfga |
les relations d'auth sur un serveur OpenFGA |
@ddd-ts-kit/aspects |
journalisation, métriques, nouvelle tentative, délai d'expiration, disjoncteur, cache et cloison appliqués de l'extérieur |
@ddd-ts-kit/audit |
journal d'audit chaîné par hachage, en ajout seul |
@ddd-ts-kit/redis |
cache, verrou, limiteur de débit et signal de relais sur Redis, Dragonfly ou Valkey |
@ddd-ts-kit/s3 |
stockage de fichiers sur AWS S3, MinIO, OVHcloud, Scaleway ou Cloudflare R2 |
@ddd-ts-kit/http |
des routes déclarées une fois, montées sur Express, Fastify, Hono ou NestJS ; erreurs RFC 9457 ; OpenAPI 3.1 ; cache HTTP |
@ddd-ts-kit/validation |
un seul port Schema au-dessus de zod, class-validator, TypeBox et Standard Schema |
@ddd-ts-kit/di |
des modules de contexte sur tsyringe, les classes de port comme jetons, une application de test avec des fakes |
@ddd-ts-kit/pino, winston |
le port Logger du kernel sur pino ou winston |
@ddd-ts-kit/sentry |
le port ErrorReporter du kernel sur Sentry ou GlitchTip |
@ddd-ts-kit/tracing |
OpenTelemetry câblé une fois par la plateforme |
@ddd-ts-kit/testing |
builders, scénarios étant donné / quand / alors, suites de contrat, harnais de bout en bout |
@ddd-ts-kit/drizzle, knex, prisma, typeorm |
unité de travail, stockage de l'outbox, modèles de lecture, isolation des tenants, magasin d'événements |
@ddd-ts-kit/eslint-plugin |
les règles de code sur l'arbre syntaxique, avec des préréglages |
Tout passe par des ports du kernel, si bien que chaque pièce est remplaçable : un autre broker, un autre ORM ou un autre framework HTTP est un adaptateur qui passe la même suite de contrat. Le README de chaque package dit ses limites et ce qui a été vérifié.
Pipeline
Section intitulée « Pipeline »init --ci github|gitlab|both installe les mêmes portes sur l'une ou l'autre plateforme :
vérification des types, lint, architecture, code mort, tests unitaires avec seuils de
couverture, tests d'intégration sur PostgreSQL, tests de bout en bout, dérive de la
documentation et du contrat, sécurité et construction de l'image, derrière une seule porte
finale. Chaque outil est gratuit sur n'importe quel dépôt. Les détails :
pipeline/README.md.
Documentation
Section intitulée « Documentation »- Index de la documentation : chaque page, et un ordre de lecture pour qui découvre le DDD, pour un tech lead qui adopte le kit et pour un contributeur.
- Référence de l'architecture (normative) et configuration.
- Concepts : une page par idée, des contextes délimités à l'event sourcing.
- Guides et comparaisons d'outils : la méthodologie, le travail en équipe et en parallèle, et une page par choix technique.
Application d'exemple
Section intitulée « Application d'exemple »examples/scheduling est une plateforme de prise de rendez-vous construite avec le kit comme un utilisateur la construirait : à partir d'une expression des besoins, à travers les neuf étapes, par plusieurs workers en parallèle. Quatre contextes délimités sur Express, class-validator, tsyringe, Knex sur PostgreSQL, l'outbox transactionnelle, Keycloak et une autorisation par relations.
Prérequis
Section intitulée « Prérequis »Node 22.12 ou ultérieur. Les projets générés vérifient leurs types avec le compilateur TypeScript 7 natif et gardent TypeScript 6 pour les outils qui ont encore besoin de son API.
Communauté et aide
Section intitulée « Communauté et aide »- Questions et idées : GitHub Discussions.
- Bugs et propositions : les issues, à partir de leurs modèles.
- Sécurité : jamais dans une issue publique ; voir SECURITY.fr.md.
- Chaque participant suit le code de conduite.
Contribuer
Section intitulée « Contribuer »ddd-ts-kit se construit en public, et les contributions de toute taille sont les bienvenues : une coquille, une traduction, un test, un adaptateur ou une nouvelle règle. De bons points de départ :
- les issues étiquetées good first issue ou help wanted ;
- un adaptateur pour un broker, un ORM ou un framework HTTP que le kit ne prend pas encore en charge : il passe la suite de contrat de son port ;
- la documentation, en anglais ou en français, et l'application d'exemple ;
- un retour d'un vrai projet, dans les Discussions : ce qui a tenu, ce qui a gêné.
CONTRIBUTING.fr.md donne l'installation, les règles de base et le chemin
d'un changement jusqu'à main. Si ddd-ts-kit vous est utile, une étoile sur GitHub aide d'autres
personnes à le trouver.
MIT © Gary Bourgeat et les contributeurs.