Commit Graph

122 Commits

Author SHA1 Message Date
Matthieu
5c55441e6c fix(audit) : visibilité protected pour ActorProfileResolver
AbstractAuditSubscriber déclarait $actorProfileResolver en private readonly
via promoted property. MachineAuditSubscriber surcharge onFlush() et accède
à $this->actorProfileResolver, mais private n'est pas hérité — PHP voyait
null et levait "Call to a member function resolve() on null" sur chaque
flush Doctrine touchant des link entities.

Le passage à protected suit la convention déjà en place dans la classe
(safeGet, normalizeValue, persistAuditLog, etc. sont protected). readonly
préserve l'immutabilité de la dépendance DI.

Ajoute aussi deux tests de régression pour le clone des contextFieldValues
(symétrique au test composant existant) et nettoie deux lignes vides
cosmétiques laissées par le refactor précédent.

- testCloneMachineCopiesPieceContextFieldValues : vérifie que les CFV
  context d'un MachinePieceLink sont bien rattachées au nouveau lien
  après clone.
- testCloneMachineLeavesSourceContextFieldValuesIntact : vérifie que la
  machine source garde ses CFV context après clone (invariant implicite).
2026-05-06 15:30:59 +02:00
Matthieu
e432153083 refactor : simplification globale (vague 1 + 2)
- ActorProfileResolver : service unique partage par AbstractAuditSubscriber, EntityVersionService et ModelTypeCategoryConversionService (3 implementations dupliquees+divergentes)
- corrige un bug latent : EntityVersionService restoraitsans le fallback Security::getUser, loggant actor=null hors session
- machine-clone : clonage des contextFieldValues integre dans cloneComponentLinks/clonePieceLinks, supprime cloneContextFieldValues et son find() en boucle
- helpers extraits : serializeProductSlots (EntityVersionService), updateModelTypeCategory (ModelTypeCategoryConversionService)
- supprime collectCollectionUpdate() vide + ses appels (AbstractAuditSubscriber)
- useMachineDetailData : retire debug ref couplee a isEditMode, componentTypeLabelMap/pieceTypeLabelMap jamais consommes, double assignation machine.productLinks
- PieceItem : retire l'init pieceData dans onMounted (deja couvert par reactive() et le watcher)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 10:14:23 +02:00
8f5cd98b82 fix(machine-clone) : preserve context field values when cloning a machine
All checks were successful
Auto Tag Develop / tag (push) Successful in 35s
Context CustomFieldValues attached to component/piece links were
silently dropped from the clone response (and from any subsequent
read in the same request) because the controller persisted the new
CFVs without adding them to the inverse-side collection of the new
link. Doctrine does not auto-sync inverse OneToMany associations,
so getContextFieldValues() returned an empty collection on the
freshly persisted link.

Also synchronise the inverse collection in the test factory so
identity-mapped entities reflect newly-created CFVs when reused
by request handlers within the same test.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-03 19:59:03 +02:00
c46769a67d fix(model-types) : nullify weak references on ModelType delete
Belt-and-suspenders against orphan refs when a ModelType is deleted:
applicatively nullifies typeComposantId / typePieceId / typeProductId
on every "ON DELETE SET NULL" relationship before the row is removed,
in case the database FK cascade fails to fire.

Observed in prod 2026-04-28: deletion of ModelType "Paliers" left an
orphan in skeleton_subcomponent_requirements, surfacing as a 500 when
API Platform tried to lazy-load the missing proxy.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-03 19:29:36 +02:00
Matthieu
8cfcb41a39 feat(conversion) : commande CLI pour convertir la catégorie Moteur de PIECE vers COMPONENT
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Migre les 18 pièces en composants, transfère documents, custom fields,
slots et skeleton requirements dans une transaction. Supporte --dry-run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:57:46 +02:00
244bfdc3e4 fix : code review — correct 15 issues across UX overhaul (phases 1-4)
Critical fixes:
- Make MigrateConstructeurLinks migration no-op (legacy tables already dropped)
- Add explicit ON CONFLICT (id) target in RestoreConstructeurLinks migration
- Replace N+1 queries with 4 bulk GROUP BY in ConstructeurStatsController
- Declare missing versionListRef template ref in machine detail page
- Add missing await on removeMachineDocument, cast activeTab as string

Important fixes:
- Add lang="ts" to ToastContainer and constructeurs page
- Type entityType as union in UsedInSection/useUsedIn
- Remove dead duration param from showError
- Update back-link props to new /catalogues/* URLs (3 pages)
- Replace raw error blocks with EmptyState in component/piece detail pages
- Type handleFillEntity params and machineInfoCardRef

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:26:05 +02:00
eef4b01d74 fix(api) : add priority to constructeurs/stats route to avoid {id} conflict 2026-04-04 19:30:55 +02:00
14ed38704f feat(api) : add machine count to category related items endpoint 2026-04-04 17:29:39 +02:00
4afbc8ba8a feat(api) : add constructeur stats endpoints with entity counts 2026-04-04 17:26:06 +02:00
b484a426e0 feat(api) : add /api/{entityType}/{id}/used-in endpoint for reverse entity lookups
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 17:25:43 +02:00
894d522036 refactor(custom-fields) : unify 3 parallel implementations into 1 module
Replace ~2900 lines across 9 files with ~400 lines in 2 files:
- shared/utils/customFields.ts (types + pure helpers)
- composables/useCustomFieldInputs.ts (reactive composable)

Migrated all consumers:
- Backend: add defaultValue to API Platform serialization groups
- Standalone pages: component edit/create, piece edit/create, product edit/create/detail
- Machine page: MachineCustomFieldsCard, MachineInfoCard, useMachineDetailCustomFields
- Hierarchy: ComponentItem, PieceItem
- Shared: CustomFieldDisplay, CustomFieldInputGrid
- Category editor: componentStructure.ts

Deleted:
- entityCustomFieldLogic.ts (335 lines)
- customFieldUtils.ts (440 lines)
- customFieldFormUtils.ts (404 lines)
- useEntityCustomFields.ts (181 lines)
- customFieldFormUtils.test.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 13:09:27 +02:00
0049638e3c fix(custom-fields) : context fields display, batch save, hierarchy propagation and UniqueEntity fix
- ComponentItem/PieceItem: DaisyUI divider, emit context-field-update for batch save
- CustomFieldDisplay: support editable/emit-blur/title/show-header props
- MachineComponentsCard/MachinePiecesCard: propagate custom-field-update events
- useMachineDetailCustomFields: pendingContextFieldUpdates + saveAllContextCustomFields
- useMachineDetailData: wire context field save into submitEdition
- useMachineDetailUpdates: only PATCH changed machine fields
- useMachineHierarchy: propagate contextCustomFields/Values from link to nodes
- componentStructure: include machineContextOnly in normalizeStructureForEditor
- Machine entity: convert empty reference to null, ignoreNull on UniqueEntity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:46:39 +02:00
c54e5c33f2 fix(custom-fields) : include machineContextOnly in ModelType.serializeCustomFields
The GET response for ModelType structure was missing machineContextOnly,
so on page reload the flag was always read as false by the frontend.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:24:20 +02:00
a88e4a68fb fix(custom-fields) : persist machineContextOnly in structure save and clone
- SkeletonStructureService: read and write machineContextOnly on create/update
- normalizeCustomFieldData: pass machineContextOnly through both payload formats
- cloneCustomFields: copy machineContextOnly flag on machine clone

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:09:15 +02:00
aec33e7911 feat(custom-fields) : clone context field values on machine clone
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:52:50 +02:00
2edb748bd4 feat(custom-fields) : support link-based upsert in CustomFieldValueController
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:52:18 +02:00
da12955b52 feat(custom-fields) : expose context custom fields in machine structure response
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:51:40 +02:00
4f1f643436 feat(custom-fields) : add machineContextOnly flag and link FKs for machine context
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:49:01 +02:00
1c3b566923 feat(machines) : allow category-only links on machine structure
Enable adding a component, piece, or product to a machine by selecting
only the category (ModelType) without a specific entity. The link
displays a red "À remplir" badge; clicking it reopens the modal
pre-filled with the category so the user can associate an item later.

Backend: entity FKs made nullable on the 3 link tables, modelType FK
added, controller/audit/version/MCP normalization adapted for null
entities.

Frontend: modal accepts category-only confirm, page handles fill mode,
hierarchy builder creates pending nodes, display components show
clickable badge with event propagation through the full hierarchy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:15:47 +02:00
Matthieu
d6441bef06 feat(ui) : highlight empty slots with category name in red
- Empty component slots (pieces, products, subcomponents) now display
  the category/type name with red styling instead of generic labels
- Machine view: empty structure pieces show type name + "manquant" in red
- Backend: include typePiece in structure slot data for name resolution

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 09:21:25 +02:00
Matthieu
5e7a744151 feat : add maintenance mode toggle in admin panel
All checks were successful
Auto Tag Develop / tag (push) Successful in 8s
- Backend: MaintenanceModeListener blocks non-admin API requests when
  var/maintenance flag file exists. MaintenanceController provides
  toggle (PUT /api/admin/maintenance) and public check endpoint
  (GET /api/maintenance/check).
- Frontend: Toggle button in admin page, maintenance.vue page for
  blocked users, middleware redirects non-admins to /maintenance.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 16:18:32 +02:00
Matthieu
476060cf7d WIP 2026-03-31 17:57:59 +02:00
Matthieu
1b1dab65b6 feat(constructeur) : add SearchFilter on ConstructeurLink entities
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:31:54 +02:00
Matthieu
5fff226f84 fix(constructeur) : fix remaining references after ConstructeurLink migration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:50:05 +02:00
Matthieu
691f632be0 refactor(mcp) : update MCP tools to use ConstructeurLinks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:29:10 +02:00
Matthieu
43fafc2251 refactor(conversion) : update category conversion to use ConstructeurLink tables
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:26:30 +02:00
Matthieu
0ad5815659 refactor(versioning) : update EntityVersionService to use ConstructeurLinks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:25:20 +02:00
Matthieu
a249a5b785 refactor(audit) : update audit subscribers to use ConstructeurLinks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:23:35 +02:00
Matthieu
d85272208a refactor(machines) : update structure controller to use ConstructeurLinks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:19:03 +02:00
Matthieu
26be0b655d refactor(constructeur) : replace ManyToMany with OneToMany to ConstructeurLink entities
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:12:17 +02:00
Matthieu
2d33c97449 feat(constructeur) : add 4 ConstructeurLink pivot entities with supplierReference
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:09:07 +02:00
Matthieu
03c2451990 feat(reference-auto) : extend auto-reference to composants + formula builder UI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:59:42 +02:00
Matthieu
3f6ce153bb feat(reference-auto) : add automatic reference generation for pieces
ModelType defines a formula with placeholders ({serie}{diametre}{type}).
ReferenceAutoGenerator resolves it from CustomFieldValues with trim+uppercase normalisation.
ReferenceAutoSubscriber (onFlush) recalculates on Piece/CFV insert/update/delete.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:58:53 +01:00
Matthieu
d568961eb3 feat(machine) : single save button + link versioning with restore
Backend:
- Enrich machine snapshot with componentLinks/pieceLinks/productLinks
- Detect link add/remove in MachineAuditSubscriber onFlush
- Add link diff comparison in restore preview
- Add link restoration in applyRestore for machines
- Add integrity warnings for missing linked entities

Frontend (submodule update):
- Single save button replacing auto-save-on-blur
- Link versioning display in version list and restore modal

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:51:58 +01:00
Matthieu
9299a46c8b feat(versioning) : add entity versioning with numbered versions and restore
Backend:
- Migration: version column on audit_logs and machines
- AuditLog, Machine, Composant, Piece, Product: version + skipAudit properties
- AbstractAuditSubscriber: auto-increment version, skip on restore, fix decimal diff
- Enriched snapshots with slots, custom fields and version number
- AuditLogRepository: findVersionHistory, findByVersion
- EntityVersionService: list, preview, restore with skeleton/integrity checks
- EntityVersionController: REST endpoints for all 4 entity types
- 11 tests covering list, preview, restore, auth

Frontend: update submodule pointer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:01:56 +01:00
3a75269323 fix(composant) : replace unique constraint from name to reference validation
Remove DB unique index on composants.name and add Symfony UniqueEntity
validation on reference field with explicit error message.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:12:19 +01:00
Matthieu
d70b9086d5 feat(search) : add MultiSearchFilter for OR search on name + reference
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:57:30 +01:00
Matthieu
3b35598b07 fix(structure) : stabilize piece/component/product ordering in machines
All findBy(['machine' => ...]) queries now sort by createdAt ASC.
Without explicit ORDER BY, PostgreSQL returned rows in heap order which
changed on every INSERT, causing the displayed order to shuffle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:02:36 +01:00
Matthieu
8851f22e4e feat(ops) : add custom field audit and restore commands
- app:check-missing-custom-field-values — diagnostic des valeurs perdues
- app:restore-piece-custom-field-values — restauration générale
- app:restore-recoverable-piece-custom-field-values — restauration ciblée
  depuis l'audit log (dry-run par défaut, --apply pour exécuter)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:49:53 +01:00
Matthieu
330b9376f6 feat(comments) : add file attachments on comments
Comments can now have documents attached via multipart/form-data upload.
New endpoint GET /api/documents/comment/{id} to list a comment's files.
Document entity gains a comment relation with cascade remove.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:49:46 +01:00
Matthieu
4468fd7cdf fix(custom-fields) : match by orderIndex to prevent value loss on rename
When a ModelType's custom field was renamed without sending the field ID,
the service would create a new CustomField instead of reusing the existing
one, orphaning all CustomFieldValues. Now matches by orderIndex as fallback
before name, preserving the link to existing values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:36:59 +01:00
Matthieu
509c4d2247 test(data-integrity) : add 10 tests for data loss prevention
Tests cover:
- Clone: CustomFieldValue references cloned definitions, not source
- Clone: values are preserved after cloning
- Slots: 404 on non-existent piece, 422 on wrong type, success on correct type
- Conversion: blocked when slots have filled data, allowed when empty
- CustomField: rejects orphan creation, accepts existing field by ID

Also removes legacy JSON structure check (column no longer exists
after normalization) — replaced by slot table checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 17:33:18 +01:00
Matthieu
043f6b1ce6 fix(data-integrity) : prevent data loss in clone, slots, conversion and custom fields
- Clone: CustomFieldValue now references cloned CustomField, not source
- Slots: validate piece type matches slot requirement + 404 on missing piece
- Conversion: check slot tables before allowing category conversion + clean orphan skeleton requirements
- CustomFieldValue: prevent creation of orphan CustomField without target entity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 17:15:05 +01:00
Matthieu
5ec6e49af2 feat(documents) : accept type on upload + expose in query controller + PATCH tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 15:20:39 +01:00
Matthieu
8d920d5f65 feat(documents) : add migration for type column with data classification
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 15:14:33 +01:00
Matthieu
342b0afdbb feat(documents) : add DocumentType enum and type column on entity
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 15:09:49 +01:00
Matthieu
2043e5b643 fix(constructeurs) : persist supplier removal on Piece, Composant and Product
- Frontend: always include constructeurs key in PATCH payload even when
  empty, so merge-patch+json actually clears the relation
- Backend: add setConstructeurs() on Piece and Product entities (Composant
  already had it) so API Platform can replace the ManyToMany collection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:54:08 +01:00
Matthieu
53b6abc9a8 fix(composant) : persist piece/product/subcomponent selections on creation
The ComposantProcessor now reads the structure payload from the frontend
and applies selectedPieceId/selectedProductId/selectedComponentId to the
scaffolded slots, so user selections are actually saved to the database.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:04:19 +01:00
Matthieu
826dae7712 fix(composant) : scaffold skeleton slots on creation + explicit unique constraint errors
- Add ComposantProcessor: initializes piece/product/subcomponent slots
  from ModelType skeleton requirements when a composant is created
- UniqueConstraintSubscriber: priority 256, French error messages,
  constraint name detection for specific feedback
- Migration: scaffold missing slots for existing composants in prod

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:48:23 +01:00
Matthieu
38777b7de0 fix(custom-fields) : prevent data loss on ModelType save + restoration scripts
Backend: match existing CustomField by name as fallback when ID is not provided,
preventing deletion and recreation of field definitions (which cascade-deletes values).

Includes restoration/migration scripts for prod:
- restore-custom-field-values.php: restores piece values from audit logs
- migrate-orphaned-custom-fields.php: migrates values from orphaned CFs
- fix-prod-all.php: combined fix (migrate + restore + cleanup)
- fix-prod-recreate-and-migrate.php: full fix (recreate missing CFs + migrate + restore)
- check-prod-*.php: diagnostic scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 20:24:37 +01:00