Documents, products, components and pieces cards are now hidden when
empty in consultation mode. They remain visible in edit mode so users
can still add items. Addresses Geoffrey's feedback (INV-7).
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>
The definitionSources passed to saveCustomFieldValues were pointing at
properties not serialized by the API (typeComposant.customFields,
typePiece.pieceCustomFields). Changed to structure.customFields which
is the correct serialized path, preventing orphan custom field creation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace site dropdown with inline checkboxes for multi-site filtering
- Sort machines alphabetically (localeCompare fr)
- Switch catalog search from ?name= to ?q= for OR search on name/reference
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>
Prevents data loss when saving ModelType: the frontend now sends existing
CustomField IDs so the backend can match them instead of deleting and recreating.
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>
The v-if on resolveDescription() was hiding the entire slot when
optionDescription prop was not provided. Now checks for slot presence
first, allowing custom formatDescription in PieceSelect/ProductSelect/
ComposantSelect to render properly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PieceSelect, ProductSelect, ComposantSelect: show type name and
"Ref." prefix in dropdown descriptions (matching create page format)
- Category edit pages (component, piece, product): stay on page after
successful save instead of navigating back to list
- Component and product edit pages: same — stay on page after save
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>
- list_slots + update_slots for composant/piece slots
- list/add/update/remove machine links (component, piece, product)
- get_machine_structure with full hierarchy
- clone_machine with all links and custom fields
- 52 MCP tests pass total
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 5 tools each: list, get, create, update, delete
- Piece: includes typePiece, constructeurs, prix (string)
- Composant: includes typeComposant, constructeurs, prix (string)
- Machine: includes site (required), constructeurs
- 40 MCP tests pass total
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>