shoc-backend/docs/work-orders/phase-1/README.md

159 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Fase 1 — Weekly Board (leitura)
**Programa:** Work Orders Board
**Objetivo:** Endpoint window-based para carregar a visão semanal do SHOC (Mon–Fri + Unscheduled) com projeção das 14 colunas operacionais.
---
## Endpoints
### `GET /api/workorders/board`
Retorna WOs agendadas na semana + seção **Unscheduled** em uma única chamada.
**Autenticação:** Bearer JWT (`[Authorize]`)
**Query params:**
| Param | Obrigatório | Descrição |
|-------|-------------|-----------|
| `weekStart` | Sim (`BindRequired`) | Segunda-feira da semana (`YYYY-MM-DD`). Omitir retorna **400**. |
| `weekEnd` | Não | Default: `weekStart + 4 dias` (sexta). Janela pode ter até 7 dias. |
| `dispatchers` | Não | Lista de GUIDs; use `__unassigned__` para não atribuídos. **Ignorado** quando `myWorkOrders=true`. |
| `myWorkOrders` | Não | `true` → filtra `AssignTo == usuário logado` e tem **precedência** sobre `dispatchers` (não é AND). |
| `types` | Não | Valores enum `WorkOrderType` (`PM`, `PO`, `Emergency`, etc.) |
| `search` | Não | Busca contextual (site, WO#, location, dispatcher, trade, vendor, status) |
**Exemplo:**
```bash
curl -H "Authorization: Bearer <token>" \
"https://localhost:5001/api/workorders/board?weekStart=2026-06-22&myWorkOrders=true"
```
**Response:**
```json
{
"weekStart": "2026-06-22",
"weekEnd": "2026-06-26",
"counts": { "returned": 42, "total": 58 },
"unscheduled": [ /* WorkOrderBoardRowDto[] */ ],
"scheduled": [ /* WorkOrderBoardRowDto[] — agrupar por dayGroup no FE */ ]
}
```
- `counts.total` — WOs agendadas na semana (filtros dispatcher/tipo, **sem** search)
- `counts.returned` — WOs agendadas após aplicar search
- `dayGroup` — `monday`…`friday` para dias úteis; **`null` no sábado/domingo** (a janela pode incluir fim de semana; o FE deve tratar `dayGroup` nulo)
- Referência de dia / past-due: **UTC** nesta fase (timezone de negócio fica para fase posterior)
### `GET /api/workorders/lookups/dispatchers`
Lista opções para o filtro/dropdown de assignee do board.
**Escopo atual (placeholder):** todos os users com `IsDeleted != true` — ainda **sem** filtro por role. Quando roles de assignee estiverem definidos, este lookup será restrito.
```json
[
{ "id": "guid", "name": "Jane Doe", "initials": "JD", "color": "#4A90D9" }
]
```
---
## Matriz coluna → campo API
| Coluna board | Campos response |
|--------------|-----------------|
| WO# | `woNumber`, `rescheduleCount`, `carriedOver` |
| Type | `workOrderType`, `isPastDue` |
| Site | `siteCode`, `locationName`, `pocName`, `pocPhone`, `pocNotes` |
| Status | `lifecycleStatus`, `lifecycleStatusLabel`, `legacyStatus` |
| Assignee | `dispatcherId`, `dispatcherName`, `initials`, `color` |
| Due | `dueDate` |
| Scheduled | `scheduledDate`, `targetWeek`, `scheduleWeekOnly`, `dayGroup` |
| Vendor | `vendorId`, `vendorName`, `techName`, `techPhone` |
| Appt | `apptDate`, `apptTime` |
| Past Due | `isPastDue` (derivado on-read) |
| Carried | `carriedOver` |
| Reschedule | `rescheduleCount` |
| Doc | `docStatus` |
| Actions | FE only |
---
## Regras de derivação
### isPastDue
```
ScheduledDate < UTC hoje
AND LifecycleStatus NOT IN (Complete, Canceled, Closed)
```
Implementação: `SeaHaven.Services/Helpers/WorkOrderDerivedFields.cs`
### Vendor / Appt
Projeção read-only via `WorkOrder.PrimaryDispatchId` → `Dispatch` → `Vendor` ([ADR](../phase-0/adr-vendor-source-of-truth.md)).
### Janela semanal
WO entra em **scheduled** se:
- `ScheduledDate` entre `weekStart` e `weekEnd`, **ou**
- `ScheduleWeekOnly == true` e `TargetWeek == weekStart`
**Unscheduled:** `ScheduledDate == null` e status não terminal (`LifecycleStatusSets.Terminal`).
---
## Código entregue
| Camada | Arquivo |
|--------|---------|
| DTOs | `SeaHaven.Services/DTOs/WorkOrderBoardDTOs.cs` |
| Derived fields | `SeaHaven.Services/Helpers/WorkOrderDerivedFields.cs` |
| Data | `SeaHaven.DataServices/Implementation/WorkOrderBoardDataService.cs` |
| Service | `SeaHaven.Services/Implementation/WorkOrderBoardService.cs` |
| API | `Api.SeaHavenIndustries/Controllers/WorkOrderController.cs` (`board`, `lookups/dispatchers`) |
| Migration | `Data.SeaHavenIndustries/Migrations/20260701120000_Phase1_BoardIndexes.cs` |
| Testes | `SeaHavenIndustries.Tests/WorkOrderDerivedFieldsTests.cs`, `WorkOrderBoardServiceTests.cs` |
---
## Gates de aceite
### Desenvolvimento (concluído)
- [x] Endpoint `GET board` — semana + Unscheduled
- [x] Projeção 12/14 colunas de dados
- [x] `isPastDue` derivado on-read
- [x] Vendor via dispatch primário
- [x] Filtros dispatcher / My WOs / tipo / search
- [x] Contador X of Y
- [x] Índices Tier S
- [x] 14 testes unitários board (+ 12 Fase 0 = 26 total)
### Staging / produção (pendente)
- [ ] Sign-off CTO/PO (herda gates Fase 0)
- [ ] Dry-run migration Phase0 + Phase1 em staging
- [ ] Tier volume confirmado em staging/prod
- [ ] Smoke checklist Blazor / Sync / Portal
- [ ] Gate Vendor Portal regression (endpoints dispatch inalterados)
- [ ] Latência aceitável com volume real (Tier S: &lt; 25k WOs)
- [ ] Feature flag SHOC board em staging
---
## Coexistência
Endpoints legados (`GetWorkOrderList`, `GetWorkorderById`, etc.) **não foram alterados**. O board usa contrato novo em rotas separadas.
---
## Próximo passo
**Fase 2** — Inline edit + concorrência (dual RowVersion, audit por campo, PATCH granular).