Files
Inventory/CLAUDE.md
Matthieu daa0cb1e28
All checks were successful
Auto Tag Develop / tag (push) Successful in 9s
feat(fournisseurs) : categories (M2M) + telephones (1-N) + import customer.json
- Nouvelles entites ConstructeurCategorie (referentiel M2M) et ConstructeurTelephone (1-N)
- Constructeur : retrait colonne phone, ajout collections telephones/categories, groupes de serialisation constructeur:read/write
- Migration : cree les 3 tables, migre la colonne phone existante vers constructeur_telephone, drop phone
- Commande app:import-fournisseurs (dry-run par defaut, --force) : non destructive, find-or-create par nom, ne touche jamais un ID existant, ajout-seulement pour telephones/categories
- MAJ MCP tools / MachineStructureController / audit subscriber / tests
- Frontend : page constructeurs avec telephones multiples + categories (tableau, filtre, formulaire), composable useConstructeurCategories, composant ConstructeurCategorieSelect

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:02:44 +02:00

16 KiB

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)
├── 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

# 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 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

# Import fournisseurs (customer.json → Constructeur + ConstructeurCategorie + ConstructeurTelephone)
docker exec -u www-data php-inventory-apache php bin/console app:import-fournisseurs            # dry-run (par défaut)
docker exec -u www-data php-inventory-apache php bin/console app:import-fournisseurs --force    # applique
# Non destructif : find-or-create par nom normalisé, ne change jamais un ID existant, n'ajoute que les téléphones/catégories manquants

# 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)

<type>(<scope optionnel>) : <message>

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 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, ConstructeurCategorie, ConstructeurTelephone, Site, ModelType, CustomField, CustomFieldValue, Document, AuditLog, Comment, Profile, MachineComponentLink, MachinePieceLink, MachineProductLink

Constructeur (Fournisseur) : possède name, email, une collection telephones (1-N → ConstructeurTelephone, cascade/orphanRemoval) et categories (M2M → ConstructeurCategorie, table constructeur_categories). Sérialisation API Platform via les groupes constructeur:read / constructeur:write (téléphones & catégories embarqués). ⚠️ L'adder M2M s'appelle addCategory()/removeCategory() (l'inflector singularise categoriescategory), pas addCategorie. ConstructeurCategorie et ConstructeurTelephone sont aussi des ApiResource à part entière (/api/constructeur_categories, /api/constructeur_telephones).

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
  • ⚠️ Préfixe /api : useApi() prepend déjà apiBaseUrl (= /api par défaut, cf. nuxt.config.ts). Les appels doivent donc utiliser des chemins sans /api au début. Ex : api.get('/custom-fields/names') et PAS api.get('/api/custom-fields/names') (sinon 404 sur /api/api/...).
  • 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 :

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(), createConstructeurCategorie(), createConstructeurTelephone()
  • 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)

Delegation Codex

Pour les taches mecaniques (tests, boilerplate, renommages, refacto repetitif), delegue a Codex via le plugin codex. Garde Claude pour la reflexion, l'architecture et la verification.

  • Codex = junior dev rapide et pas cher (executions mecaniques)
  • Claude = senior dev qui verifie et reflechit (design, review, decisions)

C'est le meilleur ratio qualite/credits.