# 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.