# Work Orders Board & Search API Frontend integration contract for weekly board and advanced search filters. ## Base | Item | Valor | | ------------ | ------------------------------------------- | | Prefixo | `/api/workorders` (alias: `/api/WorkOrder`) | | Auth | `Authorization: Bearer {token}` (JWT) | | Content-Type | Não necessário (GET) | Paths no FE: `API_PATHS.workOrder.board`, `boardSearch`, `lookupsDispatchers`. ## Quando usar qual endpoint | Modo FE | Endpoint | Quando | | --------------------------------------- | -------------------------- | ------------------------------------------------ | | Barra principal (`advApplied === null`) | `GET /board` | Semana + dispatchers + tipo segment + search | | Filtros avançados aplicados | `GET /board/search` | Todos os filtros avançados + paginação/ordenação | | Lookup dispatchers | `GET /lookups/dispatchers` | Popular multi-select de dispatchers | **Não misture parâmetros:** `weekStart`/`weekEnd` só no `/board`; `datePreset` só no `/search`. ## Query builders (FE) - [`board-query-params.ts`](../../src/domain/work-orders/utils/board-query-params.ts) — `toBoardQueryParams`, `toBoardSearchQueryParams` - Arrays na query: repetição simples (`types=2&types=6`), via `toUrlSearchParams` em `work-orders-api.ts` ## Barra → `GET /board` | FE state | API param | Regra | | --------------- | ---------------------- | ----------------------------------------------------------- | | `search` | `search` | Enviar só se `length >= 2`; com 1 char, filtrar client-side | | `weekMonday` | `weekStart` | ISO `YYYY-MM-DD` (segunda) | | — | `weekEnd` | `weekStart + 4` (sexta) | | `dispatcherIds` | `dispatchers` | `__unassigned` → `__unassigned__` | | "My WOs" | `dispatchers={userId}` | Equivalente a `myWorkOrders=true` | | `typeFilter` | `types` / `overdue` | Tipos reais em `types`; past-due via `overdue=true` (OR) | ## Advanced → `GET /board/search` | FE state | API param | Regra | | ---------------- | --------------------- | ------------------------------------------- | | `page` | `page` | **0-based** (primeira página = `0`) | | `pageSize` | `pageSize` | Default `100`, max `100` | | `sortBy` | `sortBy` | `scheduledDate` \| `woNumber` \| `dueDate` | | `sortDir` | `sortDir` | `asc` \| `desc` | | `search` | `search` | `>= 2` chars | | `dateRange` | `datePreset` | PascalCase (ver abaixo) | | `customFrom/To` | `dateFrom` / `dateTo` | Obrigatórios se `datePreset=Custom` | | `sites` (IDs UI) | `sites` | **Site codes**, não location ID | | `types` | `types` | Integers de `WorkOrderType` reais | | overdue (UI) | `overdue` | `true` = past-due (`isPastDue`); ver abaixo | | `dispatchers` | `dispatchers` | `__unassigned` → `__unassigned__` | | `statuses` | `statuses` | Integers 1–10 | | `pmTypes` | `pmTypes` | Strings (labels Problem dropdown) | | `vendorTechs` | `vendorIds` | Integers (resolvidos por companyName) | | `docs` | `docStatuses` | No=2, Yes=1, NN=3 | ### `datePreset` | FE key | API value | | --------------- | ------------- | | `this-week` | `ThisWeek` | | `last-week` | `LastWeek` | | `this-month` | `ThisMonth` | | `last-3-months` | `Last3Months` | | `next-week` | `NextWeek` | | `next-month` | `NextMonth` | | `custom` | `Custom` | ### `types` — WorkOrderType Somente tipos reais de work order. **Não** use sentinel `99` para overdue. | Label FE | API | | --------- | -------------------------------------------- | | PM | `2` | | Emergency | `3` | | Reactive | `6` | | Add-On | `7` | | Other | tipo real do enum (não é filtro de past-due) | ### `overdue` — past-due | FE / UI | API param | Regra | | ------- | -------------- | ----------------------------------------- | | Overdue | `overdue=true` | Filtra work orders past-due (`isPastDue`) | `types` e `overdue` combinam com **OR**: uma WO entra no resultado se corresponder a algum `types` **ou** estiver overdue (quando `overdue=true`). Exemplos: - Só PM e Emergency: `types=2&types=3` - Só past-due: `overdue=true` - PM **ou** past-due: `types=2&overdue=true` ### `statuses` — LifecycleStatus Incomplete=1, Pending=2, Scheduled=3, En Route=4, On Site=5, In Progress=6, Completed=7, Rescheduled=8, Canceled=9, Pending Quote=10. ### `docStatuses` Pending (`No`)=2, Uploaded (`Yes`)=1, N/N (`NN`)=3. ## Respostas ### `/board` ```json { "weekStart": "2026-07-14", "weekEnd": "2026-07-18", "counts": { "total": 42, "returned": 10 }, "scheduled": [], "unscheduled": [] } ``` ### `/board/search` ```json { "items": [], "totalCount": 150, "page": 0, "pageSize": 100, "totalPages": 2, "hasPrevious": false, "hasNext": true } ``` ## Erros HTTP | Situação | Status | | --------------------------------------------------- | ------ | | `weekEnd < weekStart` ou janela > 7 dias | 400 | | `datePreset=Custom` sem datas / `dateTo < dateFrom` | 400 | | `sortBy` inválido | 400 | | Sem token / expirado | 401 | Body típico: `{ "status": "Error", "message": "..." }` — o FE exibe `message` via `ApiError`. ## Add-On indicator See [addon-indicator.md](./addon-indicator.md) (SH-184): backend recalculates `isAddOn` on schedule move/clear with audit; FE only reflects the API value. ## Validação UI O side sheet de filtros avançados valida Custom (From/To obrigatórios e `dateTo >= dateFrom`) antes de aplicar, para evitar 400 desnecessário.