shoc-backend/docs/auditoria-work-orders-api-vs-frontend.md

299 lines
16 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.

# Auditoria — API Work Orders vs Frontend (WorkOrders.tsx)
**Data:** 2026-06-19
**Fonte da verdade (FE):** `seahaven.desing/src/pages/WorkOrders.tsx`
**Backend auditado:** `seaheven.api`
---
## Resumo executivo
| Métrica | Valor |
|---------|-------|
| Compatibility Score | **24/100** |
| Backend Readiness | **Not Ready** |
| Confidence | **High** |
A API atual foi construída para **CRUD legado** (listagem paginada, detalhe rico, dispatch). O frontend `WorkOrders.tsx` define um **Schedule Board operacional** (visão semanal, 14 colunas, edição inline, advanced search, completion doc WO-level). Os contratos são fundamentalmente diferentes.
**O que funciona hoje:** id, dueDate, location (parcial), CRUD básico, detalhe rico, comments, audit field-based, mídia WO-level, reatribuição, dispatch.
**O que falta:** listagem window-based, 14 colunas board, PATCH inline, campos derivados, advanced search, completion doc WO-level, jobs Past Due/Carried Over, status 10 labels, WO# 11 dígitos.
---
## Endpoints que existem hoje
| Endpoint | O que entrega |
|----------|----------------|
| `GET GetWorkOrderList` | Lista **paginada** (default 12): id, número, título, location, priority, status, dueDate, assignedTo, lastUpdated |
| `GET Getworkorders` / `GetworkordersDD` | Lista legada para admin/dropdown |
| `GET GetFilteredWorkorder` / `2` | Filtros legados (assignee, location, priority, status, due date buckets) — carrega tudo em memória |
| `GET GetWorkorderById` / `{id}` | Detalhe: título, descrição, datas, status, problem, trade, POC, attachments, comments, audit, dispatches |
| `POST AddWorkorder` | Criação via form: título, descrição, assignee, dueDate, location, priority, mídia, contacts/categories |
| `POST/PUT EditWorkorder` | Update parcial via form (subset mapeado ao service) |
| `POST ChangeStatus` | Muda status (string livre) + audit |
| `POST ChangeAssignment` | Reatribui dispatcher + audit |
| `POST AddComment` / `AddCommentJson` | Comentário + upload opcional |
| `GET GetComments` / `GetCommentsByWorkorderId` | Lista comentários |
| `DELETE DeleteWorkorder` | **Delete físico** (não soft cancel) |
| Dispatch endpoints | Vendor, checklist, signoff, verify — **nível dispatch**, não board |
**Lookups relacionados (outros controllers):** `Common/GetUsers`, `Location/GetLocationList`, `Vendor/GetVendorList` — paginados, contrato diferente do FE.
**Documentado mas não implementado no código:** `GET GetWorkOrdersBoard`, `IWorkOrderBoardMapper`, `IWorkOrderStatusMapper` (ver `docs/adr/work-orders-board-api.md`).
---
## 1. Listagem da tela principal (visão semanal)
| Frontend espera | API entrega hoje | Gap |
|-----------------|------------------|-----|
| 1 call por semana (`weekStart` / `weekEnd`) | Paginação `page` / `pageSize` sem janela temporal | Sem fetch window-based |
| WOs agrupados por dia (Mon–Fri) | Lista flat paginada | Sem `scheduledDate` na projeção de listagem |
| Seção **Unscheduled** sempre visível no topo | Só WOs da página atual | Sem WOs sem data retornados independente da semana |
| `targetWeek` (scheduling week-only) | Campo inexistente na entidade/API | Não implementado |
| Contador `X of Y` da semana ativa | `totalCount` global paginado | Contagem inadequada para o board |
| Skeleton Mon–Fri vazios | N/A (FE-only) | OK — responsabilidade do FE |
**Evidência BE:** `WorkOrderDataService.GetWorkOrderListPagedAsync` — projeção L163-183, sem `ScheduledDate`, `SiteCode`, vendor, type.
---
## 2. Colunas da tabela (`COLS`)
Definidas no FE em `WorkOrders.tsx` L4234-4249.
| Coluna FE | Campo(s) FE | API hoje | Gap |
|-----------|-------------|----------|-----|
| Grip | drag reorder | Ausente | FE local-only; BE não persiste ordem |
| Flag | flag pessoal | Ausente | FE session-only |
| **SITE** | `site`, `pocName`, `pocPhone`, `pocNotes` | List: `location` (name); Detail: POC via `WorkOrderContacts` | Sem `siteCode` na listagem; sem POC na lista |
| **WO** | `woNumber`, `rescheduleCount`, `carriedOver` | `internalWONumber` / `workerOrderNumber` | Formato ≠ 11 dígitos; sem badges ↻ ↷N |
| **TYPE OF WO** | `type` (PM / Reactive / Emergency / Add-On / Overdue) | Não exposto (`WorkOrderType` em `db.txt`, não mapeado em EF) | Coluna inoperante |
| **ASSIGNED TO** | `dispatcherId` + avatar/cor | `assignedTo` (nome completo); `AssignTo` = GUID Identity | Sem id/initials/color para avatar |
| **SCHEDULE ON** | `scheduledOn`, `targetWeek` | Detail: `scheduledDate`; **list: ausente** | Listagem sem data de agendamento |
| **DUE DATE** | `dueDate` | `dueDate` | **OK** na listagem |
| **SERVICE** | `pm` | Detail: `trade` / `problem`; list: ausente | Coluna vazia na lista |
| **VENDOR** | `company`, `tech`, `techPhone` | Detail: `dispatches` → vendor; list: ausente | Coluna vazia na lista |
| **APPT TIME** | `apptTime` (ex: "07:00 – 09:00") | Entidade: `ScheduledStart`; sem `ScheduledEnd` | Janela de horário incompleta |
| **STATUS** | 10 labels + overlay Past Due | String legada DB + enum 5 valores API | Sem mapping para status operacionais do FE |
| **COMP DOC** | `docStatus` (Yes / No / NN) | Ausente no WO | Completion existe só no **dispatch** (`VerifyDispatch`) |
| Actions | View / Edit | `GetWorkorderById` separado | Detalhe existe; contrato diferente |
---
## 3. Filtros e busca
### Barra principal (FE L5083-5099)
| Frontend | API hoje | Gap |
|----------|----------|-----|
| **Dispatcher** multi-select + `__unassigned__` + default usuário logado | `assignee` single string; `__unassigned` suportado em `GetWorkOrderList` | Multi-select e default "My WOs" não cobertos |
| **Semana ativa** | Sem filtro `ScheduledDate` | Filtro semanal inexistente |
| **Tipo** (All / PM / Reactive / Emergency / Add-On / Overdue) | Sem filtro por work order type | Inexistente |
| **Busca contextual** na semana (site, wo#, dispatcher, location, pm, company, tech, status) | Search em 5 campos (`InternalWONumber`, `WorkerOrderNumber`, `Title`, `Location`), escopo global paginado | Campos e escopo incompatíveis |
### Advanced Search (FE L4255-4324)
| Frontend | API hoje | Gap |
|----------|----------|-----|
| Lista plana cross-week | Ausente | Sem endpoint dedicado |
| Date range (this-week, last-week, this-month, last-3-months, next-week, next-month, custom) | `GetFilteredWorkorder` com due date buckets legados | Semântica diferente |
| Filtros: sites[], types[], dispatchers[], statuses[], pmTypes[], vendorTechs[], docs[] | Parcial em endpoints legados | Cobertura incompleta |
---
## 4. Edição inline (spreadsheet-style)
| Frontend | API hoje | Gap |
|----------|----------|-----|
| PATCH por campo (site, wo#, type, dispatcher, schedule, due, service, vendor, appt, status…) | `EditWorkorder` (form multipart) + `ChangeStatus` + `ChangeAssignment` separados | Sem update granular por campo |
| Auto-schedule: `Incomplete` → `Scheduled` quando data + dispatcher | Ausente no BE | Regra `maybeAutoSchedule` só no FE |
| `rescheduleCount++` ao mudar `scheduledOn` | Campo inexistente | Badge ↻ impossível |
| Limpar `isPastDue` ao reagendar para data futura | Campo derivado inexistente | Past Due não limpa via API |
| Bloquear mudança de status se `isPastDue` | `ChangeStatus` aceita qualquer string | Sem validação 422 |
| WO# único 11 dígitos normalizado | Gerador `WO-{yyyyMMdd}-{random}` ou sync sequencial `10000001` | Formato e unicidade incompatíveis |
| WO cancelado read-only | Sem enforcement no BE | Só lógica no FE (`WOSlideOver` L2380) |
**Evidência BE:** `WorkOrderController.Editworkorder` L182-192 mapeia subset para `UpdateWorkOrderDTO` — ignora `Problem`, `Trade`, `ScheduledDate`, `Source` apesar de existirem em `EditWorkorder_DTO`.
---
## 5. Criação de WO
| Frontend | API hoje | Gap |
|----------|----------|-----|
| Wizard `NewWOWizard` + inline `InlineRow` | `POST AddWorkorder` | Campos do wizard majoritariamente ausentes |
| Campos: site, type, scheduledOn, targetWeek, pm, company, tech, appt, POC | `CreateWorkOrderDTO`: title, description, assignTo, dueDate, location | Contrato incompleto |
| Status inicial `Incomplete` | Cria com `WorkOrderStatus.Open` | Status inicial diferente |
| `scheduleWeekOnly` / `targetWeek` | Ausente | Week-only scheduling impossível |
| Navegação automática para semana do WO criado | Depende de listagem semanal | Listagem incompatível |
---
## 6. Cancelamento
| Frontend | API hoje | Gap |
|----------|----------|-----|
| Soft cancel → status `Canceled` | `POST ChangeStatus(id, "Canceled")` manual | Sem endpoint `POST cancel` dedicado |
| WO cancelado não editável | Sem bloqueio no BE | Enforcement só no FE |
| Delete permanente (Admin) | `DELETE DeleteWorkorder` — delete físico | Comportamento diverge do soft cancel FE |
---
## 7. Slide-over (`WOSlideOver`)
| Tab FE | API hoje | Gap |
|--------|----------|-----|
| **Info** | `GET GetWorkorderById` | Omite `siteCode`; sem campos derivados FE (`isPastDue`, `rescheduleCount`, etc.) |
| **Comments** | `AddComment` + `GetCommentsByWorkorderId` | Formato FE `{authorId, text, time}` vs BE `{Commenttext, FirstName, Documents}` |
| **Audit Log** | `WorkOrderAuditLog` retornado no detalhe | Schema `{fieldName, oldValue, newValue, action}` vs FE `{type: manual\|system, dispatcherId?, action, time}` |
| **Completion Doc** | `SignOffName` / `SignOffAttachment` no WO; `VerifyDispatch` no dispatch | Sem template por service type, PDF, `docStatus` WO-level |
| **Extra Docs / Media** | `BeforPhoto`, `AfterPhoto`, `workOrderAttachments` | Sem `MediaFile.category`; sem API extra docs dedicada |
---
## 8. Regras de sistema (background jobs)
| Frontend assume | API hoje | Gap |
|-----------------|----------|-----|
| Job Past Due: `scheduledOn < hoje` + não terminal → `isPastDue=true` | Ausente (zero `BackgroundService` / Hangfire / Quartz no repo) | Flag nunca setada automaticamente |
| Job Carried Over: virada de semana → `carriedOver++` | Ausente | Contador ↷N nunca incrementado |
| Type Overdue promotion | Ausente | Filtro/tipo Overdue não automático |
| Sync APM | `SyncController` POST manual (DynamoDB → SQL) | On-demand, não integrado à UX do board |
---
## 9. Lookups (catálogos)
| FE usa (mock estático) | API relacionada | Gap |
|------------------------|-----------------|-----|
| `DISPATCHERS` (id, name, initials, color) | `Common/GetUsers` | Sem initials/color; paginado; ids são GUIDs |
| `SITE_OPTIONS` (code → city, state) | `Location/GetLocationList` | Sem lookup por site code; sem mapeamento BK5 → Dallas |
| `PM_TYPES` | Ausente | Sem catálogo de service types |
| `TECHNICIANS` (name, company, phone) | `Vendor/GetVendorList` | Sem endpoint technicians |
| `WEEK_RANGES` (Mon–Fri + flag LIVE) | Ausente | Sem endpoint weeks |
---
## Contrato de dados — campo a campo
| Campo FE (`WorkOrder`) | Campo BE | Status |
|------------------------|----------|--------|
| `id` | `WorkOrder.Id` | SUPPORTED |
| `woNumber` | `InternalWONumber` / `WorkerOrderNumber` | PARTIALLY_SUPPORTED — formatos conflitantes |
| `site` | `SiteCode` | PARTIALLY_SUPPORTED — entidade tem; API omite na listagem |
| `type` | — (`WorkOrderType` só em SQL) | NOT_SUPPORTED |
| `dispatcherId` | `AssignTo` (GUID) | PARTIALLY_SUPPORTED |
| `scheduledOn` | `ScheduledDate` | PARTIALLY_SUPPORTED — list omite |
| `dayGroup` / `dayLabel` | — | NOT_SUPPORTED (derivado) |
| `location` | `Locations.Name` | SUPPORTED (via join) |
| `pm` | `Trade` / `Problem` | PARTIALLY_SUPPORTED |
| `company` / `tech` | `Dispatches` → `Vendor` | PARTIALLY_SUPPORTED — não inline na lista |
| `techPhone` | — | NOT_SUPPORTED |
| `apptTime` | `ScheduledStart` (sem end) | PARTIALLY_SUPPORTED |
| `status` | `Status` (string livre) | PARTIALLY_SUPPORTED — 10 vs 5+ formatos |
| `docStatus` | — | NOT_SUPPORTED |
| `pocName` / `pocPhone` / `pocNotes` | `WorkOrderContacts` | PARTIALLY_SUPPORTED — notes ausente |
| `dueDate` | `DueDate` | SUPPORTED |
| `rescheduleCount` | — | NOT_SUPPORTED |
| `carriedOver` | — | NOT_SUPPORTED |
| `originalWeek` / `originalDate` | — | NOT_SUPPORTED |
| `isPastDue` | — | NOT_SUPPORTED (derivado) |
| `targetWeek` | — | NOT_SUPPORTED |
---
## Regras de negócio — FE vs BE
| Regra FE | Evidência FE | BE hoje | Status |
|----------|--------------|---------|--------|
| Auto-schedule Incomplete → Scheduled | `maybeAutoSchedule` L500-506 | Ausente | NOT_SUPPORTED |
| Reschedule incrementa contador | `updateScheduledOn` L4856 | Ausente | NOT_SUPPORTED |
| Reschedule limpa Past Due | L4851-4857 | Ausente | NOT_SUPPORTED |
| Status bloqueado em Past Due | `StatusCell` L1120-1159 | `ChangeStatus` sem validação | NOT_SUPPORTED |
| WO# único 11 dígitos | `findDuplicateWONumber` L4897 | Gerador random; `InternalNumberExistsAsync` sem normalização | NOT_SUPPORTED |
| Cancel → Canceled, read-only | `cancelWO` L4946; `WOSlideOver` L2380 | `ChangeStatus` manual | PARTIALLY_SUPPORTED |
| Carried over job semanal | Audit derivado L2414-2416 | Sem job | NOT_SUPPORTED |
| Completion doc por tipo de serviço | `CompDocDialog` L3902+ | Dispatch verify only | NOT_SUPPORTED (WO-level) |
| Emergency/Reactive → media flow | `isMediaWO` L332-334 | Mídia WO genérica | PARTIALLY_SUPPORTED |
---
## Diagrama — contrato atual vs esperado
```
HOJE (GetWorkOrderList) FRONTEND (WorkOrders.tsx)
───────────────────── ─────────────────────────
Paginação 12/page 1 call = semana inteira
Sem ScheduledDate Agrupamento Mon–Fri
Sem siteCode, type, vendor 14 colunas preenchidas
Sem unscheduled semantics Seção Unscheduled fixa
5 status legados 10 status + Past Due overlay
CRUD admin Schedule Board operacional
EditWorkorder (form) PATCH inline por célula
```
---
## Cobertura por área
| Área | Cobertura estimada |
|------|-------------------|
| Listagem board (visão semanal) | ~5% |
| Colunas da tabela (14) | ~15% |
| Filtros e busca | ~10% |
| Edição inline | ~0% |
| Criação (wizard/inline) | ~25% |
| Slide-over (detalhe) | ~40% |
| Completion doc WO-level | ~0% |
| Background jobs | ~0% |
| Lookups/catálogos | ~20% |
---
## Critical blockers
1. **Sem API window-based** para visão semanal + Unscheduled — tela principal não carrega.
2. **Contrato de listagem incompatível** com 14 colunas do board.
3. **Campos persistidos ausentes** — `rescheduleCount`, `carriedOver`, `targetWeek`, `docStatus`, `isPastDue`.
4. **Sem PATCH inline** — edição spreadsheet-style impossível.
5. **Advanced search cross-week inexistente.**
6. **Status 10 valores + Past Due** sem mapping layer implementado.
7. **Completion doc WO-level inexistente** — coluna COMP DOC inoperante.
8. **WO# 11 dígitos único** não suportado.
9. **Jobs Past Due / Carried Over ausentes.**
---
## Non-critical gaps
- Reorder intra-dia persistido (FE já local-only)
- Flags pessoais (FE session-only)
- Paginação 12/24/48/96 (FE não implementou)
- Bulk select (FE não implementou)
- `[Authorize]` comentado no `WorkOrderController` (risco de segurança)
---
## Referências
- Frontend: `seahaven.desing/src/pages/WorkOrders.tsx`
- Controller: `Api.SeaHavenIndustries/Controllers/WorkOrderController.cs`
- Data service: `SeaHaven.DataServices/Implementation/WorkOrderDataService.cs`
- Entidade: `Data.SeaHavenIndustries/Models/WorkerOrder.cs`
- ADR (proposto, não implementado): `docs/adr/work-orders-board-api.md`
- Spikes: `docs/spikes/consumer-audit-getworkorderlist.md`, `search-strategy.md`, `status-mapping.md`, `work-order-type.md`
---
## Classificação final
| Métrica | Valor |
|---------|-------|
| Compatibility Level | **Minimally Compatible** |
| Backend Readiness | **Not Ready** |
| Confidence | **High** |
Este documento reporta apenas **findings** — gaps entre o que a API entrega hoje e o que o frontend especifica. Não inclui propostas de implementação.