fix(api): close v2 mobile contract gaps
This commit is contained in:
@@ -143,6 +143,7 @@ Those routes still exist for backend/internal compatibility, but mobile/frontend
|
||||
|
||||
- [Authentication](./authentication.md)
|
||||
- [Unified API](./unified-api.md)
|
||||
- [Staff Shifts](./staff-shifts.md)
|
||||
- [Core API](./core-api.md)
|
||||
- [Command API](./command-api.md)
|
||||
- [Query API](./query-api.md)
|
||||
|
||||
176
docs/BACKEND/API_GUIDES/V2/staff-shifts.md
Normal file
176
docs/BACKEND/API_GUIDES/V2/staff-shifts.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# Staff Shifts V2
|
||||
|
||||
This document is the frontend handoff for the `staff/shifts/*` routes on the unified v2 API.
|
||||
|
||||
Base URL:
|
||||
|
||||
- `https://krow-api-v2-933560802882.us-central1.run.app`
|
||||
|
||||
## Read routes
|
||||
|
||||
- `GET /staff/shifts/assigned`
|
||||
- `GET /staff/shifts/open`
|
||||
- `GET /staff/shifts/pending`
|
||||
- `GET /staff/shifts/cancelled`
|
||||
- `GET /staff/shifts/completed`
|
||||
- `GET /staff/shifts/:shiftId`
|
||||
|
||||
## Write routes
|
||||
|
||||
- `POST /staff/shifts/:shiftId/apply`
|
||||
- `POST /staff/shifts/:shiftId/accept`
|
||||
- `POST /staff/shifts/:shiftId/decline`
|
||||
- `POST /staff/shifts/:shiftId/request-swap`
|
||||
- `POST /staff/shifts/:shiftId/submit-for-approval`
|
||||
|
||||
All write routes require:
|
||||
|
||||
- `Authorization: Bearer <firebase-id-token>`
|
||||
- `Idempotency-Key: <unique-per-action>`
|
||||
|
||||
## Shift lifecycle
|
||||
|
||||
### Find shifts
|
||||
|
||||
`GET /staff/shifts/open`
|
||||
|
||||
- use this for the worker marketplace feed
|
||||
- the worker applies to a concrete shift role
|
||||
- send the `roleId` returned by the open-shifts response
|
||||
- `roleId` here means `shift_roles.id`, not the role catalog id
|
||||
|
||||
Apply request example:
|
||||
|
||||
```json
|
||||
{
|
||||
"roleId": "uuid",
|
||||
"instantBook": false
|
||||
}
|
||||
```
|
||||
|
||||
### Pending shifts
|
||||
|
||||
`GET /staff/shifts/pending`
|
||||
|
||||
- use `POST /staff/shifts/:shiftId/accept` to accept
|
||||
- use `POST /staff/shifts/:shiftId/decline` to decline
|
||||
|
||||
### Assigned shifts
|
||||
|
||||
`GET /staff/shifts/assigned`
|
||||
|
||||
Each item now includes:
|
||||
|
||||
- `clientName`
|
||||
- `hourlyRate`
|
||||
- `totalRate`
|
||||
- `startTime`
|
||||
- `endTime`
|
||||
|
||||
### Shift detail
|
||||
|
||||
`GET /staff/shifts/:shiftId`
|
||||
|
||||
Each detail response now includes:
|
||||
|
||||
- `clientName`
|
||||
- `latitude`
|
||||
- `longitude`
|
||||
- `hourlyRate`
|
||||
- `totalRate`
|
||||
|
||||
Use this as the source of truth for the shift detail screen.
|
||||
|
||||
### Request swap
|
||||
|
||||
`POST /staff/shifts/:shiftId/request-swap`
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"reason": "Need coverage for a family emergency"
|
||||
}
|
||||
```
|
||||
|
||||
Current backend behavior:
|
||||
|
||||
- marks the assignment as `SWAP_REQUESTED`
|
||||
- stores the reason
|
||||
- emits `SHIFT_SWAP_REQUESTED`
|
||||
- exposes the shift in the replacement pool
|
||||
|
||||
This is enough for the current staff UI.
|
||||
It is not yet the full manager-side swap resolution lifecycle.
|
||||
|
||||
### Submit completed shift for approval
|
||||
|
||||
`POST /staff/shifts/:shiftId/submit-for-approval`
|
||||
|
||||
Use this after the worker has clocked out.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"note": "Worked full shift and all tasks were completed"
|
||||
}
|
||||
```
|
||||
|
||||
Current backend behavior:
|
||||
|
||||
- only allows shifts in `CHECKED_OUT` or `COMPLETED`
|
||||
- creates or updates the assignment timesheet
|
||||
- sets the timesheet to `SUBMITTED` unless it is already `APPROVED` or `PAID`
|
||||
- emits `TIMESHEET_SUBMITTED_FOR_APPROVAL`
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"assignmentId": "uuid",
|
||||
"shiftId": "uuid",
|
||||
"timesheetId": "uuid",
|
||||
"status": "SUBMITTED",
|
||||
"submitted": true
|
||||
}
|
||||
```
|
||||
|
||||
## Completed shifts
|
||||
|
||||
`GET /staff/shifts/completed`
|
||||
|
||||
Each item now includes:
|
||||
|
||||
- `date`
|
||||
- `clientName`
|
||||
- `startTime`
|
||||
- `endTime`
|
||||
- `hourlyRate`
|
||||
- `totalRate`
|
||||
- `timesheetStatus`
|
||||
- `paymentStatus`
|
||||
|
||||
## Clock-in support fields
|
||||
|
||||
`GET /staff/clock-in/shifts/today`
|
||||
|
||||
Each item now includes:
|
||||
|
||||
- `clientName`
|
||||
- `hourlyRate`
|
||||
- `totalRate`
|
||||
- `latitude`
|
||||
- `longitude`
|
||||
- `clockInMode`
|
||||
- `allowClockInOverride`
|
||||
|
||||
## Frontend rule
|
||||
|
||||
Use the unified routes only.
|
||||
|
||||
Do not build new mobile work on:
|
||||
|
||||
- `/query/*`
|
||||
- `/commands/*`
|
||||
- `/core/*`
|
||||
@@ -153,6 +153,7 @@ Example `GET /staff/clock-in/shifts/today` item:
|
||||
- `POST /staff/shifts/:shiftId/accept`
|
||||
- `POST /staff/shifts/:shiftId/decline`
|
||||
- `POST /staff/shifts/:shiftId/request-swap`
|
||||
- `POST /staff/shifts/:shiftId/submit-for-approval`
|
||||
- `PUT /staff/profile/personal-info`
|
||||
- `PUT /staff/profile/experience`
|
||||
- `PUT /staff/profile/locations`
|
||||
@@ -174,6 +175,7 @@ These are exposed as direct unified aliases even though they are backed by `core
|
||||
- `POST /invoke-llm`
|
||||
- `POST /rapid-orders/transcribe`
|
||||
- `POST /rapid-orders/parse`
|
||||
- `POST /rapid-orders/process`
|
||||
- `POST /verifications`
|
||||
- `GET /verifications/:verificationId`
|
||||
- `POST /verifications/:verificationId/review`
|
||||
@@ -183,7 +185,9 @@ These are exposed as direct unified aliases even though they are backed by `core
|
||||
|
||||
- `POST /staff/profile/photo`
|
||||
- `POST /staff/profile/documents/:documentId/upload`
|
||||
- `PUT /staff/profile/documents/:documentId/upload`
|
||||
- `POST /staff/profile/attire/:documentId/upload`
|
||||
- `PUT /staff/profile/attire/:documentId/upload`
|
||||
- `POST /staff/profile/certificates`
|
||||
- `DELETE /staff/profile/certificates/:certificateId`
|
||||
|
||||
@@ -191,7 +195,21 @@ These are exposed as direct unified aliases even though they are backed by `core
|
||||
|
||||
- `roleId` on `POST /staff/shifts/:shiftId/apply` is the concrete `shift_roles.id` for that shift, not the catalog role definition id.
|
||||
- `accountType` on `POST /staff/profile/bank-accounts` accepts either lowercase or uppercase and is normalized by the backend.
|
||||
- Document routes now return only document rows. They do not mix in attire items anymore.
|
||||
- Tax-form data should come from `GET /staff/profile/tax-forms`, not `GET /staff/profile/documents`.
|
||||
- File upload routes return a storage path plus a signed URL. Frontend uploads the file directly to storage using that URL.
|
||||
- The frontend upload contract for documents, attire, and certificates is:
|
||||
1. `POST /upload-file`
|
||||
2. `POST /create-signed-url`
|
||||
3. `POST /verifications`
|
||||
4. finalize with:
|
||||
- `PUT /staff/profile/documents/:documentId/upload`
|
||||
- `PUT /staff/profile/attire/:documentId/upload`
|
||||
- `POST /staff/profile/certificates`
|
||||
- Finalization requires `verificationId`. Frontend may still send `fileUri` or `photoUrl`, but the backend treats the verification-linked file as the source of truth.
|
||||
- `POST /rapid-orders/process` is the single-call route for "transcribe + parse".
|
||||
- `POST /client/orders/:orderId/edit` builds a replacement order from future shifts only.
|
||||
- `POST /client/orders/:orderId/cancel` cancels future shifts only on the mobile surface and leaves historical shifts intact.
|
||||
- Verification upload and review routes are live and were validated through document, attire, and certificate flows. Do not rely on long-lived verification history durability until the dedicated persistence slice is landed in `core-api-v2`.
|
||||
- Attendance policy is explicit. Reads now expose `clockInMode` and `allowClockInOverride`.
|
||||
- `clockInMode` values are:
|
||||
|
||||
Reference in New Issue
Block a user