# Backlog, Known Gaps and Go-Live Hardening

Honest statement of what is and is not in this codebase, so the team plans the remaining work rather than discovering it.

## 1. Not included (by design, for the dev team)

| Item | Why | Suggested approach |
|------|-----|--------------------|
| Web front-end (ops console, client portal) | UI stack is the team's choice; the API is complete and documented | SPA (React/Vue) against `docs/openapi.yaml`; start with dashboard, inbound, outbound, exceptions, AI recommendations |
| RF device app | Device/OS choice (Android Zebra/Honeywell) | Thin state machine over `/rf/*`: render `next.prompt`, scan into `expect`, send with an `Idempotency-Key` per scan |
| Label printing (LPN, carton, shipping labels) | Printer stack specific | ZPL templates rendered from `handling_units.lpn` (Code128 with the mod-10 check digit) and `packages`; carrier labels via the carrier API or WeStore Freight |
| Carrier integrations | Per carrier | `carriers.integration_type = api`: implement a `CarrierGateway` interface in `Outbound/Services` called from `ShipmentService::manifest()` |
| SAP export of billing | Group SAP specifics | Consume `billing.period_closed` from the outbox or call `GET /billing/periods/{id}` and post to SAP; store the document number via `/export` |
| OCR for PDF/image supplier documents | Needs a document pipeline | Any OCR (Textract, Azure, Tesseract) → send text to `POST /asns/extract` |
| EDI (ASN 856, order 940/945) | Per client | Map to `POST /asns` / `POST /orders`; webhooks give the 945 |

## 2. Known gaps to close before go-live

| Gap | Impact | Fix |
|-----|--------|-----|
| Allocation re-run after a hold cancels reservations | Orders go back to `confirmed` and need `POST /orders/{id}/allocate` again | Add a job that re-allocates affected orders automatically after `allocation.cancelled_by_hold` |
| Partial shipment leaves order status derived from lines but does not re-wave the remainder | Remainder must be waved again manually | Add "backorder" handling: after partial dispatch, keep remaining allocations and allow re-waving (`OrderStatus::Allocated`) |
| Serial numbers on pack/ship are carried per allocation; picking a subset of serials from a tote during packing requires `serials` to be passed | Operators must scan serials at pack for serialised SKUs | UI must enforce serial scanning at pack for `is_serial_tracked` |
| Cycle count `count_type = sku` / `abc` scope selection is approximated (location-based with product filters) | Fine for v1 | Dedicated SKU-count generator walking `inventory_balances` by product |
| Replenishment uses min/max only; demand-driven replen is triggered manually (`ensureForDemand`) | Wave release does not pre-replenish | Call `ReplenishmentService::ensureForDemand()` from `WaveService::release()` for forward-pick shortfalls |
| Transfer orders between warehouses: tables and statuses exist, service not implemented | Inter-site transfers are done as order + ASN manually | `TransferService`: confirm → outbound order (type transfer) → dispatch posts `transfer_out` to in-transit → ASN at destination → `transfer_in` |
| Labor: clock-in is recorded but productivity ignores breaks/indirect time | Performance % slightly optimistic | Add `labor_activities` of type `idle`/`break` from RF and subtract |
| Storage billing counts pallets by LPN type `pallet`; loose stock on shelves bills by location-day only | Confirm with finance which basis each client contract uses | Rate card: enable only the applicable `storage_*` codes per client |
| Larastan baseline contains ~380 relation-typing notices (`phpstan-baseline.neon`) | None at runtime | Add generics to relations (`BelongsTo<Product, $this>`) progressively and shrink the baseline |
| `shouldBeStrict` is off (only silent-discard prevention is on) | N+1 queries possible in list endpoints with large pages | Enable `Model::preventLazyLoading()` in local/CI and add the missing eager loads |
| Reports are views without materialisation | Fine to ~10M ledger rows | Materialise `v_pick_productivity` / `v_billable_summary` nightly if dashboards slow down |

## 3. Hardening checklist

- [ ] Postgres roles applied (`docs/DEPLOYMENT.md` §3), including `REVOKE UPDATE, DELETE` on the ledger and audit tables
- [ ] Read-only connection configured for `nl_query`
- [ ] Redis for cache/queue/rate limits; outbox publisher under Supervisor with auto-restart
- [ ] Backups + restore test; WAL archiving
- [ ] Load test: 20 concurrent RF users picking from the same wave (the concurrency tests cover correctness, not throughput)
- [ ] Pen-test the API (auth, scoping, idempotency replay, webhook signature verification on the receiving side)
- [ ] Review rate limits for RF scanners (`config/wms.php`)
- [ ] AI: set `daily_cost_cap_usd` per client; keep every use case in `advise` for the first month; confirm PII policy (consignee data is never sent except address validation, which is not shipped)
- [ ] Client webhooks: agree event list and signature verification with each client's IT
- [ ] Train supervisors on exception handling (`docs/OPERATIONS-PLAYBOOK.md` §3)

## 4. Phase 2 candidates

Cross-docking flows, pick-to-light/voice integration, vision-based receiving (pallet photo → ASN match), carrier rate shopping, client-facing chatbot over the portal, dynamic labor scheduling, multi-currency billing, 3D warehouse visualisation on top of `locations.coord_x/coord_y`, mobile supervisor app, SLA engine (dock-to-stock, order-to-ship targets per client with alerts).
