mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-01 19:13:13 +00:00
Past Due must track the deadline (Due Date), not Schedule On. Keep dueDate and scheduledDate PATCH mutations independent so rescheduling alone does not clear Past Due.
162 lines
5.4 KiB
Markdown
162 lines
5.4 KiB
Markdown
# 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
|
||
|
||
```
|
||
DueDate != null
|
||
AND DueDate < UTC hoje
|
||
AND LifecycleStatus NOT IN (Completed, Canceled)
|
||
```
|
||
|
||
`DueDate` null → `isPastDue = false`. Independent of `ScheduledDate` (Schedule On).
|
||
|
||
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: < 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).
|