- 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>
- 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>
- 5 tools each: list, get, create, update, delete
- McpToolHelper extracted to AbstractApiTestCase for reuse
- DashboardStatsToolTest simplified to use base helpers
- 22 MCP tests pass
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- McpStdioAuthSubscriber for console transport auth via env vars
- DashboardStatsTool as PoC (validates MCP protocol flow)
- McpToolHelper trait for shared pagination/error utilities
- Key learning: #[McpTool] must be on CLASS, not method for __invoke
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
- 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>
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>
Exposes structure as a computed property from pieceSlots, productSlots,
and subcomponentSlots relations, including slotId for frontend quantity
persistence.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
normalizeProduct() had customFields hardcoded to [] and was missing
customFieldValues entirely, unlike normalizeComposant and normalizePiece.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
getStructure() was returning hardcoded empty customFields arrays after
the JSON-to-tables migration. Now reads from the relational CustomField
entities via serializeCustomFields() for all three categories.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
ModelType.setStructure() now stores data in pendingStructure instead of
writing to JSON columns. A new ModelTypeProcessor intercepts API Platform
POST/PUT/PATCH operations and delegates skeleton writes to
SkeletonStructureService, which persists to relation tables.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- normalizeComposant : inclure structure du composant dans la réponse
- enrichStructureWithPieceData : résoudre selectedPieceId vers les
données complètes de la pièce catalogue (nom, référence, prix, etc.)
- Update submodule : affichage pièces incluses + quantité machine
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
API Platform silently ignored the constructeurs field on PATCH because
Machine was missing the add/remove methods (unlike Composant, Piece, Product).
Also fixes the read-only fournisseur display overflow in MachineInfoCard.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add color VARCHAR(7) column to sites entity
- Migration with IF NOT EXISTS for idempotence
- Update reference config
- Frontend: site color picker, dark mode, card styling improvements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
- 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>
Add nullable TEXT description column to both pieces and composants
tables with corresponding Doctrine entity mappings, getters/setters
and serialization groups.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Patch operation to Site entity (was only Put, causing 405 errors).
Fix migration to use ALTER TABLE DROP CONSTRAINT instead of DROP INDEX
for the piece name unique constraint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>