Commit Graph

35 Commits

Author SHA1 Message Date
Matthieu
bc32648918 fix(custom-fields) : supporte les caracteres accentues dans les placeholders de formule
La regex \w+ ne capturait pas les caracteres accentues (ex. {Diametre}
avec 'è'), le placeholder restait litteral dans la reference auto.
Remplace par [^}]+ avec le flag u/gu cote PHP et JS pour matcher
n'importe quel caractere entre les accolades.
2026-05-11 16:22:52 +02:00
Matthieu
9027917ea2 fix(custom-fields) : propage le renommage d'un champ dans la formule de reference auto 2026-05-11 16:22:28 +02:00
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
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
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
476060cf7d WIP 2026-03-31 17:57:59 +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
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
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
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
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
Matthieu
43bec07bb8 fix(sync) : preserve slot selections when modifying ModelType structure
SkeletonStructureService was deleting all skeleton requirements and
recreating them on every ModelType update. Combined with position-based
matching in sync strategies, any reordering or insertion caused all
existing slots to be orphaned and recreated empty, losing selections.

- SkeletonStructureService: update requirements in-place by matching
  on typeId instead of delete-all/recreate-all
- ComposantSyncStrategy & PieceSyncStrategy: two-pass smart matching
  algorithm (exact typeId+position first, then typeId-only fallback)
  to preserve selectedPiece/selectedComposant/selectedProduct on
  reorder/insertion
- Frontend: check patch result.success before updating local state

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:32:14 +01:00
Matthieu
b2aff0e414 feat(sync) : add slot selection controllers, custom field sync, and position fallbacks
- Add selectedPieceId support to ComposantPieceSlotController
- Create ComposantProductSlotController and ComposantSubcomponentSlotController
- Add updateCustomFields() to SkeletonStructureService for managing CustomField entities
- Fix position/orderIndex fallback to array index in all 3 sync strategies
- Fix type comparison in ProductSyncStrategy for dual format support
- Update CLAUDE.md with new entities, controllers, and fixtures documentation
- Update frontend submodule with interactive slot selectors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:40:44 +01:00
Matthieu
4072abf7ba feat(sync) : add ModelTypeSyncService orchestrator and controller with tests
Implement the sync orchestrator that delegates to tagged strategies via
AutowireIterator, and the HTTP controller exposing sync-preview and sync
endpoints with transaction wrapping and role-based access control.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:17:57 +01:00
Matthieu
089ca43404 feat(sync) : implement PieceSyncStrategy with tests 2026-03-13 14:07:04 +01:00
Matthieu
f09c7e4782 feat(sync) : implement ComposantSyncStrategy with tests 2026-03-13 14:00:59 +01:00
Matthieu
6a20dcce54 feat(sync) : implement ProductSyncStrategy with tests 2026-03-13 13:54:47 +01:00
Matthieu
6e0be3dbf3 feat(sync) : add DTOs and SyncStrategyInterface
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 13:47:59 +01:00
Matthieu
a6139d7090 feat(normalization) : drop structure and productIds JSON columns
- Remove Composant.structure property, getter/setter
- Remove Piece.productIds property, setProductIds()
- Update fixtures to remove dropped columns
- Add migrations to drop both columns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 08:19:54 +01:00
Matthieu
5336dfc09d feat(skeleton) : drop skeleton JSON columns from model_types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 18:11:14 +01:00
Matthieu
e2326064ba feat(skeleton) : expose skeleton relations via API and create SkeletonStructureService
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:58:18 +01:00
b342d0e50a fix(security) : harden auth, session, document access and health endpoint
- Remove orphaned PUBLIC_ACCESS rule for deleted /api/test route
- Remove JWT login firewall (app is session-based only)
- Set APP_SECRET placeholder (real value must be in .env.local)
- Remove JWT env vars from .env
- Add session regeneration on login (prevent session fixation)
- Remove Document.path from API serialization groups (prevent path leak)
- Restrict health check details to ROLE_ADMIN (anonymes get status only)
- Add path traversal guard in DocumentStorageService
- Convert CreateProfileCommand password to interactive hidden prompt
- Restrict Profile Get endpoint to ROLE_ADMIN
- Change api firewall to stateless: false (matches session-based auth)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 13:42:09 +01:00
74f77a3ba8 refactor(backend) : extract CuidEntityTrait, abstract audit subscriber, merge history controllers
- Extract shared ID generation + timestamps into CuidEntityTrait used by all entities
- Create AbstractAuditSubscriber to deduplicate audit logic across 7 subscribers
- Merge per-entity history controllers into single EntityHistoryController
- Delete redundant ComposantHistory/MachineHistory/PieceHistory/ProductHistoryController
- Add OpenApiDecorator for API documentation customization
- Disable failOnDeprecation in PHPUnit (vendor API Platform deprecation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 13:39:03 +01:00
Matthieu
0e11f4ad2d refactor(api) : remove TypeMachine skeleton system, fix ModelType serialization
- Remove TypeMachine, TypeMachineComponentRequirement, TypeMachinePieceRequirement,
  TypeMachineProductRequirement entities and related repositories/state processor
- Replace MachineSkeletonController with MachineStructureController
- Link CustomField directly to Machine instead of TypeMachine
- Add migration to drop TypeMachine tables and migrate custom fields to machines
- Fix ModelType serialization: Annotation\Groups → Attribute\Groups (Symfony 8 compat)
  and add product:read, composant:read, piece:read groups for embedded category display
- Fix Profile: same Annotation → Attribute import
- Fix SearchFilter: partial → ipartial on Comment and Document
- Update frontend submodule (remove skeleton pages/components, simplify machine creation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:26:16 +01:00
Matthieu
d89c97f0a0 feat(documents) : filesystem storage, server-side pagination and PDF compression
- Add DocumentStorageService for file-based storage (replaces Base64 in DB)
- Add DocumentServeController with /file and /download endpoints
- Add DocumentUploadProcessor using FormData + filesystem storage
- Add DocumentNormalizer exposing fileUrl/downloadUrl on all responses
- Add DocumentFileCleanupListener for automatic file deletion
- Add MigrateDocumentsToFilesystemCommand (Base64 → files, memory-safe)
- Add ApiFilter (SearchFilter, ExistsFilter, OrderFilter) on Document entity
- Add PdfCompressorService + refactor CompressPdfCommand for batch processing
- Fix TypeMachine PUT: deserialize=false + validate=false to prevent
  UniqueEntity false positive and writableLink collection interference
- Update CHANGELOG for v1.8.0
- Update frontend submodule

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:18:55 +01:00
Matthieu
02ff8b1a96 feat(audit) : extend audit logging to machines, constructeurs, model types, documents and conversions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:51:26 +01:00
Matthieu
cd2a3fac55 feat(categories) : add bidirectional piece/component category conversion
Backend service and controller for converting piece categories to component
categories (and vice-versa). Uses raw SQL in a transaction to preserve IDs
and transfer all related data (documents, custom fields, constructeurs).
Includes php-cs-fixer formatting pass on existing controllers/entities.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:27:07 +01:00
Matthieu
a5118305d3 feat : automatic PDF compression on upload
- Add PdfCompressorService for lossless compression with qpdf
- Add DocumentPdfCompressorListener for automatic compression on persist/update
- Add app:compress-pdf command for batch compression of existing PDFs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 19:02:26 +01:00