mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 17:23:12 +00:00
197 lines
9.2 KiB
Markdown
197 lines
9.2 KiB
Markdown
# 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.
|