shoc-frontend-new/docs/work-orders/board-search-api.md
2026-08-18 17:46:53 -03:00

197 lines
9.2 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.

# 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 |
| `severities` | `severities` | Integers `1`–`5` (Emergency/Reactive) |
| `rescheduled` | `rescheduled` | `true` = reschedule count ≥ 2 |
| `carriedOver` | `carriedOver` | `true` = carried-over count ≥ 2 |
| `addOn` | `addOn` | `true` = `isAddOn` indicator |
| `flagColors` | `flagColors` | Multi `#RRGGBB` (board flag palette) |
| `internalOnly` | `internalOnly` | `true` = WO# starts with `SH` |
| `hasUplift` | `hasUplift` | `true` = WO has standing uplift |
| `upliftStatuses` | `upliftStatuses` | With `hasUplift`; see below |
### `severities`
Multi-select SEV 1–5. Applies to Emergency/Reactive work orders with a transcribed APM severity.
### Indicators (`rescheduled`, `carriedOver`, `addOn`)
Boolean flags matching board badge thresholds (counters ≥ 2 for reschedule/carried-over). `addOn` filters the `isAddOn` indicator (not a WO type).
### `flagColors`
Repeated `#RRGGBB` values from the fixed board flag palette (`WorkOrderFlagColors`).
### `internalOnly`
When `true`, only work orders whose number starts with `SH` (internal placeholder).
### Uplift filters
| FE state | API param | Regra |
| ---------------- | ---------------- | ------------------------------------------------ |
| `hasUplift` | `hasUplift` | `true` = WO has non-cancelled/non-revoked uplift |
| `upliftStatuses` | `upliftStatuses` | Optional refinement when `hasUplift=true` |
Allowed `upliftStatuses`: `pending`, `approved`, `auto_approved`, `rejected` (excludes cancelled/revoked).
Exemplo: pending uplifts only — `hasUplift=true&upliftStatuses=pending`.
## Backend producer (`shoc-backend` `dev`)
These facet keys are handled on `GET /board/search` in `shoc-backend` `origin/dev` ([#45](https://github.com/Sea-Haven-Industries/shoc-backend/pull/45), [#65](https://github.com/Sea-Haven-Industries/shoc-backend/pull/65)). There is no frontend deployment fence.
- `IsAddOn` is owned by migration `20260730150000_WoIsAddOn` (legacy type-7 backfill).
- `20260813193000_SH121_BoardSearchFacets` is a **no-op** so both PRs can land without a duplicate column.
- Pagination matches this contract: `page` is 0-based; `pageSize` default/max is 100.
- Aveta (`avetaOnly`) remains omitted until `avetaRequired` is confirmed.
### `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.