# Fase 4 — Search contextual + Advanced Search **Programa:** Work Orders Board **Objetivo:** Hardening da busca contextual no board semanal, endpoint de advanced search cross-week (Tier S), índices de suporte e harness de load test. **Depende de:** [Fase 0](../phase-0/README.md), [Fase 1](../phase-1/README.md), [Fase 2](../phase-2/README.md), [Fase 3](../phase-3/README.md) **Tier vigente (dev):** **S (provisório)** — ver [search-tier-decision.md](./search-tier-decision.md) --- ## Endpoints ### `GET /api/workorders/board?search=` (hardening) Busca contextual na janela semanal. Campos cobertos: | Campo | Origem | |-------|--------| | Site | `SiteCode` | | WO# | `InternalWONumber`, `WorkerOrderNumber` | | Location | `Locations.Name` | | Dispatcher | `AssignToUser` nome | | PM | `Trade`, `Problem` | | Vendor | `PrimaryDispatch.Vendor.CompanyName` | | Tech | `PrimaryDispatch.Vendor.ContactName` | | Status legado | `Status` | | Lifecycle | label enum (`Scheduled`, `In Progress`, etc.) | **Regras:** - `search` com trim; ignorado se vazio ou < 2 caracteres - `counts.total` — agendadas na semana **sem** search - `counts.returned` — agendadas **com** search ### `GET /api/workorders/board/search` Advanced search cross-week paginado. **Autenticação:** Bearer JWT **Query params:** | Param | Tipo | Descrição | |-------|------|-----------| | `search` | string | Texto livre (mesmos campos do contextual) | | `datePreset` | enum | `thisWeek`, `lastWeek`, `thisMonth`, `last3Months`, `nextWeek`, `nextMonth`, `custom` | | `dateFrom` / `dateTo` | date | Obrigatórios se `datePreset=custom` | | `sites` | string[] | `SiteCode` | | `types` | WorkOrderType[] | Tipo WO | | `dispatchers` | string[] | GUIDs + `__unassigned__` | | `statuses` | LifecycleStatus[] | Status operacional | | `pmTypes` | string[] | Match em `Trade`/`Problem` (contains, case-insensitive) | | `vendorIds` | int[] | Via `PrimaryDispatch.VendorId` | | `docStatuses` | DocStatus[] | Enum `DocStatus` | | `myWorkOrders` | bool | Filtro usuário logado | | `page` | int | Default 1 | | `pageSize` | int | Default 50; max 100 (Tier S/M) | | `sortBy` | string | `scheduledDate` (default), `woNumber`, `dueDate` | | `sortDir` | string | `asc` / `desc` | **Response:** `PagedResult` ```json { "items": [ /* WorkOrderBoardRowDto */ ], "totalCount": 120, "page": 1, "pageSize": 50, "totalPages": 3, "hasNext": true, "hasPrevious": false } ``` **Exemplo:** ```bash curl -H "Authorization: Bearer " \ "https://localhost:5001/api/workorders/board/search?datePreset=thisMonth&sites=BK5&search=HVAC&page=1" ``` --- ## Matriz preset → intervalo de datas Base: **segunda-feira ISO** (`WorkOrderSearchDateRangeResolver`). | Preset | Intervalo | |--------|-----------| | `thisWeek` | Seg–Dom da semana ISO corrente | | `lastWeek` | Seg–Dom da semana ISO anterior | | `nextWeek` | Seg–Dom da próxima semana ISO | | `thisMonth` | 1º–último dia do mês corrente | | `nextMonth` | 1º–último dia do mês seguinte | | `last3Months` | Hoje − 3 meses → hoje | | `custom` | `dateFrom` / `dateTo` (400 se ausentes) | **Filtro de data:** `ScheduledDate` no intervalo **OU** `ScheduleWeekOnly && TargetWeek` intersectando o intervalo. Exclui templates e `IsDeleted`. --- ## Código entregue | Camada | Arquivo | |--------|---------| | Search filter | `SeaHaven.DataServices/Helpers/WorkOrderBoardSearchFilter.cs` | | Query filters | `SeaHaven.DataServices/Helpers/WorkOrderBoardQueryFilters.cs` | | Projeção | `SeaHaven.DataServices/Helpers/WorkOrderBoardProjection.cs` | | Date presets | `SeaHaven.Services/Helpers/WorkOrderSearchDateRangeResolver.cs` | | Advanced data | `SeaHaven.DataServices/Implementation/WorkOrderAdvancedSearchDataService.cs` | | Advanced service | `SeaHaven.Services/Implementation/WorkOrderAdvancedSearchService.cs` | | DTOs | `SeaHaven.Services/DTOs/WorkOrderBoardDTOs.cs` | | API | `WorkOrderController` — `GET board/search` | | Migration | `20260624200000_Phase4_SearchIndexes.cs` | | Testes | `SeaHavenIndustries.Tests/WorkOrderBoardSearchTests.cs` | | Load test | `scripts/load-test/work-order-search.k6.js` | | Seed | `scripts/seed-work-orders-search.ps1` | --- ## Gates de aceite ### Dev (implementação) - [x] Helper de search compartilhado + testes por campo - [x] `GET /board/search` paginado com filtros FE - [x] Date presets alinhados ao SHOC (ISO Monday) - [x] Migration índices Phase 4 - [x] Harness k6 + seed sintético (Tier S local) - [x] Endpoints legados inalterados - [x] ~12 testes unitários novos (total ~80) ### Staging/prod (GO — pendente) - [ ] Volume Discovery preenchido — [volume-discovery-report.md](../phase-0/volume-discovery-report.md) - [ ] Tier assinado — [search-tier-decision.md](./search-tier-decision.md) - [ ] Load test em staging com volume real - [ ] Latência dentro do SLO do tier confirmado - [ ] Smoke Portal/Blazor inalterados --- ## SLOs Tier S (load test local) | Cenário | Endpoint | p95 | |---------|----------|-----| | Board sem search | `GET /board?weekStart=...` | < 800ms | | Board com search | `GET /board?search=BK5` | < 1000ms | | Advanced preset | `GET /board/search?datePreset=thisMonth` | < 1200ms | | Advanced multi-filter | sites + types + search | < 1500ms | Ver [scripts/load-test/README.md](../../scripts/load-test/README.md). --- ## Fora de escopo - Full-text search (Tier L) - Search externo dedicado (Tier XL) - Lookups PM catalog (`PM_TYPES`) — backlog #17 - Alterações em endpoints legados