# Machine Single Save Button + Link Versioning — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Replace the machine page's auto-save-on-blur with a single "Enregistrer les modifications" button (matching composant/pièce/produit pages), and add versioning for machine link add/remove operations.
**Architecture:** Frontend changes remove all `@blur` save triggers from MachineInfoCard, consolidate saves into a single `submitEdition()` method in the orchestrator composable, and add Save/Cancel buttons at the bottom of the page. MachineInfoCard exposes `saveFieldDefinitions()` via `defineExpose` so the parent can call it during submit. Backend changes extend `MachineAuditSubscriber`'s `onFlush` to detect link entity insertions/deletions and create audit entries on the parent machine.
**Tech Stack:** Vue 3 / Nuxt 4, Symfony 8, Doctrine ORM, PHP 8.4
---
## File Structure
| Action | File | Responsibility |
|--------|------|----------------|
| Modify | `frontend/app/components/machine/MachineInfoCard.vue` | Remove blur-triggered saves, expose saveFieldDefinitions via defineExpose |
| Modify | `frontend/app/components/machine/MachineCustomFieldDefEditor.vue` | Remove standalone save button |
| Modify | `frontend/app/pages/machine/[id].vue` | Add Save/Cancel buttons, wire submitEdition via template ref |
| Modify | `frontend/app/composables/useMachineDetailData.ts` | Add submitEdition, cancelEdition, saving, canSubmit |
| Modify | `frontend/app/composables/useMachineDetailUpdates.ts` | Remove auto-save from handleMachineConstructeurChange |
| Modify | `frontend/app/composables/useMachineDetailCustomFields.ts` | Add saveAllMachineCustomFields batch method |
| Modify | `src/EventSubscriber/MachineAuditSubscriber.php` | Enrich snapshot with links + detect link changes in onFlush |
---
### Task 1: Remove blur-triggered saves from MachineInfoCard
**Files:**
- Modify: `frontend/app/components/machine/MachineInfoCard.vue`
- [ ] **Step 1: Remove `@blur` from name input (line 17)**
Replace:
```vue
@input="$emit('update:machine-name', ($event.target as HTMLInputElement).value)"
@blur="$emit('blur-field')"
```
With:
```vue
@input="$emit('update:machine-name', ($event.target as HTMLInputElement).value)"
```
- [ ] **Step 2: Remove `$emit('blur-field')` from site select (line 31)**
Replace:
```vue
@change="$emit('update:machine-site-id', ($event.target as HTMLSelectElement).value); $emit('blur-field')"
```
With:
```vue
@change="$emit('update:machine-site-id', ($event.target as HTMLSelectElement).value)"
```
- [ ] **Step 3: Remove `@blur` from reference input (line 57)**
Replace:
```vue
@input="$emit('update:machine-reference', ($event.target as HTMLInputElement).value)"
@blur="$emit('blur-field')"
```
With:
```vue
@input="$emit('update:machine-reference', ($event.target as HTMLInputElement).value)"
```
- [ ] **Step 4: Remove `@blur` from all custom field inputs**
For each custom field input, remove the `@blur="$emit('update-custom-field', field)"` line:
- text input (line 118)
- number input (line 127)
- select (line 135)
- boolean checkbox (line 152)
- date input (line 163)
- [ ] **Step 5: Remove `@save` handler from MachineCustomFieldDefEditor usage (line 187)**
Replace:
```vue
```
With:
```vue
```
- [ ] **Step 6: Remove unused emit declarations and add defineExpose**
Replace the `defineEmits` block (lines 222-231):
```ts
const emit = defineEmits<{
'update:machine-name': [value: string]
'update:machine-reference': [value: string]
'update:machine-site-id': [value: string]
'update:constructeur-ids': [ids: unknown]
'blur-field': []
'set-custom-field-value': [field: any, value: unknown]
'update-custom-field': [field: any]
'custom-fields-saved': []
}>()
```
With:
```ts
const emit = defineEmits<{
'update:machine-name': [value: string]
'update:machine-reference': [value: string]
'update:machine-site-id': [value: string]
'update:constructeur-ids': [ids: unknown]
'set-custom-field-value': [field: any, value: unknown]
'custom-fields-saved': []
}>()
```
Then, at the end of the `