feat(api): complete M5 swap and dispatch backend slice
This commit is contained in:
@@ -24,10 +24,11 @@ What was validated live against the deployed stack:
|
||||
- client coverage incident feed for geofence and override review
|
||||
- client blocked-staff review and invited shift-manager creation
|
||||
- client hub, order, coverage review, device token, and late-worker cancellation flows
|
||||
- client swap-request review, dispatch-team management, and dispatch-candidate ranking
|
||||
- client invoice approve and dispute
|
||||
- staff dashboard, availability, payments, shifts, profile sections, documents, certificates, attire, bank accounts, benefits, and time card
|
||||
- staff benefit history read model
|
||||
- staff availability, profile, tax form, bank account, shift apply, shift accept, push token registration, clock-in, clock-out, location stream upload, and swap request
|
||||
- staff availability, profile, tax form, bank account, shift apply, shift accept, push token registration, clock-in, clock-out, location stream upload, swap request, and completed-shift submission
|
||||
- direct file upload helpers and verification job creation through the unified host
|
||||
- client and staff sign-out
|
||||
|
||||
@@ -109,6 +110,20 @@ Important operational rules:
|
||||
- background location streams are stored as raw batch payloads in the private v2 bucket and summarized in SQL for query speed
|
||||
- incident review lives on `GET /client/coverage/incidents`
|
||||
- confirmed late-worker recovery is exposed on `POST /client/coverage/late-workers/:assignmentId/cancel`
|
||||
- client swap review is exposed on:
|
||||
- `GET /client/coverage/swap-requests`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/resolve`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/cancel`
|
||||
- dispatch-team management is exposed on:
|
||||
- `GET /client/coverage/dispatch-teams`
|
||||
- `GET /client/coverage/dispatch-candidates`
|
||||
- `POST /client/coverage/dispatch-teams/memberships`
|
||||
- `DELETE /client/coverage/dispatch-teams/memberships/:membershipId`
|
||||
- dispatch ranking order is:
|
||||
1. `CORE`
|
||||
2. `CERTIFIED_LOCATION`
|
||||
3. `MARKETPLACE`
|
||||
- expired swap requests are auto-cancelled by the notification worker and emit manager plus staff alerts
|
||||
- queued alerts are written to `notification_outbox`, dispatched by the private Cloud Run worker service `krow-notification-worker-v2`, and recorded in `notification_deliveries`
|
||||
|
||||
## 5) Route model
|
||||
|
||||
@@ -80,8 +80,15 @@ Token refresh:
|
||||
- `GET /client/coverage/core-team?date=YYYY-MM-DD`
|
||||
- `GET /client/coverage/incidents?startDate=YYYY-MM-DD&endDate=YYYY-MM-DD`
|
||||
- `GET /client/coverage/blocked-staff`
|
||||
- `GET /client/coverage/swap-requests?status=OPEN`
|
||||
- `GET /client/coverage/dispatch-teams`
|
||||
- `GET /client/coverage/dispatch-candidates?shiftId=uuid&roleId=uuid`
|
||||
- `POST /client/coverage/reviews`
|
||||
- `POST /client/coverage/late-workers/:assignmentId/cancel`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/resolve`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/cancel`
|
||||
- `POST /client/coverage/dispatch-teams/memberships`
|
||||
- `DELETE /client/coverage/dispatch-teams/memberships/:membershipId`
|
||||
|
||||
Use `POST /client/coverage/reviews` when the business is rating a worker after coverage review.
|
||||
|
||||
@@ -98,6 +105,19 @@ Payload may include:
|
||||
|
||||
If `markAsBlocked` is `true`, backend blocks that worker for that business and rejects future apply or assign attempts until a later review sets `markAsBlocked: false`.
|
||||
|
||||
Swap-management rule:
|
||||
|
||||
- use `GET /client/coverage/swap-requests` as the client review feed
|
||||
- use `GET /client/coverage/dispatch-candidates` for the ranked replacement list
|
||||
- use `POST /client/coverage/swap-requests/:swapRequestId/resolve` when ops selects a replacement
|
||||
- use `POST /client/coverage/swap-requests/:swapRequestId/cancel` when ops wants to close the swap request without replacement
|
||||
|
||||
Dispatch-priority rule:
|
||||
|
||||
1. `CORE`
|
||||
2. `CERTIFIED_LOCATION`
|
||||
3. `MARKETPLACE`
|
||||
|
||||
### Orders
|
||||
|
||||
- `GET /client/orders/view`
|
||||
@@ -178,10 +198,8 @@ Current swap behavior:
|
||||
- backend records the swap request
|
||||
- assignment moves to `SWAP_REQUESTED`
|
||||
- shift becomes visible in the replacement pool
|
||||
|
||||
Current limitation:
|
||||
|
||||
- full manager-side swap resolution lifecycle is not yet a separate frontend contract
|
||||
- client/ops can review and resolve swap requests through the coverage endpoints
|
||||
- if the swap request expires without coverage, backend auto-cancels it and alerts both the manager path and the original worker
|
||||
|
||||
### Clock in / clock out
|
||||
|
||||
|
||||
@@ -99,9 +99,16 @@ Current backend behavior:
|
||||
- stores the reason
|
||||
- emits `SHIFT_SWAP_REQUESTED`
|
||||
- exposes the shift in the replacement pool
|
||||
- starts the swap-expiry window used by backend auto-cancellation
|
||||
|
||||
This is enough for the current staff UI.
|
||||
It is not yet the full manager-side swap resolution lifecycle.
|
||||
Manager/ops review happens through:
|
||||
|
||||
- `GET /client/coverage/swap-requests`
|
||||
- `GET /client/coverage/dispatch-candidates`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/resolve`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/cancel`
|
||||
|
||||
If the swap request expires without coverage, backend auto-cancels it and alerts the manager path plus the original worker.
|
||||
|
||||
### Submit completed shift for approval
|
||||
|
||||
|
||||
@@ -45,6 +45,9 @@ Full auth behavior, including staff phone flow and refresh rules, is documented
|
||||
- `GET /client/coverage/core-team`
|
||||
- `GET /client/coverage/incidents`
|
||||
- `GET /client/coverage/blocked-staff`
|
||||
- `GET /client/coverage/swap-requests`
|
||||
- `GET /client/coverage/dispatch-teams`
|
||||
- `GET /client/coverage/dispatch-candidates`
|
||||
- `GET /client/hubs`
|
||||
- `GET /client/cost-centers`
|
||||
- `GET /client/vendors`
|
||||
@@ -80,6 +83,10 @@ Full auth behavior, including staff phone flow and refresh rules, is documented
|
||||
- `POST /client/billing/invoices/:invoiceId/dispute`
|
||||
- `POST /client/coverage/reviews`
|
||||
- `POST /client/coverage/late-workers/:assignmentId/cancel`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/resolve`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/cancel`
|
||||
- `POST /client/coverage/dispatch-teams/memberships`
|
||||
- `DELETE /client/coverage/dispatch-teams/memberships/:membershipId`
|
||||
|
||||
Coverage-review request payload may also send:
|
||||
|
||||
@@ -94,6 +101,45 @@ Coverage-review request payload may also send:
|
||||
|
||||
If `markAsBlocked` is `true`, backend adds that staff member to the business-level blocked list and future apply or assign attempts are rejected until a later review sends `markAsBlocked: false`.
|
||||
|
||||
Swap-review routes:
|
||||
|
||||
- `GET /client/coverage/swap-requests?status=OPEN`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/resolve`
|
||||
- `POST /client/coverage/swap-requests/:swapRequestId/cancel`
|
||||
|
||||
Resolve example:
|
||||
|
||||
```json
|
||||
{
|
||||
"applicationId": "uuid",
|
||||
"note": "Dispatch selected the strongest replacement candidate"
|
||||
}
|
||||
```
|
||||
|
||||
Dispatch-team routes:
|
||||
|
||||
- `GET /client/coverage/dispatch-teams`
|
||||
- `GET /client/coverage/dispatch-candidates?shiftId=uuid&roleId=uuid`
|
||||
- `POST /client/coverage/dispatch-teams/memberships`
|
||||
- `DELETE /client/coverage/dispatch-teams/memberships/:membershipId`
|
||||
|
||||
Dispatch-team membership example:
|
||||
|
||||
```json
|
||||
{
|
||||
"staffId": "uuid",
|
||||
"hubId": "uuid",
|
||||
"teamType": "CORE",
|
||||
"notes": "Preferred lead barista for this location"
|
||||
}
|
||||
```
|
||||
|
||||
Dispatch priority order is:
|
||||
|
||||
1. `CORE`
|
||||
2. `CERTIFIED_LOCATION`
|
||||
3. `MARKETPLACE`
|
||||
|
||||
Shift-manager creation example:
|
||||
|
||||
```json
|
||||
@@ -257,6 +303,9 @@ These are exposed as direct unified aliases even though they are backed by `core
|
||||
- `GET /client/coverage/incidents` is the review feed for geofence breaches, missing-location batches, and clock-in overrides.
|
||||
- `GET /client/coverage/blocked-staff` is the review feed for workers currently blocked by that business.
|
||||
- `POST /client/coverage/late-workers/:assignmentId/cancel` is the client-side recovery action when lateness is confirmed by incident evidence or elapsed grace time.
|
||||
- `GET /client/coverage/swap-requests` is the manager/ops review feed for swap requests, candidate applications, and status.
|
||||
- `GET /client/coverage/dispatch-candidates` returns ranked candidates with the dispatch-team priority already applied.
|
||||
- swap auto-cancellation is backend-driven. If a swap request expires without a replacement, backend cancels the original assignment, marks the swap request `AUTO_CANCELLED`, and alerts both the manager path and the original worker.
|
||||
- Raw location stream payloads are stored in the private v2 bucket; SQL only stores the summary and incident index.
|
||||
- Push delivery is backed by:
|
||||
- SQL token registry in `device_push_tokens`
|
||||
|
||||
Reference in New Issue
Block a user