Aller au contenu
Garder la main
Sommaire
10Chapitre 10·Variable (hands-on)·Tous niveaux

Labs pratiques

Sur ton projet, pas sur un exemple

Équiper un codebase existant, puis appliquer Explore → Plan → Code → Verify sur NestJS, Next.js, Laravel, FastAPI, la CI et un incident de prod.

Ce que tu sauras faire
  • 01Équiper un vrai codebase en contexte et en tests avant tout le reste
  • 02Appliquer le cycle Explore → Plan → Code → Verify sur des cas réels
  • 03Valider un plan une fois, puis dérouler par blocs en relisant le diff
  • 04Couvrir NestJS, Next.js, Laravel, CI/CD, FastAPI et l'incident en prod

Lab 1 — Équiper un codebase existant

Durée : 45-60 min · Niveau : tous · Prérequis : un vrai projet, si possible un que tu connais mal · Livrable : un fichier de contexte qui tient, un filet de tests sur une zone, et une session mesurée

C'est le lab à faire en premier, et de préférence sur ton projet le moins reluisant. Les six autres partent d'un environnement propre ; celui-ci construit l'environnement. Il applique le Module 4 (archéologie et filet) et le Module 5 (contexte), et tout le reste devient plus facile ensuite.

Étape 1 — Une session entièrement en lecture

Aucune écriture pendant toute cette étape. On ferme la porte plutôt que de compter sur sa bonne volonté — chez Claude Code, le plan mode ; ailleurs, l'équivalent de ton outil, ou une branche jetable (Module 4 §2) :

claude --permission-mode plan
Prompt
Tu découvres ce projet. Je le connais mal moi aussi, donc ne compte pas sur moi pour rattraper tes erreurs : dis-moi ce dont tu n'es pas sûr. Livre-moi, sans écrire un seul fichier : 1. À quoi sert ce projet, en trois lignes, déduites du code et non du README. 2. Comment on le lance, on le teste, on le construit. Cite le fichier qui te le prouve (package.json, Makefile, CI, composer.json...). 3. Les cinq répertoires où se passe l'essentiel du travail, et ce que fait chacun. 4. L'état réel des tests : y en a-t-il, tournent-ils, que couvrent-ils ? 5. Ce que tu n'as pas compris.

Le point 5 est celui qu'on lit en premier. Le point 2 est celui qui va directement dans le fichier de contexte : ce sont les commandes qu'aucun agent ne peut deviner.

Étape 2 — Extraire les conventions plutôt que les inventer

Prompt
Lis @[3 ou 4 fichiers de couches différentes : une route, un service, un test]. Déduis les conventions réellement appliquées : nommage, structure, gestion des erreurs, accès aux données, style de tests. Pour chacune : sa formulation en une ligne, sur combien de fichiers de l'échantillon elle tient, et si elle est systématique ou ponctuelle. Ne me dis pas ce qui serait une bonne pratique. Dis-moi ce que ce code fait.

Puis c'est ton tour, et cette partie ne se délègue pas. Tu tries en trois catégories : ce qu'on impose, ce qu'on tolère sans l'étendre, ce qu'on interdit désormais. La deuxième catégorie est celle qui empêchera l'agent de « nettoyer » l'ancien code à chaque passage (Module 4 §5).

Étape 3 — Écrire le fichier, et vérifier qu'il est chargé

Écris ton AGENTS.md (le Starter Pack donne le squelette), puis le CLAUDE.md d'une ligne qui l'importe :

@AGENTS.md

Et surtout, vérifie. C'est l'étape que tout le monde saute et c'est celle qui échoue en silence :

/context

Ton fichier doit apparaître sous Memory files. S'il n'y est pas, tout ce que tu viens d'écrire ne sert à rien, et aucun message d'erreur ne te le dira. Sur un autre outil, cherche son équivalent : ce qui compte est d'avoir une preuve que le fichier est chargé, jamais une supposition.

Étape 4 — Poser un filet sur une zone, une seule

Choisis la fonction que tu vas devoir modifier bientôt, celle qui te fait peur. Pas le module entier.

Prompt
Objectif : figer le comportement actuel de @[fonction], pas l'améliorer. Écris des tests [ton runner] qui capturent ce que le code fait aujourd'hui : cas nominal, chaque branche conditionnelle, valeurs limites, comportement en cas d'échec. IMPORTANT: si un comportement te semble être un bug, encode-le tel quel avec un commentaire `// comportement actuel, à discuter`. Ne le corrige pas.

Puis casse le code exprès. Change un > en >=, relance la suite. Si tout reste vert, tes tests n'observent rien : reprends-les. Ce contrôle prend deux minutes et c'est lui qui décide si le filet en est un.

Étape 5 — Mesurer ce que ça coûte

/context    → combien ton contexte permanent occupe réellement
/usage      → ce que la session a consommé

Ton contexte permanent doit rester sous 5 % de la fenêtre (Module 5 §9). Au-delà, tu n'élagues pas des règles utiles : tu sors les règles spécialisées vers .claude/rules/ avec un champ paths.

Ce que tu dois avoir à la fin

Checklist0 / 6

Lab 2 — NestJS : API REST avec Auth JWT

Durée : 45-60 min · Niveau : intermédiaire · Prérequis : NestJS installé, Module 3 lu · Livrable : module auth avec tests E2E

Setup du contexte

<!-- CLAUDE.md pour ce lab -->
# Lab NestJS Auth

## Stack
- NestJS 10, TypeScript 5.x, TypeORM + PostgreSQL 15
- @nestjs/jwt + Passport, class-validator
- Tests : Jest + Supertest

## Conventions
- Architecture : Module / Controller / Service / Repository
- DTOs typés (jamais d'entité retournée directement)
- Erreurs : HttpException avec messages clairs
- IMPORTANT: bcrypt cost ≥ 12, jamais de mot de passe en clair après hash

Phase EXPLORE

Prompt
[ANALYSE UNIQUEMENT — PAS DE CODE] Explore la structure du projet NestJS. Identifie : 1. Les modules existants et leur organisation 2. Comment la config est gérée (ConfigModule ?) 3. La structure TypeORM (entities, migrations) 4. Si un système d'auth existe déjà, même partiel Livre un rapport de 10-15 lignes.

Phase PLAN

Prompt
Je veux une authentification JWT avec : register, login, refresh, logout, guard JWT réutilisable et une route protégée /me. Contrainte importante : le logout doit réellement invalider le refresh token (rotation + denylist côté serveur). Un JWT d'accès reste valide jusqu'à expiration — c'est le refresh qu'on révoque. Sur la base de l'exploration, propose un plan d'implémentation : étapes numérotées, fichiers concernés, critère de validation par étape, et regroupées en 3 blocs livrables. Ne génère pas de code encore. Attends ma validation du plan.

Phase CODE

Prompt
Plan validé. Implémente-le bloc par bloc : Bloc 1 — entité User + migration + config JWT (secret via env) Bloc 2 — register/login (hash bcrypt) + DTOs + guard JWT + /me Bloc 3 — refresh token avec rotation + logout (denylist) Arrête-toi à la fin de chaque bloc : je relis le diff avant le suivant. Si tu t'écartes du plan validé, signale-le au lieu d'improviser.

Phase VERIFY

Prompt
Agis en QA Engineer senior. Génère des tests E2E (Supertest + Jest) couvrant ces 5 scénarios essentiels : 1. Register → 201 + tokens / email déjà utilisé → 409 2. Login bon mot de passe → 200 / mauvais → 401 3. /me sans token → 401 / avec token valide → 200 4. Refresh avec token valide → nouveaux tokens (ancien refresh invalidé) 5. Logout → le refresh token utilisé ensuite est refusé → 401 Utilise une DB éphémère (Testcontainers PostgreSQL, ou better-sqlite3 si le schéma le permet). Pas de mock d'ORM.

Lab 3 — Next.js : Refactoring avec Context Engineering

Durée : 30-45 min · Niveau : intermédiaire · Prérequis : projet Next.js existant, Module 5 lu · Livrable : composant migré Class → Functional + hooks, tests verts

Setup CLAUDE.md

# Lab Next.js Refactoring

## Stack
- Next.js 15 (App Router), TypeScript 5.x, React 19
- Tailwind CSS
- Tests : Vitest + React Testing Library
- State : Zustand (pas de Redux)

## Conventions composants
- Functional components uniquement
- Props typées par interface : interface ButtonProps {}
- Export named uniquement (pas de default export pour les composants)
- Fichiers : ComponentName.tsx + ComponentName.test.tsx dans le même dossier

## Anti-patterns à éviter
- Pas de useEffect pour fetch (Server Components ou React Query)
- Pas de prop drilling > 2 niveaux (utiliser Zustand)
- Pas d'inline styles (Tailwind uniquement)

Workflow de refactoring

Prompt
# EXPLORE [ANALYSE UNIQUEMENT] Analyse le composant @src/components/UserProfile.tsx Identifie : type de composant (class/functional ?), props et typage, état local et usage, effets de bord, tests existants. # PLAN Propose le plan de migration vers functional component + hooks, props interface stricte, Zustand si état partagé. Liste d'étapes. Attends ma validation. # CODE Plan validé : implémente le composant refactorisé d'une traite. Respecte STRICTEMENT le CLAUDE.md. Garde l'API externe identique (mêmes props). C'est un seul composant — pas besoin de découper. # VERIFY Agis en QA. 1. Lance `npm run test -- UserProfile` 2. Si des tests échouent, identifie pourquoi (régression vs test obsolète) 3. Génère les tests manquants pour les nouveaux hooks 4. Vérifie que l'accessibilité n'a pas régressé (attributs aria-*)

Lab 4 — Laravel : Migration et Soft Delete

Durée : 30-45 min · Niveau : intermédiaire · Prérequis : Laravel 11+ installé, Module 3 lu · Livrable : migration deleted_at, modèle SoftDeletes, tests Pest verts

# CLAUDE.md Laravel

## Stack
- Laravel 11+, PHP 8.3+
- Eloquent ORM + MySQL 8
- Tests : Pest (pas PHPUnit)
- API Resources pour les réponses

## Conventions
- Repository Pattern (interface + implémentation)
- Form Requests pour la validation
- API Resources pour la transformation
- Soft deletes via le trait SoftDeletes d'Eloquent

## Commandes
php artisan serve      # Dev
php artisan test       # Tests (Pest)
php artisan migrate    # Migrations
./vendor/bin/pint      # Linter

Lab : Implémenter le soft delete sur User

Prompt
# EXPLORE Analyse le modèle User et UserRepository. Identifie : la méthode delete actuelle, les scopes existants, les relations qui pourraient être affectées, les tests existants. # PLAN Propose le plan pour migrer vers SoftDeletes Eloquent (migration deleted_at, trait sur le modèle, adaptation du repository : withTrashed/onlyTrashed/ restore, tests). Attends ma validation. # CODE Plan validé : implémente-le d'une traite (migration → modèle → repository). Arrête-toi à la fin pour que je relise le diff avant les tests. # VERIFY (Pest) Génère des feature tests Pest : - Soft delete → user non retourné dans les queries normales - withTrashed → user visible - restore → user revient dans les queries normales - forceDelete → suppression physique - Cascade sur les relations si applicable

Lab 5 — DevOps : Pipeline CI/CD avec revue IA

Durée : 45-60 min · Niveau : intermédiaire · Prérequis : projet sur GitHub, Module 6 §7 lu · Livrable : workflow .github/workflows/ai-review.yml avec 3 jobs (quality, ai-security-review, changelog)

Prompt
# EXPLORE Analyse les workflows GitHub Actions existants (.github/workflows/). Identifie les jobs actuels et ce qui manque. # PLAN Je veux un pipeline en 3 jobs : 1. quality : lint + test + coverage check (> 80 %) 2. ai-security-review : sur les PRs uniquement, commente seulement si problème trouvé (action officielle anthropics/claude-code-action, voir Module 6 §7) 3. changelog : sur merge en main, génère les notes depuis les commits Conventional Commits depuis le dernier tag Propose le plan : jobs, dépendances, permissions minimales par job. Contraintes transverses : npm ci (pas npm install), cache des deps, secrets via GitHub Secrets, fail si coverage < 80 %. Attends ma validation. # CODE Plan validé : génère le fichier .github/workflows/ai-review.yml complet en une fois. Je relis le YAML entier avant de commit. # VERIFY — checklist de relecture - [ ] Aucun secret en clair dans le YAML (tout via secrets.*) - [ ] Permissions minimales par job (contents: read, pull-requests: write) - [ ] Cache des dépendances configuré - [ ] Jobs parallélisés quand c'est possible - [ ] Le job ai-security-review ne tourne que sur pull_request - [ ] Notification en cas d'échec

Lab 6 — Python / FastAPI : endpoint async avec SQLAlchemy 2.x

Durée : 45-60 min · Niveau : intermédiaire · Prérequis : projet FastAPI, Module 3 lu · Livrable : endpoint POST /articles async + tests pytest verts

Stack : Python 3.12+, FastAPI 0.115+, SQLAlchemy 2.x async, Pydantic v2

Setup du contexte

# CLAUDE.md (extrait spécifique au lab)

## Stack
- Python 3.12+, FastAPI 0.115+
- SQLAlchemy 2.x **async** uniquement (pas de Session synchrone)
- Pydantic v2 pour les schémas
- pytest + pytest-asyncio + httpx pour les tests

## Conventions
- Fichiers par feature : `app/<feature>/{router,schemas,models,service}.py`
- Routes ne contiennent JAMAIS de logique métier — tout passe par `service.py`
- Dépendances FastAPI : injection via `Depends()`, jamais de globals
- Async partout : pas de `requests`, utiliser `httpx.AsyncClient`

## Tests
- Base de test isolée par test (SQLite async via aiosqlite, ou Postgres jetable)
- Fixtures dans `conftest.py`, factory-boy pour les seeds
- Marker `@pytest.mark.asyncio` sur les tests async

## Anti-patterns
IMPORTANT: SQLAlchemy 2.x style uniquement (`Mapped`, `mapped_column`, `select().where()`) — pas de raw SQL ni de syntaxe v1.

Phase EXPLORE

Prompt
[ANALYSE UNIQUEMENT — PAS DE CODE] Explore la structure du projet. Identifie : 1. Comment les routes existantes sont organisées (par feature ? par couche ?) 2. Comment SQLAlchemy est initialisé (engine, sessionmaker, dépendance FastAPI) 3. Comment Pydantic est utilisé (schémas In/Out séparés ou unifiés ?) 4. Quels fixtures existent dans conftest.py Livre un rapport de 10-15 lignes.

Phase PLAN

Prompt
Je veux ajouter un endpoint `POST /api/v2/articles` qui : - Reçoit un payload `{title, body, tags: string[]}` - Crée un article en DB - Lie ou crée les tags (many-to-many) - Retourne l'article créé avec ses tags Sur la base de ton exploration, propose un plan en étapes numérotées, regroupées en 2 blocs (modèles+migration, puis service+route+schemas). Format : Étape | Fichier(s) | Action | Critère de validation. Identifie les edge cases : - Tag vide ou trop long - Tag dupliqué dans la liste - Conflit de slug si auto-généré Ne génère pas de code encore. Attends ma validation.

Phase CODE

Prompt
Plan validé. Implémente-le par blocs : Bloc 1 — modèle Article + relation many-to-many Tag + migration Alembic Bloc 2 — schemas Pydantic + service + route POST SQLAlchemy 2.x style, annotations de types complètes. Arrête-toi à la fin de chaque bloc pour que je relise le diff.

Phase VERIFY

Prompt
L'implémentation est terminée. Agis maintenant en QA Engineer. 1. Lance `pytest app/articles -v` 2. Lance `ruff check app/articles` 3. Lance `mypy app/articles` 4. Génère les tests manquants pour les edge cases identifiés en PLAN 5. Relance et vérifie qu'ils passent 6. Test httpx contre `POST /api/v2/articles` avec 3 payloads : - Cas nominal - Payload invalide (titre vide) - Tag dupliqué dans la liste Rapport : tests passés | warnings ruff/mypy | tests ajoutés.

Lab 7 — Production Incident Response avec Sentry MCP

Durée : 30-45 min · Niveau : senior · Prérequis : projet en prod connecté à Sentry, MCP Sentry configuré · Livrable : PR avec fix, test de non-régression et garde-fou versionné

Utiliser Claude Code en mode incident commander : récupérer les infos Sentry, formuler une hypothèse, la valider, proposer un fix minimal, documenter.

Setup MCP

Sentry propose un serveur MCP hébergé (OAuth, sans token local à gérer). C'est la voie à privilégier ; vérifie l'URL courante sur la doc Sentry avant de te rabattre sur une install locale.

# Portée project : le serveur atterrit dans .mcp.json, versionné avec le repo
claude mcp add --transport http --scope project sentry <url-mcp-sentry>

# Vérifie que la connexion est bien établie avant de commencer le lab
claude mcp list

Si tu dois passer par un serveur local en stdio, le .mcp.json produit ressemble à ça :

// .mcp.json (racine du projet, pas .claude/settings.json)
{
  "mcpServers": {
    "sentry": {
      "command": "npx",
      "args": ["-y", "@sentry/mcp-server"],
      "env": {
        "SENTRY_AUTH_TOKEN": "${SENTRY_AUTH_TOKEN}",
        "SENTRY_ORG": "my-org",
        "SENTRY_PROJECT": "api"
      }
    }
  }
}

Phase 1 — Capture

Prompt
[LECTURE SEULE] Via le MCP Sentry, cartographie le top 5 des issues non résolues des 24 dernières heures (titre, première/dernière occurrence, utilisateurs affectés, release). Pas de fix encore.

Phase 2 — Triage

Prompt
[LECTURE SEULE] Pour l'issue à plus fort impact : récupère le détail (stack trace, breadcrumbs, requête), identifie fichier:ligne, lis le code autour (max 50 lignes). Formule 2-3 hypothèses classées par probabilité, chacune avec sa méthode de validation.

Phase 3 — Fix

Prompt
On valide l'hypothèse n°1 : [description]. Fix minimal (pas de refactoring opportuniste) + test qui reproduit le bug (rouge avant le fix). Vérifie que le test passe. Ne touche à aucun autre fichier.

Phase 4 — Empêcher la récidive

C'est la question du Module 8 §4, appliquée pour de vrai : est-ce que l'agent va me le refaire ?

Prompt
Le fix est validé. Réponds à une seule question : ce bug, un agent peut-il le réintroduire à partir de nos fichiers de contexte actuels ? Si oui, propose les deux formes de garde-fou et dis laquelle est la plus sûre ici : 1. Une ligne à ajouter dans le fichier de contexte du projet. 2. Un test de non-régression qui échoue tout seul si le pattern revient. Si le commit d'origine porte un trailer `AI-Assisted:`, reporte-le dans la description de PR. Pas de rapport d'incident : la PR doit contenir le fix, le test, et le garde-fou. Rien de plus.

Ressources complémentaires

Templates à reprendre

Le Starter Pack du guide est sur la page dédiée /templates : un fichier de contexte (AGENTS.md) qui marche pour tous les outils, une configuration Claude Code avec des permissions sécurisées par défaut, un hook qui bloque l'écriture de fichiers contenant des secrets, et trois slash commands (/audit-security, /test-gen, /release-notes). Tout est aligné avec les modules 3, 5, 6 et 9.

Pour le reste (Skills spécialisés, serveurs MCP, agents prêts à l'emploi), le catalogue de référence est aitmpl.com, un catalogue communautaire de composants pour Claude Code. La page Templates signale ceux qu'on recommande spécifiquement.