| .. | ||
| README.md | ||
Fase 5 — Scheduled Domain Events
Programa: Work Orders Board
Objetivo: Jobs agendados in-process (IHostedService) para WeekRolled → CarriedOver++ com idempotência WO+semana, audit System, cache opcional de PastDue, e garantia de que leituras do board continuam on-read como fonte da verdade.
Depende de: Fase 0, Fase 1, Fase 2, Fase 3, Fase 4
Regra de elegibilidade WeekRolled
sourceWeek = semana operacional encerrada (segunda a sexta UTC)
Elegível se:
- ScheduledDate.Date ∈ [sourceWeekStart, sourceWeekEnd]
- LifecycleStatus ∉ {Complete, Canceled, Closed}
- istemplate != true (ou null)
- Ainda não processado em WorkOrderWeekRolledLedger (WorkOrderId + SourceWeekStart)
Gate PO (pendente): confirmar se WOs só com TargetWeek (sem ScheduledDate) entram no carry-over. A implementação atual considera apenas WOs com ScheduledDate na janela.
Idempotência
Chave composta (WorkOrderId, SourceWeekStart) na tabela WorkOrderWeekRolledLedger. Re-execução do job ou endpoint admin na mesma semana não duplica CarriedOver.
Contrato de audit
Um evento WeekRolled por WO processado:
| Campo | Valor |
|---|---|
EventType |
System |
ActorType |
System |
Action |
WeekRolled |
FieldName |
CarriedOver |
OldValue / NewValue |
numéricos (string) |
CorrelationId |
week:{yyyy-MM-dd} (segunda da semana fonte) |
Não aciona ManualEditFlag nem field locks.
Regra de ouro — isPastDue
Jobs nunca são fonte da verdade para isPastDue. O board continua calculando via WorkOrderDerivedFields.IsPastDue on-read. O cache OperationalFlags.PastDue é otimização opcional (WorkOrderJobs:PastDueCache:Enabled, default false).
Configuração
"WorkOrderJobs": {
"WeekRolled": { "Enabled": true, "RunAtUtc": "00:05", "DayOfWeek": "Monday" },
"PastDueCache": { "Enabled": false, "RunAtUtc": "00:10" }
}
Variáveis de ambiente (.env.example):
WorkOrderJobs__WeekRolled__Enabled=true
WorkOrderJobs__PastDueCache__Enabled=false
Endpoints admin (ops-only)
| Endpoint | Auth | Descrição |
|---|---|---|
POST /api/workorders/jobs/week-rolled?sourceWeekStart=2026-06-16 |
Admin | Reprocessa semana (segunda-feira). Idempotente. |
POST /api/workorders/jobs/past-due-cache |
Admin | Atualiza cache OperationalFlags.PastDue |
Código entregue
| Camada | Arquivo |
|---|---|
| Ledger | Data.SeaHavenIndustries/Models/WorkOrderWeekRolledLedger.cs |
| Migration | 20260624210000_Phase5_DomainEvents.cs |
| Data | SeaHaven.DataServices/Implementation/WorkOrderDomainJobDataService.cs |
| WeekRolled | SeaHaven.Services/Implementation/WorkOrderWeekRolledService.cs |
| PastDue cache | SeaHaven.Services/Implementation/PastDueCacheService.cs |
| Hosted | Api.SeaHavenIndustries/HostedServices/*.cs |
| API | WorkOrderJobsController |
| Testes | SeaHavenIndustries.Tests/WorkOrderWeekRolledTests.cs |
Monitoramento
Logs estruturados com CorrelationId da semana. Ao concluir: processed, skipped, failed, durationMs.
Alerta ops: se failed > 0 ou job não executou em 8 dias → investigar + POST /jobs/week-rolled manual.
Critérios de aceite
- Job semanal incrementa
carriedOverpara WOs elegíveis da semana anterior - Re-execução na mesma semana não duplica (ledger WO+semana)
- Audit
WeekRolledSystem com old/newCarriedOvereCorrelationId GET /api/workorders/boardcontinua comisPastDuederivado on-read- Endpoint admin permite reprocessar semana específica
- Testes cobrem idempotência, terminal skip, audit e on-read correctness
Fora de escopo
- Message queue / worker externo
- Alteração do contrato REST do board para usar
OperationalFlags - WOs week-only (
TargetWeeksemScheduledDate) — gate PO