volontariapp-scaffold-microservice
Playbook opérationnel pas-à-pas pour créer et raccorder un nouveau domaine/microservice de bout en bout (proto, domain package, ms-*, outbox, worker, post-processor, gateway, deploy, ci-tools).
- License 许可
- MIT
- 最近更新
- 2026-11-10
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- volontariapp-scaffold-microservice
- tags
- [ "scaffolding", "microservice", "grpc", "nestjs", "ddd", "runners", "playbook" ]
- type
- Playbook
- paths
- [ "proto-registry/proto/**", "npm-packages/packages/**", "ms-*/src/**", "outbox-runners/**", "workers-runners/**", "post-processors-runner/**", "api-gateway/src/**", "deploy/**", "ci-tools/**" ]
- title
- Scaffolding d'un Nouveau Microservice gRPC et de ses Runners
- status
- stable
- sources
- [ { "id": "doc-creation", "kind": "local_file", "title": "Inventaire exhaustif de création de microservice", "resource": "docs/matching/07-creation-du-microservice.md" }, { "id": "agent-md", "kind": "local_file", "title": "AGENT.md (structure de microservice et règles d'or)", "resource": "AGENT.md" }, { "id": "outbox-script", "kind": "local_file", "title": "create-outbox.sh", "resource": "outbox-runners/scripts/create-outbox.sh" }, { "id": "compose", "kind": "local_file", "title": "ci-tools/docker-compose.yml", "resource": "ci-tools/docker-compose.yml" }, { "id": "sync-mig", "kind": "local_file", "title": "sync-migrations.mjs", "resource": "scripts/cli/commands/sync-migrations.mjs" } ]
- verified
- [ { "at": "2026-11-08T11:15:21Z", "by": "claude-code/agent", "digest": "1d3425728779bb78" }, { "at": "2026-11-08T11:53:21Z", "by": "claude-code/agent", "digest": "3c8471681c92d4c8" }, { "at": "2026-11-08T12:03:29Z", "by": "claude-code/agent", "digest": "827e2dcf344dda7d" }, { "at": "2026-11-08T12:07:08Z", "by": "claude-code/agent", "digest": "140fee1bc59cbf4d" }, { "at": "2026-11-08T12:18:56Z", "by": "claude-code/agent", "digest": "d9c18f95209c0701" }, { "at": "2026-11-08T12:28:00Z", "by": "claude-code/agent", "digest": "9c6245202a161167" } ]
- generated
- { "at": "2026-10-12T12:18:00Z", "by": "claude-code/agent" }
- mesh_keys
- [ "scaffold-microservice", "new-microservice", "create-service" ]
- description
- Playbook opérationnel pas-à-pas pour créer et raccorder un nouveau domaine/microservice de bout en bout (proto, domain package, ms-*, outbox, worker, post-processor, gateway, deploy, ci-tools).
02 资源文件 3
- 参考文档index.md631 B
- 参考文档log.md25.3 KB
- 参考文档references/lessons.md1.8 KB
03 SKILL.md 正文
Scaffolding d'un Nouveau Microservice gRPC et de ses Runners
Quand utiliser ce playbook
Utiliser ce playbook lorsqu'un nouveau bounded context métier nécessite la création d'un microservice dédié et de son écosystème satellite complet :
- Nouveau domaine métier isolé (ex.
ms-affinity,ms-billing, etc.). - Écosystème asynchrone associé : runner Outbox, worker BullMQ, post-processors Redis Streams.
- Raccordement Edge : exposition des routes REST dans
api-gateway. - Déploiement et infrastructure : base PostgreSQL dédiée, manifests Kubernetes K3s/ArgoCD, NetworkPolicies, et configuration locale
docker-compose.
Règles d'or d'architecture
- Respect absolu des deux STOPs bloquants :
- Premier STOP :
proto-registry(attente PR automatique dansnpm-packagesgénérée par la CI). - Second STOP :
npm-packages(attente release NPM publiée par la CI). - INTERDICTION FORMELLE d'implémenter les microservices ou passerelles consommateurs en avance avec du casting fictif (
as unknown as Typeouany).
- Premier STOP :
- Clean Architecture & DDD strict :
- Le microservice
ms-*est une coquille d'infrastructure mince. Toute la logique métier réside dans@volontariapp/domain-<nom>^agent-md.
- Le microservice
- Isolation des données :
- Chaque microservice dispose de sa base PostgreSQL dédiée. Aucune requête SQL inter-bases n'est permise.
- Sécurité et moindre privilège dès le premier commit :
- Manifests Kubernetes durcis PSA Restricted, NetworkPolicies default-deny, secrets scellés asymétriquement via
kubeseal(aucun secret en clair dans Git).
- Manifests Kubernetes durcis PSA Restricted, NetworkPolicies default-deny, secrets scellés asymétriquement via
Procédure pas-à-pas
Étape 1 : Contrats Protobuf dans proto-registry (🛑 PREMIER STOP)
Dans le dépôt proto-registry^doc-creation :
- Créer le dossier
proto/volontariapp/<domaine>/avec les 5 fichiers conventionnels :<domaine>.proto: Modèles d'entités du domaine.<domaine>.command.proto: Messages des commandes RPC d'écriture.<domaine>.query.proto: Messages des requêtes RPC de lecture.<domaine>.responses.proto: Messages de réponse RPC.<domaine>.services.proto: Définition des services gRPC (<Domaine>CommandServiceet<Domaine>QueryService).
- Vérifier la conformité du contrat :
cd proto-registry buf lint buf breaking --against '.git#branch=main' - 🛑 STOP IMMÉDIAT : Ouvrir la Pull Request sur
proto-registry. Attendre le merge surmain. La CI déclenche la génération automatique de la PR dansnpm-packages(contractsetcontracts-nest).
Étape 2 : Domaine et Messagerie dans npm-packages (🛑 SECOND STOP)
Une fois la PR Protobuf générée dans npm-packages^doc-creation :
- Création du package de domaine
packages/domain-<domaine>/(prendre modèle surdomain-social) :- Entités du domaine (
*Entity), modèles TypeORM, interfaces de repository. - Services de logique métier pure.
- Migrations de test sous
src/test/migrations/{common,domain}/.
- Entités du domaine (
- Définition des flux asynchrones dans
packages/messaging/:- Déclarer les payloads et queues sous
src/jobs/<domaine>/. - Enregistrer les types dans
JobRegistryetJobMessagingType. - Déclarer les noms de streams dans
packages/shared/src/enums/streams.enum.ts. - Configurer le mapping WebSocket dans
packages/messaging/src/websockets/events/mapping.ts(JOB_TO_EVENT_MAPPINGetEVENT_EVENT_TO_WS_EVENT_MAPPING).
- Déclarer les payloads et queues sous
- Validation et Versionnage :
yarn build && yarn test yarn changeset add yarn changeset version - 🛑 STOP IMMÉDIAT : Passer la main au Lead Dev pour pousser sur PR et attendre la publication NPM par la CI (
@volontariapp/domain-<domaine>,@volontariapp/messaging, etc.).
Étape 3 : Scaffolding du microservice ms-<domaine>
- Créer le dépôt
ms-<domaine>(prendre modèle surms-socialoums-user)^doc-creation :- Initialiser les dépendances via
yarn upsur les nouveaux paquets publiés. - Copier
ci-tools/templates/dependabot/service.ymldans.github/dependabot.yml(retirer le blocdockersans Dockerfile). Le jobsecurity(Trivy) est déjà fourni parservice-ci.yml, rien à ajouter dans leci.yml. Ajouter en dernier job duci.ymlunnotify-ready(needs:tous les autres jobs,if: ${{ !failure() && !cancelled() && github.event_name == 'pull_request' }},permissionsissues: writeetpull-requests: write,uses: Volontariapp/ci-tools/.github/workflows/pr-ready-notify.yml@main,with: channel: backend,secrets: inherit) : détail dansvolontariapp-ci-tools.
- Initialiser les dépendances via
- Bootstrap et Observabilité :
src/main.ts: Démarrage hybride (serveur gRPC sur port 3000 + serveur HTTP Express pour la sonde/health).src/tracing.ts: Initialisation du SDK OpenTelemetry (Datadog OTLP) avant l'instanciation de NestJS.src/app.module.ts: Enregistrement deAppConfigModule,DatabaseModule,HealthModule,GrpcValidationPipeetGrpcInternalGuardglobal^agent-md.
- Configuration & Data Source TypeORM :
src/config/data-source.ts: Déclaration deAppDataSourceréférençant les entités du domaine et le glob des migrations.src/migrations/common/: Récupérer les migrations partagées viayarn meta sync-migrations^sync-mig.src/migrations/domain/: Déposer la migration initiale de schéma métier.
- Contrôleurs CQRS :
- Contrôleurs séparés pour les commandes (
BaseCommandControlleravecwithFallback) et les requêtes de lecture. - Mappers stricts sans conversion magique.
- Pagination : copier
src/common/dto/pagination.dto.tsdems-useroums-social(PaginationRequestDTOvalidé,MAX_PAGINATION_LIMIT) et l'utiliser dans toute requête de liste avec@ValidateNested() @Type(...); défaut page 1 / limit 10 dans le contrôleur. Voir l'étape 2 de la skillvolontariapp-grpc-microservice.
- Contrôleurs séparés pour les commandes (
- Matrice de tests e2e :
- Créer
e2e-matrix.jsondansms-<domaine>et ajouter le nouveau service aux fichierse2e-matrix.jsondes services communicants et de l'API Gateway.
- Créer
Étape 4 : Démon Outbox (outbox-runners/)
- Utiliser le script de génération officiel^outbox-script :
cd outbox-runners ./scripts/create-outbox.sh # Indiquer le nom du domaine (ex. 'affinity') - Le script génère
outbox-<domaine>/surveillant les tablesjobs_outboxetevent_queuede la base du microservice. - Vérifier les targets Redis Streams et BullMQ dans la configuration.
- Rien à ajouter côté CI pour un nouveau domaine : le
ci.ymldeoutbox-runners,workers-runnersetpost-processors-runnerporte déjà un jobnotify-ready(needs: [ci],ciétant l'appel unique àrunner-pipeline.yml). Cesci.ymllistent leurs secrets au lieu desecrets: inherit:DISCORD_WEBHOOK_BACKEND,DISCORD_WEBHOOK_FRONTENDetORG_REPO_TOKENy sont passés un par un.
Étape 5 : Flotte de Workers BullMQ (workers-runners/)
- Créer le répertoire
workers-runners/worker-<domaine>/(prendre modèle surworker-social)^doc-creation. - Implémenter deux classes étanches dérivées de
BaseWorker:<domaine>.worker.tspour la file nominale.fallback-<domaine>.worker.tspour la file de fallback dégradée.
- Développer les handlers de jobs implémentant l'interface
IJobHandler. - Injecter les certificats/clés de signature interne sous
certs/pour permettre au worker d'appeler d'autres microservices via gRPC en tant que système.
Étape 6 : Consommateurs Post-Processors (post-processors-runner/)
- Créer
post-processors-runner/post-processor-<domaine>/(modèlepost-processor-social)^doc-creation. - Déclarer les post-processors métier avec groupes de consommateurs dédiés (
options/*.options.ts). - Composants critiques obligatoires :
- Enregistrer impérativement
JobOutboxSuccessPostProcessoretJobOutboxFailedPostProcessordanspost-processors.module.ts. Sans eux, les lignesjobs_outboxne sont jamais purgées et les notifications WebSocket ne sont jamais diffusées.
- Enregistrer impérativement
Étape 7 : Raccordement API Gateway Edge (api-gateway/)
Dans le dépôt api-gateway :
- Créer le module
src/modules/<domaine>/. - Implémenter le contrôleur REST
@GatewayController('<domaine>'):- DTO Swagger complets avec décorateurs
class-validator, quiimplementsles types<X>Requestde@volontariapp/contracts(npm-packages/packages/contracts/src/gateway/<domaine>/{request,response}, partagés avec nativapp). Les créer d'abord dans npm-packages (règle du STOP) s'ils n'existent pas. - Propagation de la métadonnée interne d'autorisation :
req['internalMetadata']. - Gestion des codes de retour (HTTP 200 standard, HTTP 206
FALLBACK_ACTIVATEDen cas de mode dégradé).
- DTO Swagger complets avec décorateurs
- Déclarer le client gRPC et le token d'injection correspondant dans
src/grpc/.
Étape 8 : Déploiement GitOps Kubernetes (deploy/)
Dans le dépôt deploy :
- Manifests de base sous
deploy/apps/base/ms-<domaine>/:deployment.yaml(microservice principal).deployment-outbox.yaml(démon outbox connecté auredis-master).deployment-worker.yaml(worker BullMQ).deployment-post-processor.yaml(consommateurs Redis Streams).service.yaml(exposition gRPC port 3000).kustomization.yaml(durcissement PSA Restricted :readOnlyRootFilesystem: true,runAsNonRoot: true,drop: [ALL]).
- Base de données PostgreSQL :
- Déclarer l'instance sous
deploy/infrastructure/databases/ms-<domaine>/.
- Déclarer l'instance sous
- Secrets scellés :
- Sceller les identifiants de base et les clés privées via
kubeseal(playbookvolontariapp-sealed-secrets).
- Sceller les identifiants de base et les clés privées via
- NetworkPolicies (Default-Deny) :
- Autoriser l'ingress depuis
api-gatewaysur le port 3000. - Autoriser l'egress des pods uniquement vers PostgreSQL et Redis.
- Bloquer tout le reste par défaut.
- Autoriser l'ingress depuis
- Application ArgoCD :
- Déclarer l'application sous
deploy/infrastructure/argocd/.
- Déclarer l'application sous
Étape 9 : Outillage Local & Synchronisation CI (ci-tools/)
- Docker Compose Local :
- Ajouter l'instance PostgreSQL (
postgres-<domaine>) sur un port dédié (ex. 5437 pour storage, 5438 pour ranking) dansci-tools/docker-compose.yml^compose. Le servicems-<domaine>-migrationne s'ajoute qu'une fois l'image GHCR publiée (l'E2E tire toutes les images du profilmigrations). - Déclarer le conteneur de migration
<domaine>-migration.
- Ajouter l'instance PostgreSQL (
- Script de synchronisation :
- Déclarer le nouveau microservice dans
repos.json(reposetunits, avecmigrations: true,certs: true) : les commandessync-migrations,migrate,certs,startle lisent^sync-mig.
- Déclarer le nouveau microservice dans
- Gouvernance et Hooks :
- Référencer le service dans [AGENT.md](file:///Users/victoragahi/Developer/meta/AGENT.md) et [AGENTS.md](file:///Users/victoragahi/Developer/meta/AGENTS.md).
- Déclarer le nouveau chemin dans [.agents/mesh-mcp.toml](file:///Users/victoragahi/Developer/meta/.agents/mesh-mcp.toml).
- Exécuter
./scripts/install-skill-hooks.shpour armer les hooks pre-commit sur le nouveau dépôt.
Étape 10 : Intégration Client Mobile (nativapp/)
Dans nativapp :
- Développer le hook TanStack Query
use<Domaine>(discrimination du codeFALLBACK_ACTIVATEDen cas de 206). - Brancher le listener WebSocket dans
src/hooks/useNotificationHandlers.tspour invalider le cache dès réception de la notification de complétion du job.
Checklist de validation finale
- [ ] Les 5 fichiers
.protosont créés et validés parbuf lintetbuf breaking(Premier STOP validé). - [ ] Le package
@volontariapp/domain-<domaine>et les contrats de messagerie sont publiés sur NPM (Second STOP validé). - [ ] Le microservice
ms-<domaine>démarre en mode hybride (gRPC 3000 +/health) et applique ses migrations sans erreur. - [ ] L'Outbox runner est généré via
create-outbox.sh^outbox-script et connecté à Redis. - [ ] Les workers implémentent les deux files (nominale et fallback dégradé).
- [ ]
JobOutboxSuccessPostProcessoretJobOutboxFailedPostProcessorsont déclarés dans le post-processor^doc-creation. - [ ] L'API Gateway expose la route avec
@GatewayControlleret propagereq['internalMetadata']. - [ ] Les manifests K8s respectent PSA Restricted et les NetworkPolicies bloquent tout trafic non explicitement autorisé.
- [ ] La base locale est déclarée dans
ci-tools/docker-compose.yml^compose et déclarée dansrepos.json(yarn meta manifestvalide la cohérence avec.gitignore)^sync-mig. - [ ] Les hooks pre-commit sont installés via
./scripts/install-skill-hooks.sh.
Références
04 同仓库更多 Skills
volontariapp-user-account-deletion
Suppression de compte en deux temps (PENDING_DELETION): requestDeletionWithUserDeleted, finalizeDeletion, fan-out de user.deleted vers les domaines et gather ws. A utiliser pour tout changement de domain-user touchant la suppression, le statut ou le cycle de vie d'un user.
volontariapp-proto-contract-evolution
Modifier un contrat Protobuf de proto-registry (champ, message, enum, RPC) sans casser la compatibilité wire, puis suivre la cascade proto-registry, PR automatique dans npm-packages, publication, consommateurs. À utiliser avant toute édition d'un .proto.
volontariapp-meta-scripts
Utiliser et faire evoluer la CLI Node de meta (setup, doctor, migrate, certs, repos, bump) et le manifeste repos.json, source unique des repos et unites du workspace.
volontariapp-implement-async-event-flow
Guide pas-à-pas pour concevoir et implémenter un flux asynchrone complet (messaging -> outbox -> post-processors -> ws-service -> client).
research
Investigate a question against high-trust primary sources and capture the findings as a Markdown file in the repo. Use when the user wants a topic researched, docs or API facts gathered, or reading legwork delegated to a background agent.
prototype
Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.