# CLAUDE.md — Inventory Project Application de gestion d'inventaire industriel (machines, pièces, composants, produits). **Monorepo** : backend Symfony + frontend Nuxt (`frontend/`) dans le **même dépôt git** (plus de submodule). Un seul commit/push couvre backend + frontend. ## Stack | Layer | Tech | Version | |-------|------|---------| | Backend | Symfony + API Platform | 8.0 / ^4.2 | | PHP | PHP | >=8.4 | | Database | PostgreSQL | 16 | | Frontend | Nuxt (SPA, SSR off) | 4 | | UI | Vue 3 Composition API + TypeScript | 3.5 / 5.7 | | CSS | TailwindCSS 4 + DaisyUI 5 | | | Auth | Session-based (cookies, **pas JWT**) | | | Containers | Docker Compose | | ## Documentation détaillée (lire à la demande, ne pas dupliquer ici) Vu la complexité du projet, le détail vit dans `docs/` — y aller plutôt que de deviner : - **`docs/FONCTIONNEMENT.md`** — le métier : à quoi sert l'app, entités, ModelType/skeleton, cycle de vie, rôles, fonctionnalités clés. - **`docs/GLOSSAIRE_METIER.md`** — glossaire complet, correspondance métier ↔ code (le « pourquoi »). - **`docs/BACKEND.md`** — catalogue backend complet : toutes les entités, **tous les controllers** (routes), audit, services, migrations, auth, rôles. - **`docs/FRONTEND.md`** — catalogue frontend : composables, composants, useApi, IRIs, content-types, auth, style. - **`docs/REVIEW_ARCHITECTURE.md`** — top 10 des sources de complexité et effets de bord (God controllers, canaux cachés, doubles flush…). **À consulter avant tout refacto.** ## Project Structure ``` Inventory/ # Backend Symfony (repo principal) ├── src/Entity/ (+ Trait/) # Entités Doctrine (attributs PHP 8), CuidEntityTrait ├── src/Controller/ # Controllers custom (session, comments, audit, structure…) ├── src/EventSubscriber/ # Audit (onFlush) + sync/contraintes ├── src/Service/ (+ Sync/) # Services métier (sync, conversion, storage, versions…) ├── src/Enum/ src/DTO/ src/Filter/ src/Command/ ├── config/ migrations/ docker/ scripts/ fixtures/ tests/ ├── makefile VERSION # VERSION = source unique de version (semver) └── frontend/ # ← Frontend Nuxt (MÊME repo, pas un submodule) └── app/{pages,components,composables,shared,middleware,services}/ ``` ## Key Commands ```bash # Docker make start / make stop # Démarrer / arrêter les containers make shell # Shell interactif (nécessite un TTY) make install # Install complet (composer + npm + build) # Backend make test # PHPUnit (tous) make test FILES=tests/Api/Entity/MachineTest.php # Un test make test-setup # Créer/MAJ le schéma de test make php-cs-fixer-allow-risky # Linter PHP docker exec -u www-data php-inventory-apache php bin/console doctrine:migrations:migrate # Frontend (dans frontend/) npm run dev # Dev server (port 3001) npm run lint:fix # ESLint fix npx nuxi typecheck # TypeScript check (0 erreur attendu) # Database / Fixtures make db-reset # Reset DB (drop + recreate schema) make fixtures-reset # Reset DB + recharger fixtures SQL make import-data # Importer les dumps SQL normalisés make cache-clear # Import fournisseurs (non destructif : find-or-create par nom normalisé) docker exec -u www-data php-inventory-apache php bin/console app:import-fournisseurs # dry-run docker exec -u www-data php-inventory-apache php bin/console app:import-fournisseurs --force # applique # Release ./scripts/release.sh patch # Bump version (patch/minor/major) ``` ## Git Conventions - **Branches** : `master` (prod), `develop` (cible des PR), `feat/* fix/* refactor/*`. - **Commit** (enforced par hook) : `() : ` — **espace obligatoire autour du `:`**. Types : `build chore ci docs feat fix perf refactor revert style test wip`. - Ex : `feat(auth) : add login page`, `fix(machines) : prevent null crash` - **Pre-commit hook** : php-cs-fixer + PHPUnit (bloque si échec). - **Workflow commit** : backend + frontend = **un seul commit/push** depuis la racine (pas de submodule). Le hook étant lent, committer avec `git commit --no-verify`. Push rejeté → `git pull --rebase` puis `git push`. - **Sync master ↔ develop** : `git checkout master && git merge develop && git push` puis revenir sur `develop`. ## Pièges & patterns non-évidents > Le catalogue complet est dans `docs/BACKEND.md` / `docs/FRONTEND.md`. Ci-dessous **uniquement** ce qui n'est pas évident en lisant le code. ### Backend - **IDs CUID** : strings `'cl' + bin2hex(random_bytes(12))`, **pas** d'auto-increment. - **Lifecycle** : `#[ORM\HasLifecycleCallbacks]` + `PrePersist`/`PreUpdate` pour `createdAt`/`updatedAt`. - **Sécurité** : `security: "is_granted('ROLE_...')"` sur chaque opération API Platform. Hiérarchie : `ROLE_ADMIN → ROLE_GESTIONNAIRE → ROLE_VIEWER → ROLE_USER`. - **Audit** : subscribers Doctrine `onFlush` (diff + snapshot complet). - **Migrations** : raw SQL PostgreSQL avec `IF NOT EXISTS`/`IF EXISTS` (idempotence). - **Constructeur (Fournisseur)** : collection `telephones` (1-N, cascade/orphanRemoval) + `categories` (M2M, table `constructeur_categories`). ⚠️ L'adder M2M est `addCategory()`/`removeCategory()` (l'inflector singularise `categories` → `category`), **pas** `addCategorie`. Groupes API `constructeur:read` / `constructeur:write`. - **Normalisation slots/skeleton** : les anciennes colonnes JSON `structure`/`productIds` sont remplacées par des tables relationnelles — slots réels (`ComposantPieceSlot`, `ComposantSubcomponentSlot`, `ComposantProductSlot`, `PieceProductSlot`) vs définitions ModelType (`SkeletonPieceRequirement`, `SkeletonProductRequirement`, `SkeletonSubcomponentRequirement`). - **Custom Fields** : Composants/Pièces/Produits → définitions dans les `Skeleton*Requirement` du ModelType (clé `customFields` JSON) ; Machines → entités `CustomField` liées par `machineId` FK (pas de ModelType). Les deux partagent l'entité `CustomFieldValue` pour les valeurs. - **`MachineStructureController`** (`/api/machines/{id}/structure`, `/clone`) : source principale de données de la page détail machine (normalisation JSON manuelle). Cf. `REVIEW_ARCHITECTURE.md` (God controller). ### PostgreSQL — ATTENTION - Noms de colonnes **TOUJOURS EN MINUSCULES** en PG. Doctrine camelCase (`typePieceId`) → PG `typepieceid`. Le **SQL brut doit être lowercase**. - Tables de jointure M2M : colonnes `a` et `b` (ex : `_piececonstructeurs`). ### Frontend - **Composables** : `interface Deps { ... }` + `export function useXxx(deps: Deps)`. - **Communication composants** : Props + Events uniquement (**pas** de provide/inject). - **API** : `useApi.ts` wrappe fetch avec `credentials: 'include'`. ⚠️ `useApi()` **préfixe déjà** `/api` → appeler **sans** `/api` au début. Ex : `api.get('/custom-fields/names')` **et PAS** `'/api/custom-fields/names'` (sinon 404 sur `/api/api/...`). - **Content-Type** : `application/ld+json` (POST/PUT), `application/merge-patch+json` (PATCH). - **Auth** : `useProfileSession` + middleware global `profile.global.ts`. Permissions : `usePermissions.ts` (miroir de la hiérarchie backend). - **Classes DaisyUI** : `input input-bordered input-sm md:input-md` (idem textarea/select/btn, `btn-primary`). ## Règles Importantes ### Avant de modifier du code 1. **Lire le fichier** avant de l'éditer. 2. **Reproduire le pattern existant** (noms, indentation, structure). 3. **Vérifier backend ET frontend** — un changement peut impacter les deux (même repo). ### Après chaque modification 1. Backend PHP : `make php-cs-fixer-allow-risky` 2. Frontend TS : `npm run lint:fix` puis `npx nuxi typecheck` ### Ne jamais faire - Features non demandées, code mort, abstractions prématurées - `provide/inject` (le code utilise Props + Events) · JWT/tokens (auth session-based) - SQL en camelCase (PG = lowercase) - Committer sans demande explicite · force push sans confirmation · modifier la config git ### Maintenir ce fichier Mettre à jour quand une nouvelle convention/pattern/décision archi est établie. Source de vérité pour commandes, pièges et règles ; le **détail** descriptif va dans `docs/`. ## Tests - **PHPUnit 12** + **API Platform Test** (`ApiTestCase`), env `test`, même PG. - **DAMA DoctrineTestBundle** : chaque test wrappé en transaction + rollback auto → **ne PAS** faire de TRUNCATE/cleanup en `tearDown`. - Hériter de `AbstractApiTestCase` (helpers auth + factories `create*()`). - Auth : `createViewerClient()`, `createGestionnaireClient()`, `createAdminClient()`, `createUnauthenticatedClient()`. ## URLs Locales - API Symfony : `http://localhost:8081/api` · Nuxt dev : `http://localhost:3001` - Adminer : `http://localhost:5050` · PG direct : `localhost:5433` (user/pass `root`, db `inventory`) ## Délégation Codex Pour les tâches mécaniques (tests, boilerplate, renommages, refacto répétitif), déléguer à Codex via le plugin `codex` (junior rapide/pas cher). Garder Claude pour la réflexion, l'architecture et la vérification (senior). Meilleur ratio qualité/crédits.