Description
Le module apps/server-nestjs a développé, au fil des PRs (ex. #2317), un ensemble de conventions implicites mais cohérentes pour le nommage des fonctions, la structure des tests, les commentaires, et le moment où l'on extrait une sous-fonction. Ces règles ne sont pas documentées de façon centralisée : la structure de module est partiellement couverte par documentation/Modularisation-de-console-server/02-ARCHITECTURE-MODULES.md, mais le reste dépend de la lecture du code existant.
L'objectif est de créer une documentation des conventions versionnée dans le dépôt (sous forme de guide/conventions, chargeable comme skill par les agents travaillant sur server-nestjs), avec exemples réels et pièges, afin que les futures implémentations (et les contributions de l'équipe) les respectent sans avoir à les redécouvrir. Cette documentation doit vivre dans le dépôt, partagée et reviewable comme n'importe quel autre fichier, et non dans un espace personnel.
PRs liées
Issues liées
À compléter (référencer une éventuelle épopée de suivi server-nestjs si existante).
Exemples simples
Conventions observées dans le code actuel, à consigner dans la documentation :
Nommage des fonctions
make* → factory/fixture typée dans *-testing.utils.ts, signature makeX(overrides: Partial<X> = {}): X renvoyant un objet complet avec valeurs par défaut raisonnables (makeProject, makeUser, makeProjectRole, makeSonarqubeProject, makeToUrlParams).
get* → accesseur DB/lecture dans *-queries.utils.ts (reçoit un Prisma.TransactionClient + id) : getProject, getProjectSlug, getProjectContext, getProjectBySlug.
build* → transformateur pur / assemblage : buildUpdatedProjectRoles.
handle* → handler d'event/cron, wrapper fin typé : handleUpsert via @OnEvent (voir plugin.utils.ts + capturePluginResult).
new* → invocation de constructeur dans les useFactory / factories : new Gitlab(...).
Règles de sous-fonction (pattern de plugin.utils.ts)
- Extraire une sous-fonction privée quand elle a une forme naturelle propre et doit porter sa propre décorations/trace (ex.
syncProject privé avec @StartActiveSpan).
- Confiner une assertion de type dans une helper dédiée pour ne pas polluer le reste (ex.
keyedBy).
Structure de test
Commentaires
- Commentaires fonctionnels « pourquoi » (ex.
plugin.utils.ts documente la rationale de capturePluginResult et le confinement de l'assertion de type), pas de commentaires redondants avec le code.
Structure de module
- Déjà documentée dans
02-ARCHITECTURE-MODULES.md (slice vertical : module / constants / *-client.service / service / *-datastore.service / utils / *-testing.utils / *.spec.ts). La documentation des conventions doit la référencer, pas la dupliquer.
Spécifications techniques
- Créer dans le dépôt une documentation des conventions (fichier versionné et reviewable, ex.
apps/server-nestjs/documentation/server-nestjs-conventions.md, ou un skill SKILL.md committé dans le dépôt) contenant :
- Les règles de nommage ci-dessus, chaque cas illustré par un extrait réel du repo.
- Une section « quand extraire une sous-fonction » (taille, trace dédiée, confinement d'assertion de type, lisibilité).
- Une section « structure de test » (colocalisation,
mockDeep, factories make*, *.spec.ts par couche).
- Une section « commentaires » (pourquoi fonctionnel, pas de bruit).
- Une section « structure de module » renvoyant Ă
02-ARCHITECTURE-MODULES.md.
- Section « pièges » : erreurs fréquentes (cast
as any, new Date() non déterministe, body: null vs ContractNoBody, littéraux string de nom de plugin/clef de config au lieu de constantes PLUGIN_NAME/*_PLUGIN_KEY).
- La documentation doit être committée dans le dépôt (partagée, versionnée, reviewable), et référencée dans les PR de migration en cours.
Description de la solution possible
La solution se décompose en trois niveaux, du plus simple (documentation) au plus automatisé (règles ESLint sur-mesure) :
Niveau 1 — Documentation versionnée et chargeable (cœur de l'issue)
Créer dans le dépôt (ex. apps/server-nestjs/documentation/) un fichier de conventions consommable à la fois par un humain (revue de PR) et par un agent (skill Hermes chargeable, cf. skill hermes-agent). Format recommandé : un SKILL.md committé dans le dépôt, ou un .md référencé par un SKILL.md léger, afin que les sous-agents (delegate_task), Codex/Claude Code, et les futures migrations (#2323 PluginManager) le chargent comme mémoire procédurale versionnée. Le contenu reprend les sections de la « Spécifications techniques » ci-dessus, enrichies d'extraits réels et d'une section « pièges ».
Niveau 2 — Renforcement via la configuration ESLint existante
Le dépôt utilise déjà @antfu/eslint-config centralisé dans packages/eslintconfig. Ajouter des sélecteurs @typescript-eslint/naming-convention ciblant les préfixes du repo :
function / variableLike → camelCase (défaut) ;
- factory de test
make* → camelCase + prefix: ['make'] (le préfixe est retiré avant la validation du format) ;
- accesseur DB
get* → prefix: ['get'] ;
- handler event/cron
handle* → prefix: ['handle'] ;
class / typeLike / interface → PascalCase.
NB : @typescript-eslint/naming-convention est gelé fonctionnellement (plus de nouvelles options) et le mode avec infos de type a un coût de performance ; à activer avec discernement et à mesurer sur le CI.
Niveau 3 — Règles ESLint sur-mesure (ROI le plus élevé)
Les règles natives ne couvrent pas les invariants repo-spécifiques. Implémenter 2–3 règles custom (eslint.org/docs/latest/extend/custom-rules) dans packages/eslintconfig :
Angle workflow agentique
La documentation versionnée sert de « mémoire procédurale » chargeable par les agents ; les règles ESLint ci-dessus sont le professeur déterministe le moins coûteux pour le code généré par LLM (erreur machine-readable, corrigeable en boucle). Pour le déploiement mécanique des conventions (ex. application du nouveau nommage à tous les plugins lors de la dédup #2323), privilégier la délégation parallèle de sous-tâches (subagent-driven-development).
Compatibilité et précédents
- La famille de skills
nestjs-* (nestjs-build-fixing, nestjs-spec-fixing, nestjs-logging, nestjs-module-migration, nestjs-refactor-safety) est le foyer naturel de ce skill conventions.
- Croiser avec
writing-plans, test-driven-development, vitest-configuration, simplify-code.
- Outils complémentaires déjà présents :
tsc --noEmit (strict), secret scanning (gitleaks/aperture), et pour un spike futur les plugins de garde-fou IA (eslint-plugin-ai-guardrails, Factory-AI/eslint-plugin).
Définition du fini
Description
Le module
apps/server-nestjsa développé, au fil des PRs (ex. #2317), un ensemble de conventions implicites mais cohérentes pour le nommage des fonctions, la structure des tests, les commentaires, et le moment où l'on extrait une sous-fonction. Ces règles ne sont pas documentées de façon centralisée : la structure de module est partiellement couverte pardocumentation/Modularisation-de-console-server/02-ARCHITECTURE-MODULES.md, mais le reste dépend de la lecture du code existant.L'objectif est de créer une documentation des conventions versionnée dans le dépôt (sous forme de guide/conventions, chargeable comme skill par les agents travaillant sur
server-nestjs), avec exemples réels et pièges, afin que les futures implémentations (et les contributions de l'équipe) les respectent sans avoir à les redécouvrir. Cette documentation doit vivre dans le dépôt, partagée et reviewable comme n'importe quel autre fichier, et non dans un espace personnel.PRs liées
refactor(server-nestjs): cleanup constants, tests using mockDeep and datastore tighter select: généralisemockDeepet les factories faker (make*), référence de fait pour les conventions de test.PluginManager: la future abstraction des plugins devra respecter ces conventions de nommage/structure.Issues liées
À compléter (référencer une éventuelle épopée de suivi
server-nestjssi existante).Exemples simples
Conventions observées dans le code actuel, à consigner dans la documentation :
Nommage des fonctions
make*→ factory/fixture typée dans*-testing.utils.ts, signaturemakeX(overrides: Partial<X> = {}): Xrenvoyant un objet complet avec valeurs par défaut raisonnables (makeProject,makeUser,makeProjectRole,makeSonarqubeProject,makeToUrlParams).get*→ accesseur DB/lecture dans*-queries.utils.ts(reçoit unPrisma.TransactionClient+ id) :getProject,getProjectSlug,getProjectContext,getProjectBySlug.build*→ transformateur pur / assemblage :buildUpdatedProjectRoles.handle*→ handler d'event/cron, wrapper fin typé :handleUpsertvia@OnEvent(voirplugin.utils.ts+capturePluginResult).new*→ invocation de constructeur dans lesuseFactory/ factories :new Gitlab(...).Règles de sous-fonction (pattern de
plugin.utils.ts)syncProjectprivé avec@StartActiveSpan).keyedBy).Structure de test
*.spec.tscolocalisé à la source ;<module>.service.spec.tspour l'orchestration,-datastore.service.spec.tspour la forme Prisma ; factories centralisées dans*-testing.utils.ts; usage demockDeep(cf. refactor(server-nestjs): cleanup constants, tests using mockDeep and datastore tighter select #2317).Commentaires
plugin.utils.tsdocumente la rationale decapturePluginResultet le confinement de l'assertion de type), pas de commentaires redondants avec le code.Structure de module
02-ARCHITECTURE-MODULES.md(slice vertical :module/constants/*-client.service/service/*-datastore.service/utils/*-testing.utils/*.spec.ts). La documentation des conventions doit la référencer, pas la dupliquer.Spécifications techniques
apps/server-nestjs/documentation/server-nestjs-conventions.md, ou un skillSKILL.mdcommitté dans le dépôt) contenant :mockDeep, factoriesmake*,*.spec.tspar couche).02-ARCHITECTURE-MODULES.md.as any,new Date()non déterministe,body: nullvsContractNoBody, littéraux string de nom de plugin/clef de config au lieu de constantesPLUGIN_NAME/*_PLUGIN_KEY).Description de la solution possible
La solution se décompose en trois niveaux, du plus simple (documentation) au plus automatisé (règles ESLint sur-mesure) :
Niveau 1 — Documentation versionnée et chargeable (cœur de l'issue)
Créer dans le dépôt (ex.
apps/server-nestjs/documentation/) un fichier de conventions consommable à la fois par un humain (revue de PR) et par un agent (skill Hermes chargeable, cf. skillhermes-agent). Format recommandé : unSKILL.mdcommitté dans le dépôt, ou un.mdréférencé par unSKILL.mdléger, afin que les sous-agents (delegate_task), Codex/Claude Code, et les futures migrations (#2323PluginManager) le chargent comme mémoire procédurale versionnée. Le contenu reprend les sections de la « Spécifications techniques » ci-dessus, enrichies d'extraits réels et d'une section « pièges ».Niveau 2 — Renforcement via la configuration ESLint existante
Le dĂ©pĂ´t utilise dĂ©jĂ
@antfu/eslint-configcentralisé danspackages/eslintconfig. Ajouter des sélecteurs@typescript-eslint/naming-conventionciblant les préfixes du repo :function/variableLike→camelCase(défaut) ;make*→camelCase+prefix: ['make'](le préfixe est retiré avant la validation du format) ;get*→prefix: ['get'];handle*→prefix: ['handle'];class/typeLike/interface→PascalCase.NB :
@typescript-eslint/naming-conventionest gelé fonctionnellement (plus de nouvelles options) et le mode avec infos de type a un coût de performance ; à activer avec discernement et à mesurer sur le CI.Niveau 3 — Règles ESLint sur-mesure (ROI le plus élevé)
Les règles natives ne couvrent pas les invariants repo-spécifiques. Implémenter 2–3 règles custom (
eslint.org/docs/latest/extend/custom-rules) danspackages/eslintconfig:as anydansserver-nestjs(force le typage strict ou un cast localisé + justification) ;new Date()interdit dans*.spec.ts→ exigerfaker.date.*pour des tests déterministes ;body: nullinterdit → exigerContractNoBody(cf. pièges refactor(server-nestjs): cleanup constants, tests using mockDeep and datastore tighter select #2317) ;get*doit recevoir unPrisma.TransactionClientcomme premier paramètre (vérification AST sur*-queries.utils.ts).Angle workflow agentique
La documentation versionnée sert de « mémoire procédurale » chargeable par les agents ; les règles ESLint ci-dessus sont le professeur déterministe le moins coûteux pour le code généré par LLM (erreur machine-readable, corrigeable en boucle). Pour le déploiement mécanique des conventions (ex. application du nouveau nommage à tous les plugins lors de la dédup
#2323), privilégier la délégation parallèle de sous-tâches (subagent-driven-development).Compatibilité et précédents
nestjs-*(nestjs-build-fixing,nestjs-spec-fixing,nestjs-logging,nestjs-module-migration,nestjs-refactor-safety) est le foyer naturel de ce skill conventions.writing-plans,test-driven-development,vitest-configuration,simplify-code.tsc --noEmit(strict), secret scanning (gitleaks/aperture), et pour un spike futur les plugins de garde-fou IA (eslint-plugin-ai-guardrails,Factory-AI/eslint-plugin).Définition du fini
make*/get*/build*/handle*/new*) avec exemples réels.*.spec.tscolocalisés,mockDeep, factories).02-ARCHITECTURE-MODULES.md) et liste les pièges fréquents.