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>
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>
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>
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>
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>
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>
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>
- 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>
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>
- 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>
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>
Tools now return CallToolResult directly instead of Content arrays,
preventing the MCP SDK from auto-generating structuredContent as a
JSON array (which Claude Code rejects — expects a JSON object/record).
Also adds Accept header to test helpers and SSE response parsing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 3 MCP resources: schema, roles, stats
- docs/mcp/README.md with full user guide (config, tools catalogue, workflows)
- .mcp.json for Claude Code stdio transport
- Design spec and implementation plan
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>