9.1 KiB
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
# 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) :
<type>(<scope>) : <message>— 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
- Ex :
- 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 --rebasepuisgit push. - Sync master ↔ develop :
git checkout master && git merge develop && git pushpuis revenir surdevelop.
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/PreUpdatepourcreatedAt/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, tableconstructeur_categories). ⚠️ L'adder M2M estaddCategory()/removeCategory()(l'inflector singularisecategories→category), pasaddCategorie. Groupes APIconstructeur:read/constructeur:write. - Normalisation slots/skeleton : les anciennes colonnes JSON
structure/productIdssont 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*Requirementdu ModelType (clécustomFieldsJSON) ; Machines → entitésCustomFieldliées parmachineIdFK (pas de ModelType). Les deux partagent l'entitéCustomFieldValuepour 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) → PGtypepieceid. Le SQL brut doit être lowercase. - Tables de jointure M2M : colonnes
aetb(ex :_piececonstructeurs).
Frontend
- Composables :
interface Deps { ... }+export function useXxx(deps: Deps). - Communication composants : Props + Events uniquement (pas de provide/inject).
- API :
useApi.tswrappe fetch aveccredentials: 'include'. ⚠️useApi()préfixe déjà/api→ appeler sans/apiau 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 globalprofile.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
- Lire le fichier avant de l'éditer.
- Reproduire le pattern existant (noms, indentation, structure).
- Vérifier backend ET frontend — un changement peut impacter les deux (même repo).
Après chaque modification
- Backend PHP :
make php-cs-fixer-allow-risky - Frontend TS :
npm run lint:fixpuisnpx 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), envtest, 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 + factoriescreate*()). - 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/passroot, dbinventory)
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.