shoc-backend/docs/work-orders/phase-7
2026-07-13 13:51:34 -03:00
..
README.md wip: work orders phases 1-7 (isolated from phase 0 foundation) 2026-06-30 10:09:48 -03:00

Fase 7 — Rollout e Produção

Programa: Work Orders Board
Objetivo: Piloto SHOC, rollout gradual, monitoramento de coexistência, sunset Blazor WO, cutover Lambda→API e deprecação legado.

Depende de: Fase 0 … Fase 6 concluídas e validadas em staging.


Gates

  • Entrada: phase-7-gates-signoff.md
  • Saída: piloto UAT, 100% SHOC, zero P1 × 2 semanas, Blazor sunset, Lambda cutover, ops health ativo

Runbook de rollout (ordem obrigatória)

  1. Fechar gates de entrada Fase 7
  2. Deploy API com ops health + ingest (ingest desabilitado em prod inicialmente)
  3. SHOC: feature flag board em staging → piloto 1–2 dispatchers em prod
  4. UAT dispatchers (roteiros abaixo)
  5. Rollout gradual SHOC até 100%
  6. Habilitar dual-run Lambda (ingest + Dynamo)
  7. Validar drift → cutover Lambda só API
  8. Sync:Enabled=false
  9. BlazorWorkOrderSunset:Enabled=true
  10. LegacyEndpoints:DeprecationEnabled=true + data Sunset
  11. Remover Sync/legado após período de aviso (30 dias)

Endpoints Fase 7

GET /api/workorders/ops/health

Saúde operacional para coexistência multi-consumidor.

Auth: Admin JWT

{
  "lastWeekRolledRunUtc": "2026-06-23T00:05:12Z",
  "lastPastDueCacheRunUtc": null,
  "lastWeekRolledError": null,
  "lastPastDueCacheError": null,
  "syncRejectedLast24h": 3,
  "fieldLockCount": 142,
  "syncEnabled": true,
  "ingestEnabled": true,
  "legacyDeprecationEnabled": false,
  "legacySunsetDate": null,
  "checkedAtUtc": "2026-06-25T12:00:00Z"
}

Ver cloudwatch-alerts.md.


POST /api/workorders/ingest

Ingest direto idempotente (substitui ponte DynamoDB para WOs).

Auth: header X-Ingest-Key (config WorkOrderIngest:ApiKey)

Body (single ou batch):

{
  "externalWorkOrderId": "ext-wo-12345",
  "description": "HVAC unit not cooling",
  "woStatus": "new",
  "severity": "2",
  "customer": "Acme Corp",
  "siteCode": "BK5",
  "building": "Building A",
  "address": "123 Main St",
  "dueDate": "2026-07-01T00:00:00Z",
  "dateReported": "2026-06-20T10:00:00Z",
  "scheduledStart": null,
  "sourceEmailS3Key": null,
  "createdAt": "2026-06-20T10:00:00Z"
}

Batch:

{
  "items": [ { "externalWorkOrderId": "...", "description": "..." } ]
}

Response:

{
  "created": 1,
  "updated": 0,
  "results": [{ "externalWorkOrderId": "ext-wo-12345", "workOrderId": 42, "created": true }]
}

Mapeamento completo: lambda-ingest-discovery.md


Matriz de endpoints

Tipo Exemplos Política Fase 7
Board (SHOC) GET board, PATCH {id}/board, POST board Produção
Slide-over GET {id}/detail, completion-doc, media Produção
Ingest POST ingest Dual-run → produção
Sync POST api/Sync/WorkOrders Desligar após cutover (Sync:Enabled)
Legado GetWorkOrderList, AddWorkorder, ChangeStatus Deprecation headers
Jobs POST jobs/week-rolled Ops Admin

Configuração

API (Api.SeaHavenIndustries)

{
  "FrontendBaseUrl": "https://shoc.seahaven.com",
  "WorkOrderIngest": {
    "Enabled": true,
    "ApiKey": "${WORKORDER_INGEST_API_KEY}"
  },
  "Sync": {
    "Enabled": true
  },
  "LegacyEndpoints": {
    "DeprecationEnabled": false,
    "SunsetDate": "2026-12-31"
  }
}

Env vars: ver .env.example

Blazor (SeaHavenIndustries)

{
  "BlazorWorkOrderSunset": {
    "Enabled": false,
    "ShocBaseUrl": "https://shoc.seahaven.com"
  }
}

Quando Enabled=true: nav Work Orders aponta para SHOC; mutações EF bloqueadas; banner nas páginas WO.


UAT dispatchers

Roteiro manual — marcar cada item antes de expandir rollout.

# Cenário Pass
1 Login SHOC; carregar semana (Mon–Fri + Unscheduled) [ ]
2 Filtros: dispatcher, My WOs, tipo, busca contextual [ ]
3 Inline edit célula (status, assignee, due) [ ]
4 Conflito 409 — outro usuário editou; mensagem clara [ ]
5 Criar WO wizard (Incomplete → Scheduled auto) [ ]
6 Cancel soft; campos read-only pós-cancel [ ]
7 Advanced search cross-week [ ]
8 Slide-over: detail, comments, audit, media [ ]
9 Upload completion doc; docStatus no board [ ]
10 Badge PastDue / CarriedOver após segunda-feira [ ]

Sign-off UAT

Dispatcher Data PO

Piloto e rollout SHOC

Controle somente no frontend (feature flags). Backend não filtra dispatchers.

Critérios para avançar:

  • Zero P1 na semana do piloto
  • GET board latência aceitável (Tier S)
  • Vendor Portal regression verde

Sunset Blazor

Ver data-ownership-model.md §3.

  1. Congelar WorkorderService (bugfix only) até data PO
  2. Habilitar BlazorWorkOrderSunset:Enabled
  3. Smoke final smoke-checklist.md Blazor EF

Cutover Lambda

Ver lambda-ingest-discovery.md.


Testes automatizados

dotnet test SeaHavenIndustries.Tests --filter "FullyQualifiedName~WorkOrderPhase7"

Suite: WorkOrderPhase7CoexistenceTests.cs


Critérios de aceite Fase 7

  • GET /api/workorders/ops/health
  • POST /api/workorders/ingest com API key
  • Sync:Enabled feature flag
  • Legacy deprecation middleware
  • Blazor sunset config + guard mutações
  • Documentação gates, UAT, Lambda mapping
  • Piloto prod (ops/PO)
  • 100% dispatchers SHOC (ops/PO)
  • Zero P1 × 2 semanas (ops/PO)
  • Lambda cutover executado (ops)

Comunicação

Audiência Mensagem Quando
Dispatchers piloto Novo board SHOC; suporte dedicado Início piloto
Todos dispatchers Rollout gradual; treinamento Durante rollout
Usuários Blazor WO migrou para SHOC; link direto Sunset Blazor
Engenharia Sync desligado; usar ingest API Pós-cutover