Aller au contenu principal
Tous les articles
8 min de lecture

Cadrer Claude Code avec CLAUDE.md sur un SaaS multi-tenant

Les vraies règles qui gouvernent ce SaaS avec Claude Code : ce qui va dans CLAUDE.md, ce qui n'y va pas, et ce qui est réellement livré à l'achat.

Le problème : du code plausible, pas conforme

Sans instructions, un assistant IA écrit du code qui compile et qui a l'air correct. Sur un SaaS multi-tenant, « avoir l'air correct » ne suffit pas : un findUnique({ where: { id } }) sur une ressource scopée par organisation compile très bien et laisse fuir les données d'un client vers un autre. Le modèle ne peut pas deviner tout seul que ce projet précis exige findFirst({ where: { id, organizationId } }).

CLAUDE.md et les fichiers sous .claude/ existent pour combler cet écart. Pas un prompt magique qu'on colle une fois, un ensemble de règles versionnées dans le dépôt, lues à chaque session, qui rendent explicite ce qu'un développeur senior du projet sait sans y penser.

Un deuxième exemple, moins évident que l'IDOR, tiré aussi de ce dépôt : NextAuth v5 a renommé ses cookies de session de __Secure-next-auth.* vers __Secure-authjs.*. Un getToken({ req }) sans préciser cookieName et secret compile, ne renvoie aucune erreur, et retourne silencieusement null en production, un utilisateur qui semble déconnecté sans qu'aucune exception ne remonte nulle part. Rien dans la signature de la fonction n'indique le piège. La seule façon de ne pas le retrouver à chaque nouvelle session de travail, c'est de l'écrire une fois dans une règle.

CLAUDE.md : ce qu'on y met, ce qu'on n'y met pas

Le fichier CLAUDE.md de ce dépôt commence par la structure du projet (les deux couches du produit, pour éviter qu'une IA ne mélange le code de vente et le code du SaaS livré), puis les commandes (pnpm dev, pnpm typecheck...), l'architecture (alias ~/, où vit le client Prisma généré), et une liste explicite d'interdictions : ne pas modifier tel module certifié, ne pas utiliser npm, ne pas ajouter any sans justification.

Ce qu'on y met : des faits vérifiables sur ce projet, qu'un modèle ne peut pas deviner depuis le code seul. Le choix findFirst plutôt que findUnique en fait partie : les deux compilent, seul un humain qui connaît l'historique du projet sait lequel est correct ici.

Ce qu'on n'y met pas : la doc générique de la stack (Next.js, Prisma, ça se trouve ailleurs). Une limite plus fine : certaines instructions n'ont de sens que pour notre organisation, pas pour le code lui-même. Ce dépôt tourne avec plusieurs sessions Claude Code en parallèle sur le même arbre de travail, donc CLAUDE.md contient un protocole de démarrage précis (comment trier les fichiers non commités d'une autre session, ne jamais faire git add -A, vérifier git reflog avant de toucher un fichier modifié il y a moins de cinq minutes). Utile ici, sans objet pour un acheteur qui travaille seul sur son propre dépôt. Ces process-là restent dans CLAUDE.md de ce dépôt, mais ne partent pas avec le produit livré : un acheteur reprend le code, pas notre organisation interne. Le fichier lui-même n'est d'ailleurs pas exporté (voir plus bas).

Les règles par domaine

Au-delà du fichier racine, .claude/rules/ porte une règle par domaine : sécurité, Prisma, tests, git, design, frontend. Séparées plutôt qu'entassées dans un seul fichier, pour que la règle sécurité reste courte et qu'on la retrouve sans scroller.

Exemple concret, tiré de security.md de ce dépôt :

## Isolation multi-tenant
 
- Tout `db.model.update()` et `db.model.delete()` DOIT avoir
  `organizationId` dans le `where`
- Pattern obligatoire : `findFirst({ where: { id, organizationId } })`,
  jamais `findUnique({ where: { id } })`
- IDOR → NOT_FOUND (pas FORBIDDEN), pour ne pas confirmer qu'une
  ressource existe dans une autre organisation

Ce ne sont pas des principes généraux, ce sont des décisions déjà prises pour ce projet, avec la raison écrite à côté. Un modèle qui lit cette règle avant d'écrire un update sait exactement quel where produire, sans qu'on ait à le redemander à chaque session.

prisma.md fait la même chose pour les migrations (ne jamais éditer prisma/migrations/ à la main, toujours organizationId sur un nouveau modèle multi-tenant), testing.md pour les tests (mocker Prisma, jamais de vraie base en test unitaire), git.md pour les commits (format, langue, ce qu'on ne commite jamais).

Le format qui rend une règle utile

Une règle générique du type « écris du code sécurisé » ne change rien : un modèle ne sait pas la traduire en décision concrète sur ce projet. Ce qui fonctionne a trois propriétés, visibles dans l'exemple security.md ci-dessus :

  • Courte et testable : « findFirst avec organizationId, jamais findUnique » se vérifie en une lecture de code, contrairement à « fais attention à l'isolation des données »
  • La raison à côté de l'instruction : « pour ne pas confirmer qu'une ressource existe dans une autre organisation » explique le pourquoi, donc la règle s'applique aussi à un cas qu'elle ne couvre pas mot pour mot
  • Un exemple de code, pas une phrase abstraite : montrer le where correct au lieu de décrire ce qu'il doit contenir enlève toute ambiguïté d'interprétation

Une règle qui échoue à l'un des trois se contourne ou s'oublie. C'est le même standard qu'une bonne norme d'équipe humaine : si personne ne peut dire en une phrase pourquoi elle existe, elle finit ignorée.

Les skills : un workflow, pas un prompt

Une règle dit ce qu'il ne faut pas faire. Une skill fait la tâche, dans l'ordre, avec les vérifications intégrées. feature-factory, une des skills de ce dépôt, illustre la différence : demandée pour un nouveau module métier, elle commence par une interview (nom, champs, rôles, quota freemium éventuel), présente un plan de scaffolding complet avant d'écrire une ligne de code, puis génère couche par couche : modèle Prisma, entrée dans ORG_SCOPED_MODELS, permissions RBAC, router tRPC, page dashboard, tests.

Un prompt copié-collé une fois ne fait rien de tout ça : il donne une intention, pas un ordre d'opérations ni les vérifications entre chaque étape. La skill encode la procédure elle-même, donc elle produit le même résultat qu'on la déclenche aujourd'hui ou dans six mois, avec un autre modèle.

Ce dépôt en compte neuf. feature-factory scaffolde une fonctionnalité de bout en bout. tenant-security-audit audite l'isolation multi-tenant avec des corrections automatiques, plutôt que de se contenter de lister les problèmes. prisma-migration sécurise le workflow de migration (l'ordre exact prisma generate puis prisma migrate dev, la gestion du verrou Windows sur le moteur de requête). safe-refactor gère un renommage qui traverse plusieurs couches, un champ renommé dans le schéma qui doit aussi changer dans le router, les permissions et les tests, sans qu'aucune des quatre couches ne soit oubliée en route. pre-deploy-checklist tourne avant un merge vers main. heartco-debugger diagnostique une erreur tRPC, un scoping Prisma cassé ou un 401/403 inattendu. prisma-performance détecte les N+1 et les requêtes non paginées. docs-generator rédige les pages de documentation utilisateur. La neuvième, interne à la revente du boilerplate, ne concerne pas un acheteur.

Une session réelle : ajouter un module

Concrètement, demander « ajoute un module de suivi des véhicules » déclenche feature-factory, qui répond par un plan avant de toucher au code :

Feature : vehicules (Suivi des véhicules)

Fichiers à créer/modifier :
 1. prisma/schema.prisma                    → Modèle Vehicule
 2. lib/prisma-org-scope.ts                 → Ajout à ORG_SCOPED_MODELS
 3. lib/permissions/matrix.ts               → Permissions vehicules:read/create/edit/delete
 4. server/api/routers/vehicules.ts         → Router CRUD
 5. server/api/root.ts                      → Enregistrer le router
 6. app/dashboard/vehicules/page.tsx        → Page dashboard
 7. server/api/routers/__tests__/vehicules.test.ts → Tests

Le plan attend une validation avant de continuer. C'est la partie qui change tout par rapport à un prompt générique : l'IA ne devine pas la liste de fichiers à toucher pour ajouter un module sur cette architecture précise, elle l'a écrite noir sur blanc, elle sait déjà qu'un nouveau modèle scopé doit entrer dans ORG_SCOPED_MODELS, un fait que seule la règle Prisma de ce dépôt rend explicite.

Limites : ce que l'IA ne remplace pas

Un fichier de règles réduit le taux d'erreur, il ne l'annule pas. Ce qu'il ne fait pas : deviner une décision produit que personne n'a écrite quelque part (quelle limite freemium a du sens pour votre marché), remplacer une revue de code humaine sur un changement de permissions RBAC, ou détecter un problème qui ne suit aucun des patterns déjà documentés dans les règles. Une skill d'audit trouve les IDOR qu'elle a été écrite pour chercher, pas ceux auxquels personne n'a encore pensé.

La discipline reste la même qu'avec un développeur junior à qui on donnerait ces mêmes règles : elles réduisent les erreurs connues, elles ne dispensent pas de relire ce qui touche à la sécurité ou à la facturation.

Ce que vous recevez dans HeartCo

Un point à corriger avant de citer un chiffre : CLAUDE.md et .claude/rules/ ne sont pas exportés avec le boilerplate. Ce sont les règles internes de ce dépôt de développement, pas un produit générique à copier tel quel dans un projet qui n'a ni les mêmes plans freemium ni la même structure en deux couches. Ce qui part réellement avec le code : 8 des 9 skills (audit-ai-signals, qui concerne la revente du boilerplate lui-même, reste interne), et 6 commandes de scaffolding (new-model, new-module, new-page, new-router, ship, fix-build) sur l'ensemble plus large utilisé en interne.

Vous repartez avec les outils, pas avec nos règles métier. Écrire votre propre CLAUDE.md prend une heure une fois qu'on a vu la structure ; le guide /docs/vibe-coding-guide embarqué liste 17 prompts prêts à coller, calqués sur les fichiers réels de ce dépôt, pour démarrer sans repartir d'une page blanche.

Pour aller plus loin

Partager

Prêt à lancer ton SaaS ?

HeartCo Starter inclut tout ce dont tu as besoin : auth, paiements, IA, mobile, sécurité auditée. À partir de 199 €.

Satisfait ou remboursé 30 jours