# CLAUDE.md — Inventory Project ## Project Overview Application de gestion d'inventaire industriel (machines, pièces, composants, produits). Mono-repo avec backend Symfony et frontend Nuxt en submodule git. ## 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 | | ## Glossaire Métier Voir `docs/GLOSSAIRE_METIER.md` — glossaire complet du domaine métier (concepts, workflows utilisateur, correspondance métier↔code). À consulter pour comprendre le "pourquoi" derrière le code. ## Project Structure ``` Inventory/ # Backend Symfony (repo principal) ├── src/Entity/ # Entités Doctrine (annotations PHP 8 attributes) │ └── Trait/ # CuidEntityTrait (génération d'ID CUID) ├── src/Controller/ # Controllers custom (session, comments, audit…) ├── src/EventSubscriber/ # Audit subscribers (onFlush) ├── src/Service/ # Services métier (sync, conversion, storage…) ├── src/Enum/ # Enums PHP (DocumentType, ModelCategory) ├── src/DTO/ # Data Transfer Objects (sync workflow) ├── src/Filter/ # Filtres API Platform custom ├── src/Command/ # Commandes Symfony CLI (compress-pdf, create-profile…) ├── config/ # Config Symfony ├── migrations/ # Migrations Doctrine (raw SQL PostgreSQL) ├── docker/ # Dockerfile + .env.docker ├── scripts/ # release.sh, normalize-dump.py ├── fixtures/ # SQL fixtures ├── tests/ # PHPUnit ├── pre-commit, commit-msg # Git hooks ├── makefile # Commandes Docker/dev ├── VERSION # Source unique de version (semver) ├── Inventory_frontend/ # ← SUBMODULE GIT (repo séparé) │ ├── app/pages/ # Pages Nuxt (file-based routing) │ ├── app/components/ # Composants Vue (auto-imported) │ ├── app/composables/ # Composables Vue │ ├── app/shared/ # Types, utils, validation │ ├── app/middleware/ # Auth middleware global │ └── app/services/ # Service layer (wrappers useApi) ``` ## Key Commands ```bash # Docker make start # Démarrer les containers make stop # Arrêter make shell # Shell interactif (nécessite un TTY) make install # Install complet (composer + npm + build) # Backend make test # PHPUnit (tous les tests) make test FILES=tests/Api/Entity/MachineTest.php # Un test spécifique make php-cs-fixer-allow-risky # Linter PHP (cs-fixer) docker exec -u www-data php-inventory-apache php bin/console doctrine:migrations:migrate # Frontend (dans Inventory_frontend/) npm run dev # Dev server (port 3001) npm run build # Build production npm run lint:fix # ESLint fix npx nuxi typecheck # TypeScript check (0 errors attendu) # Database / Fixtures make db-reset # Reset database (drop + recreate schema) make fixtures-dump # Dump la DB vers fixtures/data.sql make fixtures-load # Charger les fixtures SQL (désactive FK) make fixtures-reset # Reset DB + recharger fixtures make import-data # Importer les dumps SQL normalisés make cache-clear # Clear cache Symfony # Release ./scripts/release.sh patch # Bump patch version (ou minor/major) ``` ## Git Conventions ### Branches - `master` — production - `develop` — branche principale de dev (cible des PR) - `feat/xxx`, `fix/xxx`, `refactor/xxx` — branches de travail ### Commit Message Format (enforced by hook) ``` () : ``` **Espace obligatoire autour du `:`**. Types autorisés (minuscules) : `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`, `wip` Exemples : - `feat(auth) : add login page` - `fix(machines) : prevent null crash on skeleton creation` ### Pre-commit Hook 1. php-cs-fixer sur les fichiers PHP stagés 2. PHPUnit — bloque le commit si tests échouent ### Submodule Workflow Le frontend est un submodule git. Lors d'un commit frontend : 1. Commit dans `Inventory_frontend/` d'abord 2. Commit dans le repo principal pour mettre à jour le pointeur submodule 3. Push les deux repos ## Architecture Backend ### Entités Principales `Machine`, `Piece`, `Composant`, `Product`, `Constructeur`, `Site`, `ModelType`, `CustomField`, `CustomFieldValue`, `Document`, `AuditLog`, `Comment`, `Profile`, `MachineComponentLink`, `MachinePieceLink`, `MachineProductLink` #### Entités de normalisation (slots & skeleton requirements) Remplacent les anciennes colonnes JSON `structure` et `productIds` par des tables relationnelles : - **Slots composant** (données réelles d'un composant) : `ComposantPieceSlot`, `ComposantSubcomponentSlot`, `ComposantProductSlot` - **Slots pièce** (données réelles d'une pièce) : `PieceProductSlot` - **Skeleton Requirements** (définitions du ModelType) : `SkeletonPieceRequirement`, `SkeletonProductRequirement`, `SkeletonSubcomponentRequirement` ### Patterns - **IDs** : CUID-like strings (`'cl' + bin2hex(random_bytes(12))`), pas d'auto-increment - **ORM** : Attributs PHP 8 (`#[ORM\Column(...)]`, `#[Groups([...])]`) - **Lifecycle** : `#[ORM\HasLifecycleCallbacks]` avec `PrePersist`/`PreUpdate` pour `createdAt`/`updatedAt` - **Sécurité** : `security: "is_granted('ROLE_...')"` sur chaque opération API Platform - **Audit** : Subscribers Doctrine `onFlush` capturent diff + snapshot complet - **Migrations** : Raw SQL PostgreSQL avec `IF NOT EXISTS`/`IF EXISTS` pour idempotence ### Custom Controllers (pas API Platform) - `MachineStructureController` — `/api/machines/{id}/structure` (GET/PATCH), `/api/machines/{id}/clone` (POST) : hiérarchie complète machine avec normalisation JSON manuelle. Source principale de données pour la page détail machine. - `MachineCustomFieldsController` — `/api/machines/{id}/add-custom-fields` (POST) : initialise les CustomFieldValue manquants pour une machine. - `CustomFieldValueController` — `/api/custom-fields/values/*` : CRUD + upsert pour les valeurs de champs perso. - `ComposantPieceSlotController` — `/api/composant-piece-slots/{id}` (PATCH) : mise à jour des slots pièce d'un composant. - `ComposantProductSlotController` — `/api/composant-product-slots/{id}` (PATCH) : mise à jour des slots produit d'un composant. - `ComposantSubcomponentSlotController` — `/api/composant-subcomponent-slots/{id}` (PATCH) : mise à jour des slots sous-composant d'un composant. - `SessionProfileController` — `/api/session/profile` (GET/POST/DELETE) : auth session (login/logout/current user). - `SessionProfilesController` — `/api/session/profiles` (GET) : liste des profils disponibles pour la session. - `AdminProfileController` — `/api/admin/profiles` : CRUD profils, gestion rôles et mots de passe (ROLE_ADMIN). - `CommentController` — `/api/comments` : création, résolution, compteur non-résolus. - `ActivityLogController` — `/api/activity-logs` (GET) : journal d'activité global. - `EntityHistoryController` — `/api/{entity}/{id}/history` (GET) : historique audit par entité (machines, pièces, composants, produits). - `DocumentQueryController` — `/api/documents/{entity}/{id}` (GET) : documents par site/machine/composant/pièce/produit. - `DocumentServeController` — `/api/documents/{id}/file|download` (GET) : servir/télécharger fichiers. - `ModelTypeConversionController` — `/api/model_types/{id}/conversion-check|convert` : vérification et conversion de ModelType. - `ModelTypeSyncController` — `/api/model_types/{id}/sync-preview|sync-confirm` (POST) : prévisualisation et application de sync ModelType→Composants. - `EntityVersionController` — `/api/{entity}/{id}/versions` (GET), `/api/{entity}/{id}/versions/{version}/restore` (POST) : historique de versions numérotées et restauration. - `HealthCheckController` — `/api/health` (GET) : health check. ### Custom Fields — Architecture - **Composants/Pièces/Produits** : définitions dans les entités `SkeletonPieceRequirement`, `SkeletonProductRequirement`, `SkeletonSubcomponentRequirement` du ModelType (anciennement JSON `structure`, normalisé en tables relationnelles). Les custom fields de ces entités sont définis dans `customFields` JSON sur chaque Skeleton*Requirement. - **Machines** : définitions = entités `CustomField` liées directement via `machineId` FK (pas de ModelType) - Les deux partagent la même entité `CustomFieldValue` pour stocker les valeurs ### Enums (`src/Enum/`) - `DocumentType` — types de documents (photo, schéma, facture, etc.) - `ModelCategory` — catégories de ModelType ### Services (`src/Service/`) - `ModelTypeSyncService` — synchronise les skeleton requirements d'un ModelType vers les composants existants - `ModelTypeCategoryConversionService` — conversion de catégorie d'un ModelType - `SkeletonStructureService` — gestion de la structure skeleton (requirements) - `DocumentStorageService` — stockage et gestion des fichiers documents - `PdfCompressorService` — compression des PDFs uploadés - `EntityVersionService` — gestion des versions numérotées (snapshot, restore) pour machines, pièces, composants, produits - `ReferenceAutoGenerator` — génération automatique de références pour pièces et composants à partir de formules ModelType - `src/Service/Sync/` — stratégies de sync par type de slot (tagged `app.sync_strategy`) ### DTOs (`src/DTO/`) - `SyncConfirmation`, `SyncPreviewResult`, `SyncExecutionResult` — objets de transfert pour le workflow de sync ModelType ### Filters (`src/Filter/`) - `MultiSearchFilter` — filtre API Platform pour recherche OR sur plusieurs champs (ex: name + reference) ### EventSubscribers notables (non-audit) - `PieceProductSyncSubscriber` — sync automatique des PieceProductSlots - `UniqueConstraintSubscriber` — traduit les erreurs de contrainte unique PG en messages utilisateur lisibles - `ReferenceAutoSubscriber` — recalcule les références auto des pièces/composants quand les CustomFieldValues changent (onFlush) ### Rôles (hiérarchie) ``` ROLE_ADMIN → ROLE_GESTIONNAIRE → ROLE_VIEWER → ROLE_USER ``` ### PostgreSQL — ATTENTION - Les noms de colonnes sont **TOUJOURS EN MINUSCULES** dans PG - Doctrine utilise camelCase (`typePieceId`) mais PG stocke `typepieceid` - Le SQL brut doit utiliser les noms lowercase - Tables de jointure many-to-many : colonnes `a` et `b` (ex: `_piececonstructeurs`) ## Architecture Frontend ### Patterns - **Composables** : `interface Deps { ... }` + `export function useXxx(deps: Deps)` - **Communication composants** : Props + Events uniquement (pas de provide/inject) - **API** : `useApi.ts` wraps fetch avec `credentials: 'include'` pour les cookies session - **Content-Type** : `application/ld+json` pour POST/PUT, `application/merge-patch+json` pour PATCH - **Auth** : `useProfileSession` + middleware global `profile.global.ts` - **Permissions** : `usePermissions.ts` miroir de la hiérarchie backend côté client - **Auto-imports** : Nuxt auto-importe composants (`components/`) et composables (`composables/`) ### DaisyUI Classes - Input : `input input-bordered input-sm md:input-md` - Textarea : `textarea textarea-bordered textarea-sm md:textarea-md` - Select : `select select-bordered select-sm md:select-md` - Button : `btn btn-sm md:btn-md btn-primary` ## Règles Importantes ### CLAUDE.md — Maintenance obligatoire - **Toujours consulter** ce fichier en début de conversation pour respecter les conventions - **Mettre à jour** ce fichier quand une nouvelle convention, pattern ou décision architecturale est établie - **Utiliser comme source de vérité** pour les commandes, patterns et règles du projet ### Toujours faire AVANT de modifier du code 1. **Lire le fichier** avant de l'éditer — ne jamais proposer de changements sur du code non lu 2. **Comprendre le pattern existant** — reproduire le style du fichier (noms, indentation, structure) 3. **Vérifier les deux repos** — un changement peut impacter backend ET frontend ### Après chaque modification 1. Backend PHP : `make php-cs-fixer-allow-risky` 2. Frontend : `npm run lint:fix` puis `npx nuxi typecheck` si fichiers TS modifiés ### Ne jamais faire - Ajouter des features non demandées, du code mort, ou des abstractions prématurées - Utiliser `provide/inject` — le codebase utilise Props + Events - Utiliser JWT/tokens — l'auth est session-based - Écrire du SQL avec des noms camelCase — PostgreSQL = lowercase - Committer sans que l'utilisateur le demande explicitement - Force push sans confirmation explicite - Modifier la config git ### Submodule — Synchronisation Quand les branches `master` et `develop` divergent sur l'un des deux repos, **toujours les synchroniser** : - Main repo : `git checkout master && git merge develop && git push` - Frontend : `git checkout develop && git merge master && git push` (ou l'inverse selon le cas) ## Tests ### Stack de test - **PHPUnit 12** + **API Platform Test** (`ApiTestCase`) - **DAMA DoctrineTestBundle** — wrappe chaque test dans une transaction avec rollback automatique (pas de TRUNCATE) - Base de test : même PG, env `test` ### Commandes Voir section "Key Commands". Commande additionnelle : ```bash make test-setup # Créer/mettre à jour le schéma test ``` ### Pattern de test - Hériter de `AbstractApiTestCase` (helpers auth + factories) - Ne PAS faire de TRUNCATE/cleanup dans tearDown — DAMA s'en occupe par rollback - Factories : `createProfile()`, `createMachine()`, `createSite()`, `createComposant()`, `createPiece()`, `createProduct()`, `createConstructeur()`, `createCustomField()`, `createCustomFieldValue()`, `createModelType()`, `createMachineComponentLink()`, `createMachinePieceLink()`, `createMachineProductLink()`, `createComposantPieceSlot()`, `createComposantSubcomponentSlot()`, `createComposantProductSlot()`, `createPieceProductSlot()` - Auth : `createViewerClient()`, `createGestionnaireClient()`, `createAdminClient()`, `createUnauthenticatedClient()` ## URLs Locales - API Symfony : `http://localhost:8081/api` - Nuxt dev : `http://localhost:3001` - Adminer (PG) : `http://localhost:5050` - PG direct : `localhost:5433` (user: root, pass: root, db: inventory)