mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-01 23:13:22 +00:00
246 lines
6.1 KiB
Markdown
246 lines
6.1 KiB
Markdown
|
|
# 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](../phase-0/README.md) … [Fase 6](../phase-6/README.md) concluídas e validadas em staging.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Gates
|
|||
|
|
|
|||
|
|
- **Entrada:** [phase-7-gates-signoff.md](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](#uat-dispatchers))
|
|||
|
|
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
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"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](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):**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"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:**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"items": [ { "externalWorkOrderId": "...", "description": "..." } ]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Response:**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"created": 1,
|
|||
|
|
"updated": 0,
|
|||
|
|
"results": [{ "externalWorkOrderId": "ext-wo-12345", "workOrderId": 42, "created": true }]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Mapeamento completo: [lambda-ingest-discovery.md](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`)
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"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](../../../.env.example)
|
|||
|
|
|
|||
|
|
### Blazor (`SeaHavenIndustries`)
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"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](../phase-0/data-ownership-model.md) §3.
|
|||
|
|
|
|||
|
|
1. Congelar `WorkorderService` (bugfix only) até data PO
|
|||
|
|
2. Habilitar `BlazorWorkOrderSunset:Enabled`
|
|||
|
|
3. Smoke final [smoke-checklist.md](../phase-0/smoke-checklist.md) Blazor EF
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Cutover Lambda
|
|||
|
|
|
|||
|
|
Ver [lambda-ingest-discovery.md](lambda-ingest-discovery.md).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Testes automatizados
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
dotnet test SeaHavenIndustries.Tests --filter "FullyQualifiedName~WorkOrderPhase7"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Suite: `WorkOrderPhase7CoexistenceTests.cs`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Critérios de aceite Fase 7
|
|||
|
|
|
|||
|
|
- [x] `GET /api/workorders/ops/health`
|
|||
|
|
- [x] `POST /api/workorders/ingest` com API key
|
|||
|
|
- [x] `Sync:Enabled` feature flag
|
|||
|
|
- [x] Legacy deprecation middleware
|
|||
|
|
- [x] Blazor sunset config + guard mutações
|
|||
|
|
- [x] 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 |
|