14 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)
├── 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
# 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— productiondevelop— 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 pagefix(machines) : prevent null crash on skeleton creation
Pre-commit Hook
- php-cs-fixer sur les fichiers PHP stagés
- PHPUnit — bloque le commit si tests échouent
Submodule Workflow
Le frontend est un submodule git. Lors d'un commit frontend :
- Commit dans
Inventory_frontend/d'abord - Commit dans le repo principal pour mettre à jour le pointeur submodule
- 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]avecPrePersist/PreUpdatepourcreatedAt/updatedAt - Sécurité :
security: "is_granted('ROLE_...')"sur chaque opération API Platform - Audit : Subscribers Doctrine
onFlushcapturent diff + snapshot complet - Migrations : Raw SQL PostgreSQL avec
IF NOT EXISTS/IF EXISTSpour 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.HealthCheckController—/api/health(GET) : health check.
Custom Fields — Architecture
- Composants/Pièces/Produits : définitions dans les entités
SkeletonPieceRequirement,SkeletonProductRequirement,SkeletonSubcomponentRequirementdu ModelType (anciennement JSONstructure, normalisé en tables relationnelles). Les custom fields de ces entités sont définis danscustomFieldsJSON sur chaque Skeleton*Requirement. - Machines : définitions = entités
CustomFieldliées directement viamachineIdFK (pas de ModelType) - Les deux partagent la même entité
CustomFieldValuepour 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 existantsModelTypeCategoryConversionService— conversion de catégorie d'un ModelTypeSkeletonStructureService— gestion de la structure skeleton (requirements)DocumentStorageService— stockage et gestion des fichiers documentsPdfCompressorService— compression des PDFs uploadéssrc/Service/Sync/— stratégies de sync par type de slot (taggedapp.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 PieceProductSlotsUniqueConstraintSubscriber— traduit les erreurs de contrainte unique PG en messages utilisateur lisibles
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 stocketypepieceid - Le SQL brut doit utiliser les noms lowercase
- Tables de jointure many-to-many : colonnes
aetb(ex:_piececonstructeurs)
Architecture Frontend
Patterns
- Composables :
interface Deps { ... }+export function useXxx(deps: Deps) - Communication composants : Props + Events uniquement (pas de provide/inject)
- API :
useApi.tswraps fetch aveccredentials: 'include'pour les cookies session - Content-Type :
application/ld+jsonpour POST/PUT,application/merge-patch+jsonpour PATCH - Auth :
useProfileSession+ middleware globalprofile.global.ts - Permissions :
usePermissions.tsmiroir 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
- Lire le fichier avant de l'éditer — ne jamais proposer de changements sur du code non lu
- Comprendre le pattern existant — reproduire le style du fichier (noms, indentation, structure)
- Vérifier les deux repos — un changement peut impacter backend ET frontend
Après chaque modification
- Backend PHP :
make php-cs-fixer-allow-risky - Frontend :
npm run lint:fixpuisnpx nuxi typechecksi 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() - 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)