shoc-backend/docs/work-orders/phase-0/manual-edit-flag-design.md

87 lines
2.1 KiB
Markdown

# ManualEditFlag — Design
**Fase:** 0
**Implementação:** tabela satélite `WorkOrderFieldLocks`
---
## 1. Problema
Sync/Lambda faz upsert overwrite em campos que dispatchers editam no SHOC. Precisamos saber, por campo, se houve edição manual SHOC para rejeitar ingest conflitante.
---
## 2. Solução escolhida: tabela satélite
```text
WorkOrderFieldLocks
Id (PK)
WorkOrderId (FK)
FieldName (string, max 64)
LockedAt (UTC)
LockedByUserId (nullable — null = system/bootstrap)
UNIQUE (WorkOrderId, FieldName)
```
**Alternativa descartada:** bitmask — difícil de auditar e estender.
---
## 3. Comportamento
| Evento | Ação |
|--------|------|
| SHOC edita campo X pela 1ª vez | INSERT lock (WorkOrderId, FieldName) |
| Sync tenta atualizar campo X com lock | Skip update; audit `SyncRejected` |
| Sync atualiza campo Y sem lock | Apply merge normal |
| WO novo (Sync create) | Sem locks; full ingest |
| Blazor edita campo legado | **Não** cria lock Fase 0 (gap conhecido; Blazor congelado) |
---
## 4. Campos elegíveis a lock (SHOC writers)
Definidos em `SyncFieldMergePolicy.ShocOwnedFields`:
- LifecycleStatus, AssignTo, ScheduledDate, ScheduledEnd, TargetWeek, ScheduleWeekOnly
- DueDate, Description, WorkerOrderTitle, SiteCode, Building, LocationId
- WorkOrderType, DocStatus, Trade, Problem, Priority, InternalWONumber
---
## 5. Audit em rejeição
```json
{
"eventType": "Sync",
"action": "SyncRejected",
"fieldName": "DueDate",
"oldValue": "2026-06-01",
"newValue": "2026-06-15",
"actorType": "Sync"
}
```
---
## 6. API interna
```csharp
interface IWorkOrderFieldLockService
{
Task LockFieldAsync(int workOrderId, string fieldName, string? userId);
Task<bool> IsLockedAsync(int workOrderId, string fieldName);
}
```
Implementação: `WorkOrderFieldLockService` em `SeaHaven.Services`.
Lock criado automaticamente por `IWorkOrderAuditService` em eventos `Manual` + `FieldChanged` / `StatusChanged`.
---
## 7. Critérios de aceite
- [ ] Tabela criada na migration Phase0
- [ ] Sync consulta locks antes de overwrite
- [ ] SyncRejected aparece no audit log