Compare commits

...

5 Commits

Author SHA1 Message Date
Matthieu
78f19daf76 chore(release) : v1.3.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 14:20:29 +01:00
Matthieu
6caa4a61df chore(frontend) : update submodule — API optimizations, cache invalidation, tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 14:19:24 +01:00
Matthieu
bf55034b2e chore(frontend) : complete frontend refactoring (F1-F7)
Update frontend submodule with 14 conventional commits covering:
- F1.1-F1.4: Decompose mega-components (machine detail/create, ComponentItem/PieceItem)
- F2.1-F2.3: Extract shared helpers (extractCollection, history, types)
- F3.2-F3.3: Migrate composables to TypeScript, eliminate explicit any
- F4.1-F4.2: Enable strict ESLint rules, remove debug console.logs
- F5.1: Split modelUtils into thematic modules
- F6.1-F6.2: Configure Vitest with 54 unit tests
- F7.2-F7.3: DaisyUI confirm modal, extract AppNavbar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:20:55 +01:00
Matthieu
ba1114e78b chore(frontend): update refactor plan and remove legacy frontend 2026-02-06 17:17:29 +01:00
Matthieu
5ccc3b30f0 docs : add comprehensive refactoring plan (backend + frontend)
14 phases, 39 tasks covering:
- Backend: security, code duplication, controllers, storage, tests
- Frontend: mega-component split, duplication, TypeScript migration, tests

Includes agent tracking system with status, journal, and rules.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:34:43 +01:00
16 changed files with 790 additions and 12057 deletions

786
REFACTORING_PLAN.md Normal file
View File

@@ -0,0 +1,786 @@
# Plan de Refactoring - Inventory v1.2.0
> **Date de creation :** 2026-02-03
> **Branche de travail :** `refacto/v1.3.0`
> **Base :** `develop` (commit `8d83076`)
---
## Legende des statuts
| Statut | Signification |
| ------ | ---------------------- |
| `[ ]` | A faire |
| `[~]` | En cours |
| `[x]` | Termine |
| `[!]` | Bloque / besoin d'info |
---
## Phase 1 - Securite (CRITIQUE)
> **Priorite :** MAXIMALE - A traiter en premier
### 1.1 Corriger la configuration de securite
- **Statut :** `[ ]`
- **Fichier :** `config/packages/security.yaml`
- **Probleme :** `PUBLIC_ACCESS` applique a toutes les routes `/api` avant la regle `IS_AUTHENTICATED_FULLY`. Le pattern matching "first match wins" rend potentiellement tout public.
- **Action :** Reordonner les regles `access_control` pour que les routes protegees soient listees AVANT les routes publiques.
- **Agent :** -
- **Notes :** -
### 1.2 Ajouter les controles d'autorisation sur les controllers
- **Statut :** `[ ]`
- **Fichiers :**
- `src/Controller/MachineSkeletonController.php`
- `src/Controller/CustomFieldValueController.php`
- `src/Controller/DocumentQueryController.php`
- `src/Controller/SessionProfileController.php`
- `src/Controller/SessionProfilesController.php`
- Tous les `*HistoryController.php`
- **Probleme :** Aucun attribut `#[IsGranted]` sur les controllers custom. Pas de RBAC.
- **Action :** Ajouter `#[IsGranted('IS_AUTHENTICATED_FULLY')]` sur chaque controller (ou route). Definir des roles si necessaire.
- **Agent :** -
- **Notes :** -
### 1.3 Securiser les secrets
- **Statut :** `[ ]`
- **Fichiers :**
- `.env` (JWT_PASSPHRASE en dur, APP_SECRET vide)
- `docker/.env.docker` (credentials `root:root`)
- **Action :**
1. Deplacer `JWT_PASSPHRASE` dans `.env.local` (git-ignore)
2. Generer un `APP_SECRET` valide
3. Ajouter `.env.local` dans `.gitignore` si pas deja fait
4. Documenter la configuration des secrets pour les devs
- **Agent :** -
- **Notes :** -
---
## Phase 2 - Elimination de la duplication de code
> **Priorite :** HAUTE - Impact direct sur la maintenabilite
### 2.1 Refactorer les 3 Audit Subscribers en un seul generique
- **Statut :** `[ ]`
- **Fichiers concernes :**
- `src/EventSubscriber/ProductAuditSubscriber.php` (298 LOC)
- `src/EventSubscriber/PieceAuditSubscriber.php` (300 LOC)
- `src/EventSubscriber/ComposantAuditSubscriber.php` (300 LOC)
- **Probleme :** ~900 LOC dupliquees a ~95%. Les methodes `onFlush()`, `buildDiffFromChangeSet()`, `resolveActorProfileId()`, `mergeDiffs()`, `normalizeCollection()` sont identiques. Seules les methodes `snapshot*()` different legerement.
- **Action :**
1. Creer un `AbstractAuditSubscriber` ou un `GenericAuditSubscriber` parametrable
2. Extraire la logique commune (onFlush, buildDiff, resolveActor, mergeDiffs, normalizeCollection)
3. Utiliser un systeme de configuration par entite (map `entityClass => entityType + snapshotMethod`)
4. Supprimer les 3 fichiers redondants
5. Verifier que l'audit fonctionne toujours sur Product, Piece et Composant
- **Agent :** -
- **Notes :** Tester manuellement les logs d'audit apres refacto.
### 2.2 Extraire un CuidGenerator utilitaire
- **Statut :** `[ ]`
- **Fichiers concernes :** 18 entites contenant `generateCuid()` en prive
- **Probleme :** Methode `generateCuid()` dupliquee dans chaque entite. De plus, `AuditLog.php` utilise une variante differente (base_convert).
- **Action :**
1. Creer `src/Util/CuidGenerator.php` avec une methode statique `generate(): string`
2. Uniformiser l'implementation (choisir une seule methode)
3. Remplacer tous les appels dans les 18 entites
4. Supprimer les methodes privees devenues inutiles
- **Agent :** -
- **Notes :** Attention a l'inconsistance entre AuditLog et les autres entites.
### 2.3 Factoriser la logique de liaison dans MachineSkeletonController
- **Statut :** `[ ]`
- **Fichier :** `src/Controller/MachineSkeletonController.php` (756 LOC)
- **Probleme :** Les methodes `applyComponentLinks()`, `applyPieceLinks()`, `applyProductLinks()` sont quasi identiques (~90 LOC chacune).
- **Action :**
1. Extraire une methode generique `applyLinks(Machine $machine, array $links, string $type)`
2. Parametrer par le type d'entite liee (Composant, Piece, Product)
3. Reduire le controller a ~400 LOC max
- **Agent :** -
- **Notes :** -
---
## Phase 3 - Restructuration des controllers
> **Priorite :** MOYENNE - Amelioration de la lisibilite et maintenabilite
### 3.1 Decouper MachineSkeletonController
- **Statut :** `[ ]`
- **Fichier :** `src/Controller/MachineSkeletonController.php` (756 LOC)
- **Action :**
1. Extraire la logique metier dans un `MachineSkeletonService`
2. Le controller ne doit gerer que la requete/reponse HTTP
3. Le service gere la logique de skeleton (get, update, applyLinks)
4. Extraire les helpers (`resolveIdentifier`, `indexLinksById`, `applyOverrides`, `normalizeMachineSkeletonResponse`) dans le service
- **Agent :** -
- **Notes :** Depend de la phase 2.3 (factorisation des liens).
### 3.2 Ajouter un try-catch et du logging dans les controllers
- **Statut :** `[ ]`
- **Fichiers :** Tous les controllers dans `src/Controller/`
- **Probleme :** Aucun try-catch autour des `flush()` et `persist()`. Pas de logging d'erreurs.
- **Action :**
1. Ajouter `try-catch` autour des operations Doctrine dans chaque controller
2. Logger les erreurs avec le `LoggerInterface` de Symfony (Monolog)
3. Retourner des reponses JSON coherentes en cas d'erreur serveur (500)
- **Agent :** -
- **Notes :** -
### 3.3 Renforcer la validation des entrees
- **Statut :** `[ ]`
- **Fichiers :**
- `src/Controller/CustomFieldValueController.php`
- `src/Controller/MachineSkeletonController.php`
- **Probleme :** Pas de validation de longueur max, pas de regex sur les IDs, pas de controle de profondeur JSON.
- **Action :**
1. Valider le format des IDs (regex CUID : `/^cl[a-f0-9]{24}$/`)
2. Ajouter des limites de longueur sur les champs string
3. Utiliser le composant Validator de Symfony pour les DTOs si pertinent
- **Agent :** -
- **Notes :** -
---
## Phase 4 - Amelioration du stockage
> **Priorite :** MOYENNE - Performance et scalabilite
### 4.1 Migrer le stockage PDF de base64 vers le filesystem
- **Statut :** `[ ]`
- **Fichiers :**
- `src/Entity/Document.php`
- `src/Command/CompressPdfCommand.php`
- `src/Service/PdfCompressorService.php`
- **Probleme :** Les PDFs sont stockes en base64 dans la colonne `path` (TEXT) de la BDD. Risque de DoS et mauvaise perf sur des gros fichiers.
- **Action :**
1. Utiliser `vich/uploader-bundle` (deja installe) pour le stockage fichier
2. Configurer un repertoire de stockage (`var/uploads/documents/`)
3. Migrer les documents existants (script de migration)
4. Adapter `PdfCompressorService` pour lire/ecrire sur le filesystem
5. Mettre a jour l'entite Document
- **Agent :** -
- **Notes :** Prevoir une migration de donnees pour les documents existants.
### 4.2 Corriger les types de prix (string -> decimal)
- **Statut :** `[ ]`
- **Fichiers :**
- `src/Entity/Machine.php` (`$prix`)
- `src/Entity/Product.php` (`$supplierPrice`)
- **Probleme :** Les prix sont types `?string` en PHP alors que la colonne est `DECIMAL(10,2)` en BDD.
- **Action :**
1. Changer le type PHP en `?float` ou utiliser `brick/money`
2. Adapter les getters/setters
3. Verifier la serialisation API Platform
- **Agent :** -
- **Notes :** Impact potentiel sur le frontend (format des nombres).
---
## Phase 5 - Utilisation du Process Component
> **Priorite :** BASSE - Bonne pratique
### 5.1 Remplacer exec() par Symfony Process
- **Statut :** `[ ]`
- **Fichiers :**
- `src/Command/CompressPdfCommand.php` (lignes 42, 98-101)
- `src/Service/PdfCompressorService.php` (lignes 37-41)
- **Probleme :** Utilisation de `exec()` directe pour appeler `qpdf`.
- **Action :**
1. Remplacer par `Symfony\Component\Process\Process`
2. Gerer le timeout et les erreurs proprement
3. Tester que la compression fonctionne toujours
- **Agent :** -
- **Notes :** `escapeshellarg()` est deja utilise, donc pas de faille de securite immediate.
---
## Phase 6 - Tests
> **Priorite :** HAUTE - Indispensable avant toute refacto majeure
### 6.1 Mettre en place les tests unitaires
- **Statut :** `[ ]`
- **Fichiers a creer :**
- `tests/Unit/Util/CuidGeneratorTest.php`
- `tests/Unit/Entity/MachineTest.php`
- `tests/Unit/Entity/ProductTest.php`
- `tests/Unit/Service/PdfCompressorServiceTest.php`
- **Action :**
1. Tester le CuidGenerator (format, unicite)
2. Tester les entites (validation, lifecycle callbacks)
3. Tester le PdfCompressorService
- **Agent :** -
- **Notes :** -
### 6.2 Mettre en place les tests fonctionnels (API)
- **Statut :** `[ ]`
- **Fichiers a creer :**
- `tests/Functional/Api/MachineTest.php`
- `tests/Functional/Api/ProductTest.php`
- `tests/Functional/Api/AuthenticationTest.php`
- `tests/Functional/Api/MachineSkeletonTest.php`
- **Action :**
1. Configurer une base de test (SQLite ou PostgreSQL de test)
2. Creer des fixtures de test
3. Tester les endpoints CRUD
4. Tester l'authentification JWT
5. Tester les endpoints custom (skeleton, custom fields)
- **Agent :** -
- **Notes :** Utiliser `ApiTestCase` de API Platform.
### 6.3 Tests des Audit Subscribers
- **Statut :** `[ ]`
- **Fichiers a creer :**
- `tests/Unit/EventSubscriber/AuditSubscriberTest.php`
- **Action :**
1. Tester la creation de logs sur insert/update/delete
2. Tester le format des diffs et snapshots
3. Tester la resolution de l'acteur
- **Agent :** -
- **Notes :** A faire APRES la phase 2.1 (refacto des subscribers).
---
## Phase 7 - Nett oyage et conventions
> **Priorite :** BASSE - Polish final
### 7.1 Supprimer les fichiers inutiles
- **Statut :** `[ ]`
- **Fichiers a verifier :**
- `frontend/` (dossier legacy ? vs `Inventory_frontend/`)
- `src/ApiResource/` (repertoire vide)
- Fichiers SQL a la racine (`backup_v1.0.0.sql`, `data_norm.sql`, `fullasse.sql`, `fulldata.sql`)
- **Action :** Confirmer avec l'equipe quels fichiers sont obsoletes et les supprimer.
- **Agent :** -
- **Notes :** Ne pas supprimer sans validation.
### 7.2 Uniformiser la gestion des null
- **Statut :** `[ ]`
- **Fichiers :** Toutes les entites dans `src/Entity/`
- **Action :** S'assurer que les types nullable sont coherents entre PHP et la BDD (colonnes NOT NULL vs nullable).
- **Agent :** -
- **Notes :** -
---
---
# FRONTEND (`Inventory_frontend/`)
---
## Phase F1 - Decoupage des mega-composants (CRITIQUE)
> **Priorite :** MAXIMALE - Les fichiers actuels sont inmaintenables
### F1.1 Decouper `machine/[id].vue` (2989 LOC → 219 LOC)
- **Statut :** `[x]`
- **Fichier :** `Inventory_frontend/app/pages/machine/[id].vue`
- **Resultat :** Page decomposee en 2 composables + 7 composants. Orchestrateur = 219 LOC.
- **Fichiers crees :**
- `composables/useMachineDetailData.ts` (1404 LOC) — state + logique metier
- `composables/useMachineSkeletonEditor.ts` (843 LOC) — logique skeleton
- `components/machine/MachineDetailHeader.vue` (76 LOC)
- `components/machine/MachineInfoCard.vue` (185 LOC)
- `components/machine/MachineDocumentsCard.vue` (116 LOC)
- `components/machine/MachineProductsCard.vue` (62 LOC)
- `components/machine/MachineComponentsCard.vue` (53 LOC)
- `components/machine/MachinePiecesCard.vue` (34 LOC)
- `components/machine/MachineSkeletonSummary.vue` (199 LOC)
- **Pattern :** Props + Events (pas de provide/inject). Composables avec injection de dependances (interface Deps).
- **Notes :** Typecheck 0 erreurs. Lint OK.
### F1.2 Decouper `machines/new.vue` (1231 LOC → 196 LOC)
- **Statut :** `[x]`
- **Fichier :** `Inventory_frontend/app/pages/machines/new.vue`
- **Resultat :** Page decomposee en 1 composable + 5 composants. Orchestrateur = 196 LOC.
- **Fichiers crees :**
- `composables/useMachineCreatePage.ts` (460 LOC) — state, entity lookups, options, creation
- `components/machine/create/RequirementComponentSelector.vue` (126 LOC)
- `components/machine/create/RequirementPieceSelector.vue` (130 LOC)
- `components/machine/create/RequirementProductSelector.vue` (142 LOC)
- `components/machine/create/MachineCreatePreview.vue` (205 LOC)
- `components/machine/create/PreviewRequirementGroup.vue` (59 LOC)
- **Pattern :** Props + Events. Composable consolide entity lookups, options, label helpers, creation.
- **Notes :** Typecheck 0 erreurs. Lint OK. Corrige aussi un bug F1.1 (defineProps dans mauvais script block de MachineSkeletonSummary.vue).
### F1.3 Decouper les pages de creation/edition (Piece, Component, Product)
- **Statut :** `[x]`
- **Fichiers :**
- `pages/component/create.vue` (1282 LOC)
- `pages/component/[id]/edit.vue` (1629 LOC)
- `pages/pieces/create.vue` (817 LOC)
- `pages/pieces/[id]/edit.vue` (1327 LOC)
- `pages/product/[id]/edit.vue` (936 LOC)
- **Probleme :** Formulaires monolithiques avec sections multiples (infos generales, fournisseurs, documents, custom fields, etc.).
- **Action :**
1. Identifier les sections communes entre create/edit (factoriser)
2. Extraire chaque section en composant reutilisable :
- `EntityFormGeneral.vue` (nom, reference, description)
- `EntityFormSuppliers.vue` (constructeurs)
- `EntityFormDocuments.vue` (documents)
- `EntityFormCustomFields.vue` (champs personnalises)
3. Objectif par page : <400 LOC
- **Agent :** -
- **Notes :** Les formulaires create et edit partagent beaucoup de code. Factoriser.
- **Sous-taches :**
- [x] F1.3a Extraire `customFieldFormUtils.ts` (duplique dans 5 fichiers)
- [x] F1.3b Extraire `documentDisplayUtils.ts` (duplique dans 3 pages edit)
- [x] F1.3c Extraire `historyDisplayUtils.ts` (duplique dans 3 pages edit)
- [x] F1.3d Rewire les 5 pages create/edit sur les modules extraits
- [x] F1.3e Typecheck + commit F1.3 (erreurs F1.3 corrigees, 120 erreurs preexistantes documentees)
### F1.4 Reduire PieceItem.vue (1588 LOC) et ComponentItem.vue (1336 LOC)
- **Statut :** `[x]`
- **Fichiers :**
- `Inventory_frontend/app/components/PieceItem.vue` (1588 → 740 LOC)
- `Inventory_frontend/app/components/ComponentItem.vue` (1336 → 585 LOC)
- **Probleme :** ~700 LOC de logique dupliquee entre les deux composants (champs personnalises, documents, affichage produit).
- **Action realisee :**
1. Extraction de la logique pure custom fields dans `shared/utils/entityCustomFieldLogic.ts` (~350 LOC)
2. Creation de `composables/useEntityCustomFields.ts` (composable reactif, ~180 LOC)
3. Creation de `composables/useEntityDocuments.ts` (CRUD documents + preview, ~120 LOC)
4. Creation de `composables/useEntityProductDisplay.ts` (affichage produit, ~100 LOC)
5. Import des helpers document depuis `shared/utils/documentDisplayUtils.ts` (existant)
6. Rewrite des deux composants pour utiliser les modules partages
7. Typecheck 0 erreurs, lint 0 erreurs
- **Sous-taches :**
- [x] F1.4a Extraire `entityCustomFieldLogic.ts` (fonctions pures)
- [x] F1.4b Creer `useEntityCustomFields.ts` (composable reactif)
- [x] F1.4c Creer `useEntityDocuments.ts` (composable documents)
- [x] F1.4d Creer `useEntityProductDisplay.ts` (composable produit)
- [x] F1.4e Rewrite ComponentItem.vue (1336 → 585 LOC, script 900 → 150 LOC)
- [x] F1.4f Rewrite PieceItem.vue (1588 → 740 LOC, script 1100 → 255 LOC)
- [x] F1.4g Typecheck + lint (0 erreurs)
- **Notes :** Les templates restent volumineux (~430-480 LOC) car le contenu UI est dense. Une extraction en sous-composants (DocumentList, ProductDisplay, CustomFieldForm) serait une etape future optionnelle.
---
## Phase F2 - Elimination de la duplication frontend
> **Priorite :** HAUTE - DRY
### F2.1 Extraire `extractCollection()` dans un utilitaire partage
- **Statut :** `[x]`
- **Fichiers concernes :**
- `composables/useSites.ts`
- `composables/useProducts.ts`
- `composables/usePieces.ts`
- `composables/useComposants.ts`
- `composables/useMachineTypesApi.js`
- `composables/useConstructeurs.ts`
- `composables/useDocuments.ts`
- `composables/useMachineCreateSelections.ts`
- `components/ComponentStructureAssignmentNode.vue`
- `components/model-types/ManagementView.vue`
- **Probleme :** La fonction `extractCollection()` (parsing `hydra:member` / `member` / `items` / `data` / array) etait dupliquee dans 10 fichiers.
- **Action :**
1. [x] Creer `shared/utils/apiHelpers.ts` avec `extractCollection<T>()` generique
2. [x] Remplacer les 10 implementations locales par un import
- **Agent :** -
- **Notes :** Gere aussi `items` (utilise par ManagementView.vue). `extractRelationId()` et `normalizeRelationIds()` restent dans `shared/apiRelations.ts` (deja partages).
### F2.2 Fusionner les 3 composables d'historique
- **Statut :** `[x]`
- **Fichiers concernes :**
- `composables/useComponentHistory.ts` (67 → 13 LOC, thin wrapper)
- `composables/usePieceHistory.ts` (67 → 13 LOC, thin wrapper)
- `composables/useProductHistory.ts` (67 → 13 LOC, thin wrapper)
- `composables/useEntityHistory.ts` (NEW, 65 LOC, logique generique)
- **Probleme :** 3 fichiers quasi identiques (seul le endpoint differait).
- **Action :**
1. [x] Creer `composables/useEntityHistory.ts` parametrable par type d'entite
2. [x] Reecrire les 3 fichiers specifiques en wrappers backward-compatible
- **Agent :** -
- **Notes :** Les wrappers preservent l'API existante (types + fonction), aucun consommateur a modifier.
### F2.3 Factoriser les composables de types (Component/Piece/Product)
- **Statut :** `[x]`
- **Fichiers concernes :**
- `composables/useComponentTypes.ts` (165 → 30 LOC, thin wrapper)
- `composables/usePieceTypes.ts` (165 → 30 LOC, thin wrapper)
- `composables/useProductTypes.ts` (160 → 28 LOC, thin wrapper)
- `composables/useEntityTypes.ts` (NEW, 172 LOC, logique generique)
- **Probleme :** 3 composables tres similaires pour gerer les categories/types.
- **Action :**
1. [x] Creer `composables/useEntityTypes.ts` generique (CRUD + singleton state par categorie)
2. [x] Reecrire les 3 fichiers specifiques en wrappers avec renommage des champs
- **Agent :** -
- **Notes :** Les wrappers renomment `types``componentTypes`/`pieceTypes`/`productTypes`, preservent `getXxxTypes()` et `isXxxTypeLoading()`. Etat partage via `stateByCategory` map module-level.
---
## Phase F3 - Migration TypeScript
> **Priorite :** HAUTE - Securite du typage
### F3.1 Definir les types pour les reponses API
- **Statut :** `[x]` (partiellement — types definis dans chaque composable + `ApiResponse<T>` dans useApi.ts)
- **Fichiers :**
- `composables/useApi.ts``ApiResponse<T>` generique (success/data/error/status)
- `composables/useMachines.ts``Machine` interface
- `composables/useMachineTypesApi.ts``MachineType`, `MachineTypeRequirement` interfaces
- `composables/useToast.ts``Toast`, `ToastType` types
- `composables/useProfiles.ts``Profile` interface
- `composables/useCustomFields.ts``CustomFieldValue` interface
- **Notes :** Les types sont definis dans chaque composable (colocation). Types entite existants : `Product`, `Piece`, `Composant`, `Constructeur`, `Site`, `Document` dans leurs composables respectifs (.ts). `shared/types/inventory.ts` contient les types de structure de modele.
### F3.2 Convertir les composables JS en TS
- **Statut :** `[x]`
- **Fichiers convertis (7 fichiers JS → TS) :**
- [x] `useToast.js``useToast.ts` (72 LOC, types: `Toast`, `ToastType`)
- [x] `useProfiles.js``useProfiles.ts` (68 LOC, type: `Profile`)
- [x] `useProfileSession.js``useProfileSession.ts` (85 LOC, importe `Profile`)
- [x] `useApi.js``useApi.ts` (106 LOC → 120 LOC, types: `ApiResponse<T>`, `ApiCallOptions`, ajout `put()`)
- [x] `useCustomFields.js``useCustomFields.ts` (105 LOC, type: `CustomFieldValue`)
- [x] `useMachineTypesApi.js``useMachineTypesApi.ts` (173 → 188 LOC, types: `MachineType`, `MachineTypeRequirement`)
- [x] `useMachines.js``useMachines.ts` (267 LOC, type: `Machine`, utilise `extractCollection`)
- **Fichiers deja TS :** `useProducts.ts`, `usePieces.ts`, `useComposants.ts`, `useConstructeurs.ts`, `useSites.ts`, `useDocuments.ts`
- **Fichiers JS restants (deprecated) :** `useComponentModels.js`, `usePieceModels.js` (stubs deprecated, a supprimer)
- **Notes :** `ApiResponse<T = any>` par defaut `any` pour backward-compat. Les callers existants fonctionnent sans changement ; le nouveau code peut opt-in strict via `get<MyType>()`.
### F3.3 Eliminer les `any` restants
- **Statut :** `[x]`
- **Fichiers concernes :**
- `components/ProductSelect.vue` — 1 `any` restant (slot template, incompressible)
- `components/model-types/ManagementView.vue` — remplace `data?: any``Record<string, unknown>`, `error: any``error: unknown`, `item: any``item: unknown`
- `components/ComponentStructureAssignmentNode.vue` — 12 casts `(definition as any).typePiece/typeProduct` elimines grace a l'extension des types
- `components/ComponentModelStructureEditor.vue``Promise<any>``Promise<unknown>`
- `components/model-types/ModelTypeForm.vue``(incoming as any).description` → cast `Record<string, unknown>`
- `shared/types/inventory.ts``ComponentModelPiece.typePiece?` et `ComponentModelProduct.typeProduct?` ajoutes, 3 casts `(value as any)` supprimes
- **Probleme :** 20+ usages de `any` type identifies.
- **Action :** Etendre les interfaces de types pour supporter les formes alternatives de l'API. Remplacer les `any` par `unknown` ou `Record<string, unknown>` la ou possible.
- **Agent :** Claude
- **Notes :** ~15 casts `any` elimines. Les `Record<string, any>` restants dans ComponentModelStructureEditor sont justifies (manipulation dynamique interne de custom fields). Typecheck 0 erreurs.
---
## Phase F4 - Qualite du code frontend
> **Priorite :** MOYENNE
### F4.1 Activer les regles ESLint critiques
- **Statut :** `[x]` DONE
- **Fichier :** `Inventory_frontend/eslint.config.mjs`
- **Probleme :** Presque toutes les regles etaient desactivees (`no-console: off`, `no-unused-vars: off`, `no-explicit-any: off`).
- **Action realisee :**
1. [x] Active `@typescript-eslint/no-explicit-any: warn` (526 warnings — amelioration progressive)
2. [x] Active `no-console: warn` avec `allow: ['error']` — 0 violations (deja nettoye en F4.2)
3. [x] Active `@typescript-eslint/no-unused-vars: warn` avec ignore `^_` — 0 violations (26 corrigees)
4. [x] Corrige les 26 violations `no-unused-vars` : imports inutilises supprimes, variables prefixees `_`, destructurations nettoyees
- **Agent :** Claude
- **Notes :** 16 fichiers modifies. Regles organisees par categorie (vue, console, typescript, formatting). 0 erreurs, 526 warnings `no-explicit-any` restants (warn, pas bloquant).
### F4.2 Nettoyer les console.log/console.error
- **Statut :** `[x]` (console.log supprime, console.error conserve)
- **Fichiers modifies :** 8 fichiers (useMachineTypesApi.ts, useSites.ts, type/[id].vue, type/edit/[id].vue, TypeEditPieceRequirementsSection.vue, SearchSelect.vue, app.vue)
- **Probleme :** 19 appels `console.log` de debug laisses dans le code de production.
- **Action :**
1. [x] Supprimer les 19 `console.log` de debug (normalizeRequirementList, page loading, route params, etc.)
2. [ ] Les 72 `console.error` restants sont conserves (gestion d'erreur legitime). Migration vers un logger centralise a faire en F4.3.
- **Agent :** Claude
- **Notes :** 0 `console.log/warn/debug/info` restants dans le frontend.
### F4.3 Centraliser la gestion d'erreurs API
- **Statut :** `[ ]`
- **Fichier :** `Inventory_frontend/app/composables/useApi.js` (105 LOC)
- **Probleme :** Gestion d'erreur basique (juste un toast). Pas de retry, pas d'intercepteur, erreurs silencieuses dans certains composables.
- **Action :**
1. Ajouter un systeme de retry configurable (1-3 tentatives)
2. Centraliser la gestion des erreurs HTTP (401 -> redirect login, 500 -> message explicite)
3. Ajouter des intercepteurs request/response
4. Uniformiser le pattern dans tous les composables
- **Agent :** -
- **Notes :** -
---
## Phase F5 - Reduire le fichier modelUtils.ts (1017 LOC)
> **Priorite :** MOYENNE
### F5.1 Decouper `shared/modelUtils.ts`
- **Statut :** `[x]`
- **Fichier :** `Inventory_frontend/app/shared/modelUtils.ts` (1017 LOC → 37 LOC barrel)
- **Probleme :** Fichier utilitaire monolithique de 1017 lignes regroupant toute la logique de manipulation de modeles.
- **Action :**
1. Identifier les groupes de fonctions (structure, custom fields, requirements, serialization)
2. Decouper en 3 modules thematiques :
- `shared/model/componentStructure.ts` (~590 LOC) — helpers, sanitize, hydrate, normalize, extract, format pour composants
- `shared/model/pieceProductStructure.ts` (~155 LOC) — structure piece/produit (clone, sanitize, hydrate, format)
- `shared/model/definitionOverrides.ts` (~50 LOC) — sanitization des overrides de definition
3. Re-exporter depuis `shared/modelUtils.ts` (barrel) pour ne pas casser les imports
- **Agent :** Claude
- **Notes :** 11 fichiers consommateurs inchanges (barrel preserve la retro-compat). Typecheck 0 erreurs.
---
## Phase F6 - Tests frontend
> **Priorite :** HAUTE - Aucun test actuellement
### F6.1 Configurer Vitest
- **Statut :** `[x]` DONE
- **Fichiers crees :**
- `vitest.config.ts` — config Vitest avec happy-dom, alias `~` et `#imports`
- `tests/__mocks__/imports.ts` — mock des auto-imports Nuxt (useRuntimeConfig, useRoute, etc.)
- `tests/shared/inventory-types.test.ts` — 9 tests smoke (validator, empty structures)
- **Action realisee :**
1. [x] Installe `vitest`, `@vue/test-utils`, `happy-dom`
2. [x] Configure Vitest avec environment happy-dom et resolution d'alias
3. [x] Ajoute scripts `test` et `test:watch` dans `package.json`
4. [x] Premier test suite : `componentModelStructureValidator` (9 tests, 100% pass)
- **Agent :** Claude
- **Notes :** `npm test` → 9 tests, 0 failures, <1s. Alias `#imports` pointe vers un mock minimal extensible.
### F6.2 Tests unitaires des composables
- **Statut :** `[x]` DONE (base)
- **Fichiers crees :**
- `tests/shared/apiHelpers.test.ts` — 10 tests (extractCollection, tous formats API)
- `tests/shared/modelUtils.test.ts` — 18 tests (isPlainObject, clone, stats, format, piece/product)
- `tests/shared/inventory-types.test.ts` — 9 tests (validator, empty structures)
- `tests/composables/useToast.test.ts` — 9 tests (add, types, max limit, clear, singleton)
- `tests/composables/useConfirm.test.ts` — 8 tests (open, confirm, cancel, options, singleton)
- **Action realisee :**
1. [x] Teste `extractCollection()` : array, hydra:member, member, items, data, null, undefined
2. [x] Teste `useToast` : ajout, types, max 3 toasts, clearAll, removeToast, singleton
3. [x] Teste `useConfirm` : open/close, resolve true/false, custom options, singleton state
4. [x] Teste `modelUtils` : clone, stats, preview, isPlainObject, piece/product variants
5. [x] Teste `componentModelStructureValidator` : valid/invalid, custom fields, subcomponents
- **Agent :** Claude
- **Notes :** 54 tests, 5 fichiers, 100% pass, <2s. Tests `useApi` et CRUD composables necessitent mock fetch (phase ulterieure).
### F6.3 Tests de composants
- **Statut :** `[ ]`
- **Fichiers a creer :**
- `tests/components/Pagination.test.ts`
- `tests/components/SearchSelect.test.ts`
- `tests/components/MachineHeader.test.ts` (apres F1.1)
- **Action :**
1. Tester les composants communs (Pagination, SearchSelect)
2. Tester le rendu conditionnel et les events
- **Agent :** -
- **Notes :** -
---
## Phase F7 - Ameliorations UX/DX
> **Priorite :** BASSE - Polish
### F7.1 Reduire le props drilling
- **Statut :** `[ ]`
- **Probleme :** Props passees sur 3+ niveaux (ex: machine data dans les sous-composants).
- **Action :**
1. Identifier les cas de props drilling >2 niveaux
2. Utiliser `provide/inject` ou des composables partages
3. Documenter le pattern choisi
- **Agent :** -
- **Notes :** A traiter apres F1 (decoupage des composants).
### F7.2 Remplacer `confirm()` natif par des modales DaisyUI
- **Statut :** `[x]` DONE
- **Probleme :** Les confirmations de suppression utilisaient `window.confirm()` (UI native, non-stylee).
- **Action realisee :**
1. [x] Cree `composables/useConfirm.ts` — composable promise-based avec etat reactif partage
2. [x] Cree `components/common/ConfirmModal.vue` — modale DaisyUI teleportee (backdrop blur, btn-error)
3. [x] Monte `ConfirmModal` globalement dans `app.vue`
4. [x] Remplace les 10 `confirm()` natifs dans 10 fichiers :
- `constructeurs.vue`, `profiles/manage.vue`, `ManagementView.vue`
- `product-catalog.vue`, `index.vue`, `machines/index.vue`
- `machine-skeleton/index.vue`, `pieces-catalog.vue`, `component-catalog.vue`
- `useSiteManagement.ts` (composable — import explicite)
- **Agent :** Claude
- **Notes :** API : `const { confirm } = useConfirm(); const ok = await confirm({ message: '...' })`. Auto-import Nuxt pour les SFC, import explicite pour les composables.
### F7.3 Nettoyer `app.vue` (861 LOC)
- **Statut :** `[x]` DONE
- **Fichier :** `Inventory_frontend/app/app.vue` (861 → 49 LOC)
- **Probleme :** Le fichier racine contenait le layout principal, la navbar (~676 LOC dupliquee mobile/desktop), et du state management.
- **Action realisee :**
1. Cree `composables/useNavDropdown.ts` (~65 LOC) — gestion etat dropdowns navbar
2. Cree `components/layout/AppNavbar.vue` (~310 LOC) — navbar data-driven avec `v-for` eliminant duplication mobile/desktop
3. `app.vue` reecrit en orchestrateur minimal (49 LOC) + converti en TypeScript
4. Supprime 4 imports d'icones inutilises
- **Agent :** Claude
- **Notes :** Approche data-driven : liens et groupes definis comme tableaux types (`NavLink[]`, `NavGroup[]`), rendus par `v-for` pour mobile et desktop
---
## Ordre d'execution recommande
```
=== BACKEND === === FRONTEND ===
Phase 6.1 (Tests unitaires) Phase F6.1 (Config Vitest)
| |
v v
Phase 1 (Securite) Phase F1 (Decoupage mega-composants)
| |
v v
Phase 2 (Duplication backend) Phase F2 (Duplication frontend)
| |
v v
Phase 3 (Controllers) Phase F3 (Migration TypeScript)
| |
v v
Phase 6.2 (Tests API) Phase F4 (Qualite code) + Phase F5 (modelUtils)
| |
v v
Phase 4 (Stockage) Phase F6.2-F6.3 (Tests frontend)
| |
v v
Phase 5 + Phase 7 (Nettoyage) Phase F7 (UX/DX polish)
|
v
Phase 6.3 (Tests audit)
```
> Les colonnes backend et frontend peuvent etre executees **en parallele** par des agents differents.
---
## Journal des modifications
| Date | Phase | Tache | Agent | Statut | Notes |
| ---------- | ----- | ------------------------- | --------------- | ------- | ---------------------------------------------- |
| 2026-02-03 | - | Creation du plan backend | Claude Opus 4.5 | Termine | Analyse initiale backend (7 phases, 17 taches) |
| 2026-02-03 | - | Creation du plan frontend | Claude Opus 4.5 | Termine | Analyse frontend (7 phases, 22 taches) |
| | | | | | |
---
## Commandes de verification
> **Contexte :** Le backend tourne dans Docker (`docker compose`), le frontend est en local.
> Les commandes ci-dessous sont executees **depuis la racine du projet** (`/home/matthieu/dev_malio/Inventory/`).
### Frontend (Nuxt 3 / Vue 3 / TypeScript)
| Commande | Description | Quand l'utiliser |
| -------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `npx nuxi typecheck` | Verification des types TypeScript via `vue-tsc` | Apres chaque modification de fichier `.vue` ou `.ts`. C'est la commande principale de validation. |
| `npm run lint` | ESLint (config dans `eslint.config.mjs`) | Apres chaque modification pour verifier le style et les erreurs statiques. |
| `npm run lint:fix` | ESLint avec auto-fix | Pour corriger automatiquement les erreurs de formatage. |
| `npm run build` | Build de production Nuxt (inclut le typecheck) | Avant un commit pour s'assurer que tout compile. Plus lent que `typecheck` seul. |
| `npx nuxi prepare` | Regenerer les types auto-generes (`.nuxt/`) | Si les imports auto (composables, components) ne sont pas reconnus par le typecheck. |
> **Toutes les commandes frontend** sont executees depuis `Inventory_frontend/` :
>
> ```bash
> cd Inventory_frontend && npx nuxi typecheck
> ```
> **Note sur les erreurs pre-existantes :** Il y a ~120 erreurs TypeScript pre-existantes documentees
> (anterieures a la refacto). L'objectif est de ne pas en ajouter de nouvelles.
> Pour verifier : comparer le nombre d'erreurs avant/apres modification.
### Backend (Symfony 8 / PHP 8.4)
| Commande | Description | Quand l'utiliser |
| ---------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------- |
| `vendor/bin/php-cs-fixer fix --dry-run --diff` | Verifie le style PHP (PSR-12 + Symfony) sans modifier | Apres chaque modification PHP. |
| `vendor/bin/php-cs-fixer fix` | Corrige automatiquement le style PHP | Avant chaque commit. |
| `bin/phpunit` | Lance les tests PHPUnit | Apres chaque modification backend. |
| `php bin/console cache:clear` | Vide le cache Symfony | Si des erreurs bizarres apparaissent apres un changement de config. |
> **Les commandes backend** sont executees **dans le conteneur Docker** :
>
> ```bash
> docker compose exec web vendor/bin/php-cs-fixer fix --dry-run --diff
> docker compose exec web bin/phpunit
> ```
### Workflow de verification (checklist par tache)
```
1. Lire les fichiers concernes (AVANT toute modification)
2. Effectuer les modifications
3. Frontend : npx nuxi typecheck → verifier pas de nouvelles erreurs
4. Frontend : npm run lint:fix → corriger le formatage
5. Backend : php-cs-fixer fix → corriger le style PHP
6. Backend : bin/phpunit → verifier la non-regression
7. Commit si tout est OK
```
---
## Regles pour les agents
1. **Avant de commencer une tache :**
- Mettre le statut a `[~]` dans ce fichier
- Inscrire son nom/ID dans la colonne "Agent"
- Lire les fichiers concernes AVANT de modifier quoi que ce soit
2. **Pendant le travail :**
- Ne modifier QUE les fichiers listes dans la tache
- Respecter les conventions existantes (PSR-12, strict_types)
- Ne pas introduire de nouvelles dependances sans justification
- Lancer `php-cs-fixer` apres les modifications
3. **Apres avoir termine :**
- Mettre le statut a `[x]`
- Ajouter une entree dans le "Journal des modifications"
- Lancer les tests existants (`make test`) pour verifier la non-regression
- Decrire brievement les changements effectues dans "Notes"
4. **En cas de blocage :**
- Mettre le statut a `[!]`
- Documenter le blocage dans "Notes"
- Ne PAS passer a une autre tache sans signaler le blocage
5. **Regles specifiques au frontend :**
- Ecrire en TypeScript (pas de JS pour les nouveaux fichiers)
- Pas de `any` - utiliser des types concrets
- Pas de `console.log` - utiliser le logger ou `useToast`
- Composants Vue : max 400 LOC par fichier
- Utiliser les composants DaisyUI existants (pas de CSS custom)
- Tester avec Vitest quand la config est en place
6. **Regles specifiques au backend :**
- `declare(strict_types=1)` obligatoire
- Respecter PSR-12 + regles Symfony (php-cs-fixer)
- Pas de `exec()` direct - utiliser Symfony Process
- Tester avec PHPUnit

View File

@@ -1 +1 @@
1.2.0 1.3.0

View File

@@ -1,6 +1,6 @@
api_platform: api_platform:
title: Hello API Platform title: Hello API Platform
version: 1.2.0 version: 1.3.0
defaults: defaults:
stateless: false stateless: false
cache_headers: cache_headers:

24
frontend/.gitignore vendored
View File

@@ -1,24 +0,0 @@
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist
# Node dependencies
node_modules
# Logs
logs
*.log
# Misc
.DS_Store
.fleet
.idea
# Local env files
.env
.env.*
!.env.example

View File

@@ -1,75 +0,0 @@
# Nuxt Minimal Starter
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
## Setup
Make sure to install dependencies:
```bash
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
# bun
bun install
```
## Development Server
Start the development server on `http://localhost:3000`:
```bash
# npm
npm run dev
# pnpm
pnpm dev
# yarn
yarn dev
# bun
bun run dev
```
## Production
Build the application for production:
```bash
# npm
npm run build
# pnpm
pnpm build
# yarn
yarn build
# bun
bun run build
```
Locally preview production build:
```bash
# npm
npm run preview
# pnpm
pnpm preview
# yarn
yarn preview
# bun
bun run preview
```
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.

View File

@@ -1,3 +0,0 @@
<template>
<NuxtPage/>
</template>

View File

@@ -1,9 +0,0 @@
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
ssr: false,
modules: ['@nuxtjs/tailwindcss'],
typescript: {
strict: true
}
})

11892
frontend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +0,0 @@
{
"name": "frontend",
"type": "module",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare",
"build:dist": "nuxt generate && rm -rf dist && cp -R .output/public dist"
},
"dependencies": {
"nuxt": "^4.2.2",
"vue": "^3.5.26",
"vue-router": "^4.6.4"
},
"devDependencies": {
"@nuxtjs/tailwindcss": "^6.14.0"
}
}

View File

@@ -1,9 +0,0 @@
<template>
<div class="min-h-screen flex items-center justify-center">
<h1 class="text-3xl font-bold">Nuxt OK </h1>
</div>
</template>
<script setup lang="ts">
</script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,2 +0,0 @@
User-Agent: *
Disallow:

View File

@@ -1,18 +0,0 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"files": [],
"references": [
{
"path": "./.nuxt/tsconfig.app.json"
},
{
"path": "./.nuxt/tsconfig.server.json"
},
{
"path": "./.nuxt/tsconfig.shared.json"
},
{
"path": "./.nuxt/tsconfig.node.json"
}
]
}