306 lines
9.0 KiB
Markdown
306 lines
9.0 KiB
Markdown
# Mobile Frontend Implementation Spec
|
|
|
|
This is the shortest path for frontend to implement the v2 mobile clients against the unified backend.
|
|
|
|
Base URL:
|
|
|
|
- `https://krow-api-v2-933560802882.us-central1.run.app`
|
|
|
|
Use this doc together with:
|
|
|
|
- [Authentication](./authentication.md)
|
|
- [Unified API](./unified-api.md)
|
|
- [Staff Shifts](./staff-shifts.md)
|
|
|
|
## 1) Global rules
|
|
|
|
- Use unified routes only.
|
|
- Send `Authorization: Bearer <firebase-id-token>` on protected routes.
|
|
- Send `Idempotency-Key` on all write routes.
|
|
- Do not call `/query/*`, `/commands/*`, or `/core/*` directly from frontend.
|
|
|
|
## 2) Core model frontend should assume
|
|
|
|
- `order` is the client-facing request for staffing.
|
|
- `shift` is the concrete scheduled unit of work under an order.
|
|
- `shiftRole` is the role slot inside a shift that staff apply to.
|
|
- `assignment` is the worker-to-shift record once a worker is attached.
|
|
|
|
Important consequences:
|
|
|
|
- `GET /staff/shifts/open` returns open shift-role opportunities.
|
|
- `POST /staff/shifts/:shiftId/apply` must send the `roleId` from that response.
|
|
- `GET /client/orders/view` is the timeline/read model for the client app.
|
|
- `POST /client/orders/:orderId/edit` and `POST /client/orders/:orderId/cancel` only affect future shifts.
|
|
|
|
## 3) Auth implementation
|
|
|
|
### Client app
|
|
|
|
- sign in with `POST /auth/client/sign-in`
|
|
- sign up with `POST /auth/client/sign-up`
|
|
- hydrate session with `GET /auth/session`
|
|
- sign out with `POST /auth/client/sign-out`
|
|
|
|
### Staff app
|
|
|
|
- start phone auth with `POST /auth/staff/phone/start`
|
|
- complete phone auth with `POST /auth/staff/phone/verify`
|
|
- hydrate session with `GET /auth/session`
|
|
- sign out with `POST /auth/staff/sign-out`
|
|
|
|
Token refresh:
|
|
|
|
- keep using Firebase client SDK refresh behavior
|
|
- there is no backend `/auth/refresh` route
|
|
|
|
## 4) Client app screen mapping
|
|
|
|
### Home / dashboard
|
|
|
|
- `GET /client/session`
|
|
- `GET /client/dashboard`
|
|
- `GET /client/reorders`
|
|
|
|
### Billing / payments
|
|
|
|
- `GET /client/billing/accounts`
|
|
- `GET /client/billing/invoices/pending`
|
|
- `GET /client/billing/invoices/history`
|
|
- `GET /client/billing/current-bill`
|
|
- `GET /client/billing/savings`
|
|
- `GET /client/billing/spend-breakdown`
|
|
- `POST /client/billing/invoices/:invoiceId/approve`
|
|
- `POST /client/billing/invoices/:invoiceId/dispute`
|
|
|
|
### Coverage
|
|
|
|
- `GET /client/coverage?date=YYYY-MM-DD`
|
|
- `GET /client/coverage/stats?date=YYYY-MM-DD`
|
|
- `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.
|
|
|
|
Payload may include:
|
|
|
|
```json
|
|
{
|
|
"staffId": "uuid",
|
|
"assignmentId": "uuid",
|
|
"rating": 4,
|
|
"feedback": "Strong performance on the shift",
|
|
"markAsFavorite": true,
|
|
"markAsBlocked": false
|
|
}
|
|
```
|
|
|
|
If `markAsFavorite` is `true`, backend adds that worker to the business favorites list. If `markAsFavorite` is `false`, backend removes them from that list. 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`
|
|
- `GET /client/orders/:orderId/reorder-preview`
|
|
- `POST /client/orders/one-time`
|
|
- `POST /client/orders/recurring`
|
|
- `POST /client/orders/permanent`
|
|
- `POST /client/orders/:orderId/edit`
|
|
- `POST /client/orders/:orderId/cancel`
|
|
|
|
Rapid-order flow:
|
|
|
|
- use `POST /rapid-orders/process` for the single-call transcribe-and-parse flow
|
|
|
|
### Hubs and managers
|
|
|
|
- `GET /client/hubs`
|
|
- `GET /client/cost-centers`
|
|
- `GET /client/hubs/:hubId/managers`
|
|
- `GET /client/team-members`
|
|
- `POST /client/shift-managers`
|
|
- `POST /client/hubs`
|
|
- `PUT /client/hubs/:hubId`
|
|
- `DELETE /client/hubs/:hubId`
|
|
- `POST /client/hubs/:hubId/assign-nfc`
|
|
- `POST /client/hubs/:hubId/managers`
|
|
|
|
`POST /client/shift-managers` is the fastest path to create an invited manager identity for a business. If `hubId` is provided, backend also links that manager to the hub.
|
|
|
|
### Reports
|
|
|
|
- `GET /client/reports/summary?date=YYYY-MM-DD`
|
|
- `GET /client/reports/daily-ops?date=YYYY-MM-DD`
|
|
- `GET /client/reports/spend?date=YYYY-MM-DD`
|
|
- `GET /client/reports/coverage?date=YYYY-MM-DD`
|
|
- `GET /client/reports/forecast?date=YYYY-MM-DD`
|
|
- `GET /client/reports/performance?date=YYYY-MM-DD`
|
|
- `GET /client/reports/no-show?date=YYYY-MM-DD`
|
|
|
|
## 5) Staff app screen mapping
|
|
|
|
### Home / dashboard
|
|
|
|
- `GET /staff/session`
|
|
- `GET /staff/dashboard`
|
|
- `GET /staff/profile-completion`
|
|
|
|
### Availability
|
|
|
|
- `GET /staff/availability`
|
|
- `PUT /staff/availability`
|
|
- `POST /staff/availability/quick-set`
|
|
|
|
### Find shifts
|
|
|
|
- `GET /staff/shifts/open`
|
|
- `POST /staff/shifts/:shiftId/apply`
|
|
|
|
Rule:
|
|
|
|
- send the `roleId` from the open-shifts response
|
|
- this is the concrete `shift_roles.id`
|
|
|
|
### My shifts
|
|
|
|
- `GET /staff/shifts/pending`
|
|
- `GET /staff/shifts/assigned`
|
|
- `GET /staff/shifts/cancelled`
|
|
- `GET /staff/shifts/completed`
|
|
- `GET /staff/shifts/:shiftId`
|
|
- `POST /staff/shifts/:shiftId/accept`
|
|
- `POST /staff/shifts/:shiftId/decline`
|
|
- `POST /staff/shifts/:shiftId/request-swap`
|
|
- `POST /staff/shifts/:shiftId/submit-for-approval`
|
|
|
|
Current swap behavior:
|
|
|
|
- backend records the swap request
|
|
- assignment moves to `SWAP_REQUESTED`
|
|
- shift becomes visible in the replacement pool
|
|
- 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
|
|
|
|
- `GET /staff/clock-in/shifts/today`
|
|
- `GET /staff/clock-in/status`
|
|
- `POST /staff/clock-in`
|
|
- `POST /staff/clock-out`
|
|
- `POST /staff/location-streams`
|
|
|
|
Frontend should respect:
|
|
|
|
- `clockInMode`
|
|
- `allowClockInOverride`
|
|
- `latitude`
|
|
- `longitude`
|
|
- `geofenceRadiusMeters`
|
|
- `nfcTagId`
|
|
|
|
Clock-in proof rules:
|
|
|
|
- use `nfcTagId` for NFC clocking
|
|
- use `latitude`, `longitude`, and `accuracyMeters` for geolocation clocking
|
|
- send `overrideReason` only when a geofence override is allowed
|
|
- send `proofNonce` and `proofTimestamp` on attendance writes
|
|
|
|
### Payments
|
|
|
|
- `GET /staff/payments/summary`
|
|
- `GET /staff/payments/history`
|
|
- `GET /staff/payments/chart`
|
|
|
|
### Profile
|
|
|
|
- `GET /staff/profile/sections`
|
|
- `GET /staff/profile/personal-info`
|
|
- `GET /staff/profile/industries`
|
|
- `GET /staff/profile/skills`
|
|
- `GET /staff/profile/documents`
|
|
- `GET /staff/profile/attire`
|
|
- `GET /staff/profile/tax-forms`
|
|
- `GET /staff/profile/emergency-contacts`
|
|
- `GET /staff/profile/certificates`
|
|
- `GET /staff/profile/bank-accounts`
|
|
- `GET /staff/profile/benefits`
|
|
- `GET /staff/profile/benefits/history`
|
|
- `GET /staff/profile/time-card`
|
|
- `GET /staff/profile/privacy`
|
|
- `PUT /staff/profile/personal-info`
|
|
- `PUT /staff/profile/experience`
|
|
- `PUT /staff/profile/locations`
|
|
- `POST /staff/profile/emergency-contacts`
|
|
- `PUT /staff/profile/emergency-contacts/:contactId`
|
|
- `PUT /staff/profile/tax-forms/:formType`
|
|
- `POST /staff/profile/tax-forms/:formType/submit`
|
|
- `POST /staff/profile/bank-accounts`
|
|
- `PUT /staff/profile/privacy`
|
|
|
|
Document model rule:
|
|
|
|
- `GET /staff/profile/documents` returns only documents
|
|
- `GET /staff/profile/attire` returns attire items
|
|
- `GET /staff/profile/tax-forms` returns tax-form rows
|
|
- `GET /staff/profile/certificates` returns certificates
|
|
|
|
### FAQ
|
|
|
|
- `GET /staff/faqs`
|
|
- `GET /staff/faqs/search?q=...`
|
|
|
|
## 6) Upload implementation
|
|
|
|
For documents, attire, and certificates:
|
|
|
|
1. `POST /upload-file`
|
|
2. `POST /create-signed-url`
|
|
3. upload file bytes to storage with the signed URL
|
|
4. `POST /verifications`
|
|
5. finalize with:
|
|
- `PUT /staff/profile/documents/:documentId/upload`
|
|
- `PUT /staff/profile/attire/:documentId/upload`
|
|
- `POST /staff/profile/certificates`
|
|
|
|
Use the verification-linked file as the source of truth.
|
|
|
|
## 7) What frontend should not assume
|
|
|
|
- do not assume order edit mutates past shifts
|
|
- do not assume swap resolution is complete beyond the request step
|
|
- do not assume raw `/query/*` or `/commands/*` routes are stable for app integration
|
|
- do not assume blocked workers can still apply to future shifts for that business
|
|
|
|
## 8) Demo reset
|
|
|
|
To reset dev demo data:
|
|
|
|
```bash
|
|
source ~/.nvm/nvm.sh
|
|
nvm use 23.5.0
|
|
cd backend/command-api
|
|
npm run seed:v2-demo
|
|
```
|