mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 22:23:12 +00:00
245 lines
6.1 KiB
Markdown
245 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 |
|