diff --git a/TODO.md b/TODO.md index 19fa447..68fc21b 100644 --- a/TODO.md +++ b/TODO.md @@ -50,11 +50,3 @@ - [ ] When SHOC deploys, switch workorder-ingest Lambda from DynamoDB to direct SHOC API calls - [ ] Retire DynamoDB sync bridge - [ ] GitHub branch protection — requires paid plan for private repos - -### Work Orders Board — Phase 7 ops (after engineering on `feat/work-orders-phase-7`) -- [ ] Staging: dry-run migrations Phase0–Phase6 + smoke multi-consumidor -- [ ] Staging: E2E SHOC (board + slide-over + completion-doc) -- [ ] Create CloudWatch alerts from `docs/work-orders/phase-7/cloudwatch-alerts.md` -- [ ] Name Lambda cutover owner; dual-run then `Sync:Enabled=false` -- [ ] Piloto 1–2 dispatchers → UAT → 100% rollout; Blazor sunset date -- [ ] Sign GO/DONE in `docs/work-orders/phase-7/phase-7-gates-signoff.md` diff --git a/docs/work-orders/phase-7/cloudwatch-alerts.md b/docs/work-orders/phase-7/cloudwatch-alerts.md deleted file mode 100644 index 07605d6..0000000 --- a/docs/work-orders/phase-7/cloudwatch-alerts.md +++ /dev/null @@ -1,52 +0,0 @@ -# Alertas Operacionais — Fase 7 - -**Endpoint de saúde:** `GET /api/workorders/ops/health` (Admin JWT) - ---- - -## Métricas expostas - -| Campo | Fonte | Uso | -|-------|-------|-----| -| `lastWeekRolledRunUtc` | `WorkOrderJobRunState` + ledger | Job segunda-feira | -| `lastPastDueCacheRunUtc` | `WorkOrderJobRunState` | Cache opcional PastDue | -| `syncRejectedLast24h` | `WorkOrderAuditLogs` Action=SyncRejected | Conflito SHOC vs ingest | -| `fieldLockCount` | `WorkOrderFieldLocks` | Adoção edição manual | -| `syncEnabled` | `Sync:Enabled` | Estado ponte Dynamo | -| `ingestEnabled` | `WorkOrderIngest:Enabled` | Ingest direto ativo | - ---- - -## Alertas recomendados (Elastic Beanstalk / CloudWatch) - -| Alerta | Condição | Severidade | Status ops | -|--------|----------|------------|------------| -| WeekRolled stale | `lastWeekRolledRunUtc` > 8 dias | P1 | [ ] criar | -| WeekRolled job error | `lastWeekRolledError` não nulo | P1 | [ ] criar | -| SyncRejected spike | `syncRejectedLast24h` > 50 | P2 | [ ] criar | -| API 5xx board | ALB/Beanstalk 5xx rate > 1% em `/api/workorders/board` | P1 | [ ] criar | -| Ingest auth failures | 401 em `/api/workorders/ingest` > 10/h | P2 | [ ] criar | -| Sync disabled em prod sem cutover | `syncEnabled=false` e ingest não validado | P2 | [ ] criar | - ---- - -## Runbook de criação (ops) - -1. Deploy API com `WorkOrderIngest` + `Sync` + jobs habilitados conforme ambiente. -2. Obter token Admin e validar: - ```powershell - curl -H "Authorization: Bearer " https:///api/workorders/ops/health - ``` -3. Criar EventBridge/cron (ex.: a cada 15 min) que chama o health endpoint **ou** publica métricas customizadas a partir do JSON. -4. Criar os alarmes da tabela acima no CloudWatch (ALB 5xx + métricas derivadas do health). -5. Agendar checagem diária manual durante piloto e rollout. -6. Marcar status ops na tabela quando cada alarme estiver ativo em staging e prod. - ---- - -## Verificação manual (ops) - -```powershell -# Com token Admin -curl -H "Authorization: Bearer " https:///api/workorders/ops/health -``` diff --git a/docs/work-orders/phase-7/lambda-ingest-discovery.md b/docs/work-orders/phase-7/lambda-ingest-discovery.md deleted file mode 100644 index 61765c8..0000000 --- a/docs/work-orders/phase-7/lambda-ingest-discovery.md +++ /dev/null @@ -1,95 +0,0 @@ -# Lambda Ingest — Descoberta e Mapeamento de Campos - -**Fase:** 7 -**Status:** Documentação de cutover (código Lambda fora deste repositório) - ---- - -## 1. Localização da Lambda - -| Item | Valor | -|------|-------| -| Nome referenciado | `workorder-ingest` | -| Referência código | [TODO.md](../../../TODO.md) L50–51 | -| Fluxo atual | Lambda → DynamoDB (`WorkOrders`) → `POST api/Sync/WorkOrders` | -| Fluxo alvo | Lambda → `POST api/workorders/ingest` (API key) | - -**Ação pendente ops:** localizar repositório/infra AWS (SAM, Terraform, console Lambda) e preencher owner na [phase-7-gates-signoff.md](phase-7-gates-signoff.md). - ---- - -## 2. Tabelas DynamoDB (SyncController) - -| Tabela | Endpoint sync | Uso | -|--------|---------------|-----| -| `WorkOrders` | `POST api/Sync/WorkOrders` | Upsert WO por `work_order_id` | -| `WorkOrderComments` | `POST api/Sync/Comments` | Comentários cliente | -| `VendorReplies` | `POST api/Sync/VendorReplies` | Respostas vendor | - -Cutover Fase 7 foca em **WorkOrders**; comments/replies permanecem no Sync até migração separada. - ---- - -## 3. Mapeamento DynamoDB → API ingest - -Campos lidos em [SyncController.cs](../../../Api.SeaHavenIndustries/Controllers/SyncController.cs) e espelhados em `WorkOrderIngestPayload`: - -| Campo Dynamo | Campo API ingest | Campo SQL | Merge policy (update) | -|--------------|------------------|-----------|------------------------| -| `work_order_id` | `externalWorkOrderId` | `ExternalWorkOrderId` | Chave idempotente | -| `description` | `description` | `Description`, `WorkerOrderTitle` | Sim se não locked | -| `wo_status` | `woStatus` | `Status` (mapeado) | Sim se não locked | -| `severity` | `severity` | `Priority`, `Severity` | Sim se não locked | -| `customer` | `customer` | `Customer` | Direto na criação | -| `site_code` | `siteCode` | `SiteCode` | Sim se não locked | -| `building` | `building` | `Building` | Sim se não locked | -| `address` | `address` | `Locations` (resolve/create) | LocationId | -| `due_date` | `dueDate` | `DueDate` | Sim se não locked | -| `date_reported` | `dateReported` | `DateReported` | Direto | -| `scheduled_start` | `scheduledStart` | `ScheduledStart` | Direto | -| `source_email_s3_key` | `sourceEmailS3Key` | `SourceEmailS3Key` | Direto | -| `created_at` | `createdAt` | `CreatedDate` | Criação only | - -### Mapeamento `wo_status` → SQL `Status` - -| Dynamo | SQL | -|--------|-----| -| `new`, `assigned`, `unknown` | `Open` | -| `in_progress` | `In Progress` | -| `on_hold` | `On Hold` | -| `completed` | `Done` | -| `cancelled` | `Cancelled` | - -### Mapeamento `severity` → `Priority` - -`Sev {severity}` (ex.: `3` → `Sev 3`) - ---- - -## 4. Auth serviço-a-serviço - -| Header | Config | -|--------|--------| -| `X-Ingest-Key` | `WorkOrderIngest:ApiKey` (env `WorkOrderIngest__ApiKey`) | - -Lambda deve enviar o header em cada `POST /api/workorders/ingest`. Não usar JWT de usuário dispatcher. - ---- - -## 5. Estratégia dual-run - -1. **Semana 1–2:** Lambda grava DynamoDB **e** chama API ingest -2. **Validação:** `GET /api/workorders/ops/health` + script amostra `ExternalWorkOrderId` -3. **Cutover:** Lambda só API; `Sync:Enabled=false` -4. **Retire:** backup DynamoDB → desativar tabelas - ---- - -## 6. Critérios de cutover - -- [ ] `POST /api/workorders/board` estável (criação SHOC) -- [ ] Auth ingest testada em staging -- [ ] Zero drift em amostra de 100 WOs -- [ ] Owner Lambda assinou runbook -- [ ] Dual-run validado (ops) -- [ ] `Sync:Enabled=false` em prod (ops) diff --git a/docs/work-orders/phase-7/phase-7-gates-signoff.md b/docs/work-orders/phase-7/phase-7-gates-signoff.md deleted file mode 100644 index 4bb68bd..0000000 --- a/docs/work-orders/phase-7/phase-7-gates-signoff.md +++ /dev/null @@ -1,80 +0,0 @@ -# Phase 7 — Gates Sign-Off Checklist - -**Programa:** Work Orders Board -**Fase:** 7 — Rollout e Produção - ---- - -## Engineering readiness (código — branch `feat/work-orders-phase-7`) - -Itens de engenharia entregues no repositório. Não substituem gates de staging/ops abaixo. - -| # | Item | Evidência | Status | -|---|------|-----------|--------| -| E1 | `GET /api/workorders/ops/health` | `WorkOrderOpsController` + `WorkOrderOpsHealthService` | [x] | -| E2 | `POST /api/workorders/ingest` + `X-Ingest-Key` | `WorkOrderIngestController` + `IngestApiKeyFilter` | [x] | -| E3 | `Sync:Enabled` → 503 no SyncController | `SyncOptions` + checks em WorkOrders/Comments/VendorReplies/All | [x] | -| E4 | Legacy deprecation middleware | `LegacyDeprecationMiddleware` + `LegacyEndpoints` config | [x] | -| E5 | Blazor sunset guard | `BlazorWorkOrderSunsetOptions` + guard em `WorkorderService` | [x] | -| E6 | Alertas documentados | [cloudwatch-alerts.md](cloudwatch-alerts.md) | [x] | -| E7 | Lambda mapping documentado | [lambda-ingest-discovery.md](lambda-ingest-discovery.md) | [x] | -| E8 | Testes coexistência | `dotnet test --filter FullyQualifiedName~WorkOrderPhase7` | [x] | -| E9 | Fase 6 slide-over API | `GET detail/audit/comments/media`, completion-doc, templates | [x] | - -**Config flags (default seguro em prod):** - -- `WorkOrderIngest:Enabled=true` (requer `ApiKey`) -- `Sync:Enabled=true` até cutover -- `LegacyEndpoints:DeprecationEnabled=false` até anúncio -- `BlazorWorkOrderSunset:Enabled=false` até data PO - ---- - -## Gate de entrada (GO Fase 7) - -Bloqueia piloto em produção até todos os itens estarem verdes. - -| # | Gate | Artefato / evidência | Status | -|---|------|----------------------|--------| -| 1 | Fases 0–6 validadas em staging | `docs/work-orders/phase-0` … `phase-6` READMEs | [ ] | -| 2 | Sign-off CTO/PO Fase 0 | [phase-0-gates-signoff.md](../phase-0/phase-0-gates-signoff.md) | [ ] | -| 3 | Dry-run migrations Phase0–Phase6 | [migration-dry-run-report.md](../phase-0/migration-dry-run-report.md) | [ ] | -| 4 | Smoke multi-consumidor | [smoke-checklist.md](../phase-0/smoke-checklist.md) | [ ] | -| 5 | Vendor Portal regression | Checklist dispatch checklist/signoff | [ ] | -| 6 | SHOC E2E staging | Contratos phase-1 … phase-6 integrados | [ ] | -| 7 | Tier volume confirmado | [volume-discovery-report.md](../phase-0/volume-discovery-report.md) | [ ] | - -### Checklist PO ([consumer-inventory.md](../phase-0/consumer-inventory.md)) - -- [ ] App mobile externo confirmado (sim/não/N/A) -- [ ] Data sunset Blazor WO definida: _______________ -- [ ] `FrontendBaseUrl` produção → SHOC configurado -- [ ] Owner Lambda cutover nomeado: _______________ - -**Assinatura GO Fase 7** - -| Papel | Nome | Data | -|-------|------|------| -| CTO | | | -| PO | | | - ---- - -## Gates de saída (DONE Fase 7) - -| Gate | Critério | Status | -|------|----------|--------| -| Piloto | 1–2 dispatchers SHOC em prod; UAT assinado | [ ] | -| Rollout | 100% dispatchers no board SHOC | [ ] | -| Estabilidade | Zero P1 por 2 semanas consecutivas | [ ] | -| Blazor | Módulo WO sunset (`BlazorWorkOrderSunset:Enabled`) | [ ] | -| Lambda | Ingest direto `POST /api/workorders/ingest`; Dynamo/Sync desligados | [ ] | -| Monitoramento | `GET /api/workorders/ops/health` + alertas CloudWatch criados | [ ] | -| Legado | Headers `Sunset`/`Deprecation` nos endpoints legado | [ ] | - -**Assinatura DONE Fase 7** - -| Papel | Nome | Data | -|-------|------|------| -| CTO | | | -| PO | | |