Files
Inventory/REFACTORING_PLAN.md
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

37 KiB

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 :
    • F1.3a Extraire customFieldFormUtils.ts (duplique dans 5 fichiers)
    • F1.3b Extraire documentDisplayUtils.ts (duplique dans 3 pages edit)
    • F1.3c Extraire historyDisplayUtils.ts (duplique dans 3 pages edit)
    • F1.3d Rewire les 5 pages create/edit sur les modules extraits
    • 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 :
    • F1.4a Extraire entityCustomFieldLogic.ts (fonctions pures)
    • F1.4b Creer useEntityCustomFields.ts (composable reactif)
    • F1.4c Creer useEntityDocuments.ts (composable documents)
    • F1.4d Creer useEntityProductDisplay.ts (composable produit)
    • F1.4e Rewrite ComponentItem.vue (1336 → 585 LOC, script 900 → 150 LOC)
    • F1.4f Rewrite PieceItem.vue (1588 → 740 LOC, script 1100 → 255 LOC)
    • 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. Creer shared/utils/apiHelpers.ts avec extractCollection<T>() generique
    2. 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. Creer composables/useEntityHistory.ts parametrable par type d'entite
    2. 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. Creer composables/useEntityTypes.ts generique (CRUD + singleton state par categorie)
    2. Reecrire les 3 fichiers specifiques en wrappers avec renommage des champs
  • Agent : -
  • Notes : Les wrappers renomment typescomponentTypes/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.tsApiResponse<T> generique (success/data/error/status)
    • composables/useMachines.tsMachine interface
    • composables/useMachineTypesApi.tsMachineType, MachineTypeRequirement interfaces
    • composables/useToast.tsToast, ToastType types
    • composables/useProfiles.tsProfile interface
    • composables/useCustomFields.tsCustomFieldValue 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) :
    • useToast.jsuseToast.ts (72 LOC, types: Toast, ToastType)
    • useProfiles.jsuseProfiles.ts (68 LOC, type: Profile)
    • useProfileSession.jsuseProfileSession.ts (85 LOC, importe Profile)
    • useApi.jsuseApi.ts (106 LOC → 120 LOC, types: ApiResponse<T>, ApiCallOptions, ajout put())
    • useCustomFields.jsuseCustomFields.ts (105 LOC, type: CustomFieldValue)
    • useMachineTypesApi.jsuseMachineTypesApi.ts (173 → 188 LOC, types: MachineType, MachineTypeRequirement)
    • useMachines.jsuseMachines.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?: anyRecord<string, unknown>, error: anyerror: unknown, item: anyitem: unknown
    • components/ComponentStructureAssignmentNode.vue — 12 casts (definition as any).typePiece/typeProduct elimines grace a l'extension des types
    • components/ComponentModelStructureEditor.vuePromise<any>Promise<unknown>
    • components/model-types/ModelTypeForm.vue(incoming as any).description → cast Record<string, unknown>
    • shared/types/inventory.tsComponentModelPiece.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. Active @typescript-eslint/no-explicit-any: warn (526 warnings — amelioration progressive)
    2. Active no-console: warn avec allow: ['error'] — 0 violations (deja nettoye en F4.2)
    3. Active @typescript-eslint/no-unused-vars: warn avec ignore ^_ — 0 violations (26 corrigees)
    4. 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. 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. Installe vitest, @vue/test-utils, happy-dom
    2. Configure Vitest avec environment happy-dom et resolution d'alias
    3. Ajoute scripts test et test:watch dans package.json
    4. 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. Teste extractCollection() : array, hydra:member, member, items, data, null, undefined
    2. Teste useToast : ajout, types, max 3 toasts, clearAll, removeToast, singleton
    3. Teste useConfirm : open/close, resolve true/false, custom options, singleton state
    4. Teste modelUtils : clone, stats, preview, isPlainObject, piece/product variants
    5. 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. Cree composables/useConfirm.ts — composable promise-based avec etat reactif partage
    2. Cree components/common/ConfirmModal.vue — modale DaisyUI teleportee (backdrop blur, btn-error)
    3. Monte ConfirmModal globalement dans app.vue
    4. 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/ :

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 :

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