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>
This commit is contained in:
Matthieu
2026-02-09 11:20:55 +01:00
parent ba1114e78b
commit bf55034b2e
2 changed files with 425 additions and 320 deletions

View File

@@ -9,7 +9,7 @@
## Legende des statuts ## Legende des statuts
| Statut | Signification | | Statut | Signification |
|--------|--------------| | ------ | ---------------------- |
| `[ ]` | A faire | | `[ ]` | A faire |
| `[~]` | En cours | | `[~]` | En cours |
| `[x]` | Termine | | `[x]` | Termine |
@@ -22,6 +22,7 @@
> **Priorite :** MAXIMALE - A traiter en premier > **Priorite :** MAXIMALE - A traiter en premier
### 1.1 Corriger la configuration de securite ### 1.1 Corriger la configuration de securite
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichier :** `config/packages/security.yaml` - **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. - **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.
@@ -30,6 +31,7 @@
- **Notes :** - - **Notes :** -
### 1.2 Ajouter les controles d'autorisation sur les controllers ### 1.2 Ajouter les controles d'autorisation sur les controllers
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers :** - **Fichiers :**
- `src/Controller/MachineSkeletonController.php` - `src/Controller/MachineSkeletonController.php`
@@ -44,6 +46,7 @@
- **Notes :** - - **Notes :** -
### 1.3 Securiser les secrets ### 1.3 Securiser les secrets
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers :** - **Fichiers :**
- `.env` (JWT_PASSPHRASE en dur, APP_SECRET vide) - `.env` (JWT_PASSPHRASE en dur, APP_SECRET vide)
@@ -63,6 +66,7 @@
> **Priorite :** HAUTE - Impact direct sur la maintenabilite > **Priorite :** HAUTE - Impact direct sur la maintenabilite
### 2.1 Refactorer les 3 Audit Subscribers en un seul generique ### 2.1 Refactorer les 3 Audit Subscribers en un seul generique
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers concernes :** - **Fichiers concernes :**
- `src/EventSubscriber/ProductAuditSubscriber.php` (298 LOC) - `src/EventSubscriber/ProductAuditSubscriber.php` (298 LOC)
@@ -79,6 +83,7 @@
- **Notes :** Tester manuellement les logs d'audit apres refacto. - **Notes :** Tester manuellement les logs d'audit apres refacto.
### 2.2 Extraire un CuidGenerator utilitaire ### 2.2 Extraire un CuidGenerator utilitaire
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers concernes :** 18 entites contenant `generateCuid()` en prive - **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). - **Probleme :** Methode `generateCuid()` dupliquee dans chaque entite. De plus, `AuditLog.php` utilise une variante differente (base_convert).
@@ -91,6 +96,7 @@
- **Notes :** Attention a l'inconsistance entre AuditLog et les autres entites. - **Notes :** Attention a l'inconsistance entre AuditLog et les autres entites.
### 2.3 Factoriser la logique de liaison dans MachineSkeletonController ### 2.3 Factoriser la logique de liaison dans MachineSkeletonController
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichier :** `src/Controller/MachineSkeletonController.php` (756 LOC) - **Fichier :** `src/Controller/MachineSkeletonController.php` (756 LOC)
- **Probleme :** Les methodes `applyComponentLinks()`, `applyPieceLinks()`, `applyProductLinks()` sont quasi identiques (~90 LOC chacune). - **Probleme :** Les methodes `applyComponentLinks()`, `applyPieceLinks()`, `applyProductLinks()` sont quasi identiques (~90 LOC chacune).
@@ -108,6 +114,7 @@
> **Priorite :** MOYENNE - Amelioration de la lisibilite et maintenabilite > **Priorite :** MOYENNE - Amelioration de la lisibilite et maintenabilite
### 3.1 Decouper MachineSkeletonController ### 3.1 Decouper MachineSkeletonController
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichier :** `src/Controller/MachineSkeletonController.php` (756 LOC) - **Fichier :** `src/Controller/MachineSkeletonController.php` (756 LOC)
- **Action :** - **Action :**
@@ -119,6 +126,7 @@
- **Notes :** Depend de la phase 2.3 (factorisation des liens). - **Notes :** Depend de la phase 2.3 (factorisation des liens).
### 3.2 Ajouter un try-catch et du logging dans les controllers ### 3.2 Ajouter un try-catch et du logging dans les controllers
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers :** Tous les controllers dans `src/Controller/` - **Fichiers :** Tous les controllers dans `src/Controller/`
- **Probleme :** Aucun try-catch autour des `flush()` et `persist()`. Pas de logging d'erreurs. - **Probleme :** Aucun try-catch autour des `flush()` et `persist()`. Pas de logging d'erreurs.
@@ -130,6 +138,7 @@
- **Notes :** - - **Notes :** -
### 3.3 Renforcer la validation des entrees ### 3.3 Renforcer la validation des entrees
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers :** - **Fichiers :**
- `src/Controller/CustomFieldValueController.php` - `src/Controller/CustomFieldValueController.php`
@@ -149,6 +158,7 @@
> **Priorite :** MOYENNE - Performance et scalabilite > **Priorite :** MOYENNE - Performance et scalabilite
### 4.1 Migrer le stockage PDF de base64 vers le filesystem ### 4.1 Migrer le stockage PDF de base64 vers le filesystem
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers :** - **Fichiers :**
- `src/Entity/Document.php` - `src/Entity/Document.php`
@@ -165,6 +175,7 @@
- **Notes :** Prevoir une migration de donnees pour les documents existants. - **Notes :** Prevoir une migration de donnees pour les documents existants.
### 4.2 Corriger les types de prix (string -> decimal) ### 4.2 Corriger les types de prix (string -> decimal)
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers :** - **Fichiers :**
- `src/Entity/Machine.php` (`$prix`) - `src/Entity/Machine.php` (`$prix`)
@@ -184,6 +195,7 @@
> **Priorite :** BASSE - Bonne pratique > **Priorite :** BASSE - Bonne pratique
### 5.1 Remplacer exec() par Symfony Process ### 5.1 Remplacer exec() par Symfony Process
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers :** - **Fichiers :**
- `src/Command/CompressPdfCommand.php` (lignes 42, 98-101) - `src/Command/CompressPdfCommand.php` (lignes 42, 98-101)
@@ -203,6 +215,7 @@
> **Priorite :** HAUTE - Indispensable avant toute refacto majeure > **Priorite :** HAUTE - Indispensable avant toute refacto majeure
### 6.1 Mettre en place les tests unitaires ### 6.1 Mettre en place les tests unitaires
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers a creer :** - **Fichiers a creer :**
- `tests/Unit/Util/CuidGeneratorTest.php` - `tests/Unit/Util/CuidGeneratorTest.php`
@@ -217,6 +230,7 @@
- **Notes :** - - **Notes :** -
### 6.2 Mettre en place les tests fonctionnels (API) ### 6.2 Mettre en place les tests fonctionnels (API)
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers a creer :** - **Fichiers a creer :**
- `tests/Functional/Api/MachineTest.php` - `tests/Functional/Api/MachineTest.php`
@@ -233,6 +247,7 @@
- **Notes :** Utiliser `ApiTestCase` de API Platform. - **Notes :** Utiliser `ApiTestCase` de API Platform.
### 6.3 Tests des Audit Subscribers ### 6.3 Tests des Audit Subscribers
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers a creer :** - **Fichiers a creer :**
- `tests/Unit/EventSubscriber/AuditSubscriberTest.php` - `tests/Unit/EventSubscriber/AuditSubscriberTest.php`
@@ -250,6 +265,7 @@
> **Priorite :** BASSE - Polish final > **Priorite :** BASSE - Polish final
### 7.1 Supprimer les fichiers inutiles ### 7.1 Supprimer les fichiers inutiles
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers a verifier :** - **Fichiers a verifier :**
- `frontend/` (dossier legacy ? vs `Inventory_frontend/`) - `frontend/` (dossier legacy ? vs `Inventory_frontend/`)
@@ -260,6 +276,7 @@
- **Notes :** Ne pas supprimer sans validation. - **Notes :** Ne pas supprimer sans validation.
### 7.2 Uniformiser la gestion des null ### 7.2 Uniformiser la gestion des null
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers :** Toutes les entites dans `src/Entity/` - **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). - **Action :** S'assurer que les types nullable sont coherents entre PHP et la BDD (colonnes NOT NULL vs nullable).
@@ -278,39 +295,41 @@
> **Priorite :** MAXIMALE - Les fichiers actuels sont inmaintenables > **Priorite :** MAXIMALE - Les fichiers actuels sont inmaintenables
### F1.1 Decouper `machine/[id].vue` (4308 LOC) ### F1.1 Decouper `machine/[id].vue` (2989 LOC → 219 LOC)
- **Statut :** `[ ]`
- **Fichier :** `Inventory_frontend/app/pages/machine/[id].vue`
- **Probleme :** Page monolithique de 4308 lignes. Contient la vue detail, l'edition, la gestion du skeleton, les composants, les pieces, les produits, les documents, l'historique.
- **Action :**
1. Identifier les sections logiques (header, detail, skeleton, composants, pieces, produits, documents, historique)
2. Extraire chaque section en composant dedie :
- `components/machine/MachineHeader.vue`
- `components/machine/MachineDetail.vue`
- `components/machine/MachineSkeletonEditor.vue`
- `components/machine/MachineComponentsList.vue`
- `components/machine/MachinePiecesList.vue`
- `components/machine/MachineProductsList.vue`
- `components/machine/MachineDocuments.vue`
- `components/machine/MachineHistory.vue`
3. La page `[id].vue` ne doit plus etre qu'un orchestrateur (<300 LOC)
4. Utiliser `provide/inject` ou un composable partage pour l'etat machine
- **Agent :** -
- **Notes :** Tache la plus impactante du frontend. A faire en premier.
### F1.2 Decouper `machines/new.vue` (2313 LOC) - **Statut :** `[x]`
- **Statut :** `[ ]` - **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` - **Fichier :** `Inventory_frontend/app/pages/machines/new.vue`
- **Probleme :** Page de creation de machine avec selection de type et heritage de structure, trop volumineuse. - **Resultat :** Page decomposee en 1 composable + 5 composants. Orchestrateur = 196 LOC.
- **Action :** - **Fichiers crees :**
1. Extraire le formulaire de creation en composant `MachineCreateForm.vue` - `composables/useMachineCreatePage.ts` (460 LOC) — state, entity lookups, options, creation
2. Extraire la selection de type en `MachineTypeSelector.vue` - `components/machine/create/RequirementComponentSelector.vue` (126 LOC)
3. Extraire l'apercu de structure en composant separe - `components/machine/create/RequirementPieceSelector.vue` (130 LOC)
4. Objectif : page <200 LOC - `components/machine/create/RequirementProductSelector.vue` (142 LOC)
- **Agent :** - - `components/machine/create/MachineCreatePreview.vue` (205 LOC)
- **Notes :** - - `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) ### F1.3 Decouper les pages de creation/edition (Piece, Component, Product)
- **Statut :** `[x]` - **Statut :** `[x]`
- **Fichiers :** - **Fichiers :**
- `pages/component/create.vue` (1282 LOC) - `pages/component/create.vue` (1282 LOC)
@@ -337,17 +356,29 @@
- [x] F1.3e Typecheck + commit F1.3 (erreurs F1.3 corrigees, 120 erreurs preexistantes documentees) - [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) ### F1.4 Reduire PieceItem.vue (1588 LOC) et ComponentItem.vue (1336 LOC)
- **Statut :** `[ ]`
- **Statut :** `[x]`
- **Fichiers :** - **Fichiers :**
- `Inventory_frontend/app/components/PieceItem.vue` (1588 LOC) - `Inventory_frontend/app/components/PieceItem.vue` (1588 → 740 LOC)
- `Inventory_frontend/app/components/ComponentItem.vue` (1336 LOC) - `Inventory_frontend/app/components/ComponentItem.vue` (1336 → 585 LOC)
- **Probleme :** Composants d'affichage/edition inline tres volumineux. - **Probleme :** ~700 LOC de logique dupliquee entre les deux composants (champs personnalises, documents, affichage produit).
- **Action :** - **Action realisee :**
1. Separer la vue lecture de la vue edition 1. Extraction de la logique pure custom fields dans `shared/utils/entityCustomFieldLogic.ts` (~350 LOC)
2. Extraire les sous-sections (details, documents, fournisseurs) en sous-composants 2. Creation de `composables/useEntityCustomFields.ts` (composable reactif, ~180 LOC)
3. Objectif : <400 LOC par composant 3. Creation de `composables/useEntityDocuments.ts` (CRUD documents + preview, ~120 LOC)
- **Agent :** - 4. Creation de `composables/useEntityProductDisplay.ts` (affichage produit, ~100 LOC)
- **Notes :** - 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.
--- ---
@@ -356,47 +387,55 @@
> **Priorite :** HAUTE - DRY > **Priorite :** HAUTE - DRY
### F2.1 Extraire `extractCollection()` dans un utilitaire partage ### F2.1 Extraire `extractCollection()` dans un utilitaire partage
- **Statut :** `[ ]`
- **Statut :** `[x]`
- **Fichiers concernes :** - **Fichiers concernes :**
- `composables/useSites.js` - `composables/useSites.ts`
- `composables/useProducts.js` - `composables/useProducts.ts`
- `composables/usePieces.js` - `composables/usePieces.ts`
- `composables/useComposants.js` - `composables/useComposants.ts`
- `composables/useMachineTypesApi.js` - `composables/useMachineTypesApi.js`
- `composables/useConstructeurs.js` - `composables/useConstructeurs.ts`
- **Probleme :** La fonction `extractCollection()` (parsing `hydra:member` / `member` / array) est dupliquee dans 6+ fichiers. - `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 :** - **Action :**
1. Creer `shared/utils/apiHelpers.ts` 1. [x] Creer `shared/utils/apiHelpers.ts` avec `extractCollection<T>()` generique
2. Y placer `extractCollection()`, `extractRelationId()`, `normalizeRelationIds()` 2. [x] Remplacer les 10 implementations locales par un import
3. Remplacer les implementations locales par un import
- **Agent :** - - **Agent :** -
- **Notes :** - - **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 ### F2.2 Fusionner les 3 composables d'historique
- **Statut :** `[ ]`
- **Statut :** `[x]`
- **Fichiers concernes :** - **Fichiers concernes :**
- `composables/useComponentHistory.ts` (67 LOC) - `composables/useComponentHistory.ts` (67 → 13 LOC, thin wrapper)
- `composables/usePieceHistory.ts` (67 LOC) - `composables/usePieceHistory.ts` (67 → 13 LOC, thin wrapper)
- `composables/useProductHistory.ts` (67 LOC) - `composables/useProductHistory.ts` (67 → 13 LOC, thin wrapper)
- **Probleme :** 3 fichiers quasi identiques (seul le endpoint differe). - `composables/useEntityHistory.ts` (NEW, 65 LOC, logique generique)
- **Probleme :** 3 fichiers quasi identiques (seul le endpoint differait).
- **Action :** - **Action :**
1. Creer `composables/useEntityHistory.ts` parametrable par type d'entite 1. [x] Creer `composables/useEntityHistory.ts` parametrable par type d'entite
2. Supprimer les 3 fichiers specifiques 2. [x] Reecrire les 3 fichiers specifiques en wrappers backward-compatible
- **Agent :** - - **Agent :** -
- **Notes :** - - **Notes :** Les wrappers preservent l'API existante (types + fonction), aucun consommateur a modifier.
### F2.3 Factoriser les composables de types (Component/Piece/Product) ### F2.3 Factoriser les composables de types (Component/Piece/Product)
- **Statut :** `[ ]`
- **Statut :** `[x]`
- **Fichiers concernes :** - **Fichiers concernes :**
- `composables/useComponentTypes.js` (140 LOC) - `composables/useComponentTypes.ts` (165 → 30 LOC, thin wrapper)
- `composables/usePieceTypes.js` (140 LOC) - `composables/usePieceTypes.ts` (165 → 30 LOC, thin wrapper)
- `composables/useProductTypes.js` (132 LOC) - `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. - **Probleme :** 3 composables tres similaires pour gerer les categories/types.
- **Action :** - **Action :**
1. Creer `composables/useEntityTypes.ts` generique 1. [x] Creer `composables/useEntityTypes.ts` generique (CRUD + singleton state par categorie)
2. Parametrer par type d'entite et endpoint 2. [x] Reecrire les 3 fichiers specifiques en wrappers avec renommage des champs
- **Agent :** - - **Agent :** -
- **Notes :** - - **Notes :** Les wrappers renomment `types``componentTypes`/`pieceTypes`/`productTypes`, preservent `getXxxTypes()` et `isXxxTypeLoading()`. Etat partage via `stateByCategory` map module-level.
--- ---
@@ -405,53 +444,46 @@
> **Priorite :** HAUTE - Securite du typage > **Priorite :** HAUTE - Securite du typage
### F3.1 Definir les types pour les reponses API ### F3.1 Definir les types pour les reponses API
- **Statut :** `[ ]`
- **Fichier a creer :** `Inventory_frontend/app/shared/types/api.ts` - **Statut :** `[x]` (partiellement — types definis dans chaque composable + `ApiResponse<T>` dans useApi.ts)
- **Probleme :** Aucun type pour les reponses API. Les composables travaillent avec `any` implicite. - **Fichiers :**
- **Action :** - `composables/useApi.ts``ApiResponse<T>` generique (success/data/error/status)
1. Definir les interfaces pour chaque entite API : - `composables/useMachines.ts``Machine` interface
- `ApiMachine`, `ApiProduct`, `ApiPiece`, `ApiComposant` - `composables/useMachineTypesApi.ts``MachineType`, `MachineTypeRequirement` interfaces
- `ApiSite`, `ApiDocument`, `ApiConstructeur` - `composables/useToast.ts``Toast`, `ToastType` types
- `ApiAuditLog`, `ApiProfile`, `ApiCustomField` - `composables/useProfiles.ts``Profile` interface
2. Definir `ApiCollectionResponse<T>` (hydra:member, totalItems, etc.) - `composables/useCustomFields.ts``CustomFieldValue` interface
3. Definir `ApiErrorResponse` - **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.
4. Typer les retours de `useApi()`
- **Agent :** -
- **Notes :** Partir de `shared/types/inventory.ts` (289 LOC) qui contient deja des types partiels.
### F3.2 Convertir les composables JS en TS ### F3.2 Convertir les composables JS en TS
- **Statut :** `[ ]`
- **Fichiers concernes (10 fichiers JS) :** - **Statut :** `[x]`
- `useApi.js` -> `useApi.ts` - **Fichiers convertis (7 fichiers JS → TS) :**
- `useMachines.js` -> `useMachines.ts` - [x] `useToast.js` `useToast.ts` (72 LOC, types: `Toast`, `ToastType`)
- `useProducts.js` -> `useProducts.ts` - [x] `useProfiles.js` `useProfiles.ts` (68 LOC, type: `Profile`)
- `usePieces.js` -> `usePieces.ts` - [x] `useProfileSession.js` `useProfileSession.ts` (85 LOC, importe `Profile`)
- `useComposants.js` -> `useComposants.ts` - [x] `useApi.js` `useApi.ts` (106 LOC → 120 LOC, types: `ApiResponse<T>`, `ApiCallOptions`, ajout `put()`)
- `useConstructeurs.js` -> `useConstructeurs.ts` - [x] `useCustomFields.js` `useCustomFields.ts` (105 LOC, type: `CustomFieldValue`)
- `useSites.js` -> `useSites.ts` - [x] `useMachineTypesApi.js` `useMachineTypesApi.ts` (173 → 188 LOC, types: `MachineType`, `MachineTypeRequirement`)
- `useDocuments.js` -> `useDocuments.ts` - [x] `useMachines.js` `useMachines.ts` (267 LOC, type: `Machine`, utilise `extractCollection`)
- `useMachineTypesApi.js` -> `useMachineTypesApi.ts` - **Fichiers deja TS :** `useProducts.ts`, `usePieces.ts`, `useComposants.ts`, `useConstructeurs.ts`, `useSites.ts`, `useDocuments.ts`
- `useCustomFields.js` -> `useCustomFields.ts` - **Fichiers JS restants (deprecated) :** `useComponentModels.js`, `usePieceModels.js` (stubs deprecated, a supprimer)
- **Action :** - **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>()`.
1. Renommer `.js` en `.ts`
2. Ajouter les types de retour, parametres, et variables reactives
3. Utiliser les types API definis en F3.1
4. Eliminer tous les `any` explicites et implicites
- **Agent :** -
- **Notes :** Depend de F3.1 (types API).
### F3.3 Eliminer les `any` restants ### F3.3 Eliminer les `any` restants
- **Statut :** `[ ]`
- **Statut :** `[x]`
- **Fichiers concernes :** - **Fichiers concernes :**
- `components/common/ProductSelect.vue` - `components/ProductSelect.vue` — 1 `any` restant (slot template, incompressible)
- `components/common/ManagementView.vue` - `components/model-types/ManagementView.vue` — remplace `data?: any``Record<string, unknown>`, `error: any``error: unknown`, `item: any``item: unknown`
- `components/ComponentStructureAssignmentNode.vue` - `components/ComponentStructureAssignmentNode.vue` — 12 casts `(definition as any).typePiece/typeProduct` elimines grace a l'extension des types
- `components/model-types/ComponentModelStructureEditor.vue` - `components/ComponentModelStructureEditor.vue``Promise<any>``Promise<unknown>`
- `components/model-types/ModelTypeForm.vue` - `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. - **Probleme :** 20+ usages de `any` type identifies.
- **Action :** Remplacer chaque `any` par un type concret ou un type union. - **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 :** - - **Agent :** Claude
- **Notes :** - - **Notes :** ~15 casts `any` elimines. Les `Record<string, any>` restants dans ComponentModelStructureEditor sont justifies (manipulation dynamique interne de custom fields). Typecheck 0 erreurs.
--- ---
@@ -460,29 +492,31 @@
> **Priorite :** MOYENNE > **Priorite :** MOYENNE
### F4.1 Activer les regles ESLint critiques ### F4.1 Activer les regles ESLint critiques
- **Statut :** `[ ]`
- **Statut :** `[x]` DONE
- **Fichier :** `Inventory_frontend/eslint.config.mjs` - **Fichier :** `Inventory_frontend/eslint.config.mjs`
- **Probleme :** Presque toutes les regles sont desactivees (`no-console: off`, `no-unused-vars: off`, `no-explicit-any: off`). - **Probleme :** Presque toutes les regles etaient desactivees (`no-console: off`, `no-unused-vars: off`, `no-explicit-any: off`).
- **Action :** - **Action realisee :**
1. Activer `@typescript-eslint/no-explicit-any: warn` 1. [x] Active `@typescript-eslint/no-explicit-any: warn` (526 warnings — amelioration progressive)
2. Activer `no-console: warn` (ou `error` sauf pour `console.error`) 2. [x] Active `no-console: warn` avec `allow: ['error']` — 0 violations (deja nettoye en F4.2)
3. Activer `no-unused-vars: warn` 3. [x] Active `@typescript-eslint/no-unused-vars: warn` avec ignore `^_` — 0 violations (26 corrigees)
4. Fixer les violations progressivement 4. [x] Corrige les 26 violations `no-unused-vars` : imports inutilises supprimes, variables prefixees `_`, destructurations nettoyees
- **Agent :** - - **Agent :** Claude
- **Notes :** 94 appels `console.*` a nettoyer. - **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 ### F4.2 Nettoyer les console.log/console.error
- **Statut :** `[ ]`
- **Fichiers :** ~94 occurrences dans le frontend - **Statut :** `[x]` (console.log supprime, console.error conserve)
- **Probleme :** Appels de debug laisses dans le code de production. - **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 :** - **Action :**
1. Remplacer les `console.error` utiles par un logger centralise (ou `useToast`) 1. [x] Supprimer les 19 `console.log` de debug (normalizeRequirementList, page loading, route params, etc.)
2. Supprimer les `console.log` de debug 2. [ ] Les 72 `console.error` restants sont conserves (gestion d'erreur legitime). Migration vers un logger centralise a faire en F4.3.
3. Creer un utilitaire `logger.ts` si necessaire (qui respecte `enableDebug` du runtime config) - **Agent :** Claude
- **Agent :** - - **Notes :** 0 `console.log/warn/debug/info` restants dans le frontend.
- **Notes :** -
### F4.3 Centraliser la gestion d'erreurs API ### F4.3 Centraliser la gestion d'erreurs API
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichier :** `Inventory_frontend/app/composables/useApi.js` (105 LOC) - **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. - **Probleme :** Gestion d'erreur basique (juste un toast). Pas de retry, pas d'intercepteur, erreurs silencieuses dans certains composables.
@@ -501,19 +535,19 @@
> **Priorite :** MOYENNE > **Priorite :** MOYENNE
### F5.1 Decouper `shared/modelUtils.ts` ### F5.1 Decouper `shared/modelUtils.ts`
- **Statut :** `[ ]`
- **Fichier :** `Inventory_frontend/app/shared/modelUtils.ts` (1017 LOC) - **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. - **Probleme :** Fichier utilitaire monolithique de 1017 lignes regroupant toute la logique de manipulation de modeles.
- **Action :** - **Action :**
1. Identifier les groupes de fonctions (structure, custom fields, requirements, serialization) 1. Identifier les groupes de fonctions (structure, custom fields, requirements, serialization)
2. Decouper en modules : 2. Decouper en 3 modules thematiques :
- `shared/model/structureUtils.ts` - `shared/model/componentStructure.ts` (~590 LOC) — helpers, sanitize, hydrate, normalize, extract, format pour composants
- `shared/model/customFieldUtils.ts` - `shared/model/pieceProductStructure.ts` (~155 LOC) — structure piece/produit (clone, sanitize, hydrate, format)
- `shared/model/requirementUtils.ts` - `shared/model/definitionOverrides.ts` (~50 LOC) — sanitization des overrides de definition
- `shared/model/serializationUtils.ts` 3. Re-exporter depuis `shared/modelUtils.ts` (barrel) pour ne pas casser les imports
3. Re-exporter depuis un `shared/model/index.ts` pour ne pas casser les imports - **Agent :** Claude
- **Agent :** - - **Notes :** 11 fichiers consommateurs inchanges (barrel preserve la retro-compat). Typecheck 0 erreurs.
- **Notes :** -
--- ---
@@ -522,32 +556,40 @@
> **Priorite :** HAUTE - Aucun test actuellement > **Priorite :** HAUTE - Aucun test actuellement
### F6.1 Configurer Vitest ### F6.1 Configurer Vitest
- **Statut :** `[ ]`
- **Fichier a creer :** `Inventory_frontend/vitest.config.ts` - **Statut :** `[x]` DONE
- **Action :** - **Fichiers crees :**
1. Installer `vitest`, `@vue/test-utils`, `@nuxt/test-utils` - `vitest.config.ts` — config Vitest avec happy-dom, alias `~` et `#imports`
2. Configurer Vitest avec support Vue/Nuxt - `tests/__mocks__/imports.ts` — mock des auto-imports Nuxt (useRuntimeConfig, useRoute, etc.)
3. Ajouter un script `test` dans `package.json` - `tests/shared/inventory-types.test.ts` — 9 tests smoke (validator, empty structures)
4. Creer un premier test smoke - **Action realisee :**
- **Agent :** - 1. [x] Installe `vitest`, `@vue/test-utils`, `happy-dom`
- **Notes :** - 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 ### F6.2 Tests unitaires des composables
- **Statut :** `[ ]`
- **Fichiers a creer :** - **Statut :** `[x]` DONE (base)
- `tests/composables/useApi.test.ts` - **Fichiers crees :**
- `tests/composables/useProducts.test.ts` - `tests/shared/apiHelpers.test.ts` — 10 tests (extractCollection, tous formats API)
- `tests/composables/useToast.test.ts` - `tests/shared/modelUtils.test.ts` — 18 tests (isPlainObject, clone, stats, format, piece/product)
- `tests/shared/apiHelpers.test.ts` (apres F2.1) - `tests/shared/inventory-types.test.ts` — 9 tests (validator, empty structures)
- **Action :** - `tests/composables/useToast.test.ts` — 9 tests (add, types, max limit, clear, singleton)
1. Tester `useApi` (requetes, timeout, erreurs) - `tests/composables/useConfirm.test.ts` — 8 tests (open, confirm, cancel, options, singleton)
2. Tester `extractCollection()` (tous les formats de reponse) - **Action realisee :**
3. Tester les composables CRUD (mock des appels API) 1. [x] Teste `extractCollection()` : array, hydra:member, member, items, data, null, undefined
4. Tester le toast (ajout, suppression, max toasts) 2. [x] Teste `useToast` : ajout, types, max 3 toasts, clearAll, removeToast, singleton
- **Agent :** - 3. [x] Teste `useConfirm` : open/close, resolve true/false, custom options, singleton state
- **Notes :** - 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 ### F6.3 Tests de composants
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Fichiers a creer :** - **Fichiers a creer :**
- `tests/components/Pagination.test.ts` - `tests/components/Pagination.test.ts`
@@ -566,6 +608,7 @@
> **Priorite :** BASSE - Polish > **Priorite :** BASSE - Polish
### F7.1 Reduire le props drilling ### F7.1 Reduire le props drilling
- **Statut :** `[ ]` - **Statut :** `[ ]`
- **Probleme :** Props passees sur 3+ niveaux (ex: machine data dans les sous-composants). - **Probleme :** Props passees sur 3+ niveaux (ex: machine data dans les sous-composants).
- **Action :** - **Action :**
@@ -576,26 +619,33 @@
- **Notes :** A traiter apres F1 (decoupage des composants). - **Notes :** A traiter apres F1 (decoupage des composants).
### F7.2 Remplacer `confirm()` natif par des modales DaisyUI ### F7.2 Remplacer `confirm()` natif par des modales DaisyUI
- **Statut :** `[ ]`
- **Probleme :** Les confirmations de suppression utilisent `window.confirm()` (UI native, non-stylee). - **Statut :** `[x]` DONE
- **Action :** - **Probleme :** Les confirmations de suppression utilisaient `window.confirm()` (UI native, non-stylee).
1. Creer un composant `ConfirmModal.vue` reutilisable - **Action realisee :**
2. Ou creer un composable `useConfirm()` qui affiche une modale DaisyUI 1. [x] Cree `composables/useConfirm.ts` — composable promise-based avec etat reactif partage
3. Remplacer tous les `confirm()` dans les composants 2. [x] Cree `components/common/ConfirmModal.vue` — modale DaisyUI teleportee (backdrop blur, btn-error)
- **Agent :** - 3. [x] Monte `ConfirmModal` globalement dans `app.vue`
- **Notes :** - 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) ### F7.3 Nettoyer `app.vue` (861 LOC)
- **Statut :** `[ ]`
- **Fichier :** `Inventory_frontend/app/app.vue` (861 LOC) - **Statut :** `[x]` DONE
- **Probleme :** Le fichier racine contient le layout principal, la navbar, la sidebar, et du state management. - **Fichier :** `Inventory_frontend/app/app.vue` (861 → 49 LOC)
- **Action :** - **Probleme :** Le fichier racine contenait le layout principal, la navbar (~676 LOC dupliquee mobile/desktop), et du state management.
1. Extraire la navbar en `components/layout/AppNavbar.vue` - **Action realisee :**
2. Extraire la sidebar en `components/layout/AppSidebar.vue` 1. Cree `composables/useNavDropdown.ts` (~65 LOC) — gestion etat dropdowns navbar
3. Utiliser un layout Nuxt (`layouts/default.vue`) 2. Cree `components/layout/AppNavbar.vue` (~310 LOC) — navbar data-driven avec `v-for` eliminant duplication mobile/desktop
4. `app.vue` ne doit contenir que `<NuxtLayout>` et les providers globaux 3. `app.vue` reecrit en orchestrateur minimal (49 LOC) + converti en TypeScript
- **Agent :** - 4. Supprime 4 imports d'icones inutilises
- **Notes :** - - **Agent :** Claude
- **Notes :** Approche data-driven : liens et groupes definis comme tableaux types (`NavLink[]`, `NavGroup[]`), rendus par `v-for` pour mobile et desktop
--- ---
@@ -635,13 +685,68 @@ Phase 6.3 (Tests audit)
## Journal des modifications ## Journal des modifications
| Date | Phase | Tache | Agent | Statut | Notes | | 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 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) | | 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 ## Regles pour les agents
1. **Avant de commencer une tache :** 1. **Avant de commencer une tache :**