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