9.0 KiB
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:
1) Global rules
- Use unified routes only.
- Send
Authorization: Bearer <firebase-id-token>on protected routes. - Send
Idempotency-Keyon all write routes. - Do not call
/query/*,/commands/*, or/core/*directly from frontend.
2) Core model frontend should assume
orderis the client-facing request for staffing.shiftis the concrete scheduled unit of work under an order.shiftRoleis the role slot inside a shift that staff apply to.assignmentis the worker-to-shift record once a worker is attached.
Important consequences:
GET /staff/shifts/openreturns open shift-role opportunities.POST /staff/shifts/:shiftId/applymust send theroleIdfrom that response.GET /client/orders/viewis the timeline/read model for the client app.POST /client/orders/:orderId/editandPOST /client/orders/:orderId/cancelonly 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/refreshroute
4) Client app screen mapping
Home / dashboard
GET /client/sessionGET /client/dashboardGET /client/reorders
Billing / payments
GET /client/billing/accountsGET /client/billing/invoices/pendingGET /client/billing/invoices/historyGET /client/billing/current-billGET /client/billing/savingsGET /client/billing/spend-breakdownPOST /client/billing/invoices/:invoiceId/approvePOST /client/billing/invoices/:invoiceId/dispute
Coverage
GET /client/coverage?date=YYYY-MM-DDGET /client/coverage/stats?date=YYYY-MM-DDGET /client/coverage/core-team?date=YYYY-MM-DDGET /client/coverage/incidents?startDate=YYYY-MM-DD&endDate=YYYY-MM-DDGET /client/coverage/blocked-staffGET /client/coverage/swap-requests?status=OPENGET /client/coverage/dispatch-teamsGET /client/coverage/dispatch-candidates?shiftId=uuid&roleId=uuidPOST /client/coverage/reviewsPOST /client/coverage/late-workers/:assignmentId/cancelPOST /client/coverage/swap-requests/:swapRequestId/resolvePOST /client/coverage/swap-requests/:swapRequestId/cancelPOST /client/coverage/dispatch-teams/membershipsDELETE /client/coverage/dispatch-teams/memberships/:membershipId
Use POST /client/coverage/reviews when the business is rating a worker after coverage review.
Payload may include:
{
"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-requestsas the client review feed - use
GET /client/coverage/dispatch-candidatesfor the ranked replacement list - use
POST /client/coverage/swap-requests/:swapRequestId/resolvewhen ops selects a replacement - use
POST /client/coverage/swap-requests/:swapRequestId/cancelwhen ops wants to close the swap request without replacement
Dispatch-priority rule:
CORECERTIFIED_LOCATIONMARKETPLACE
Orders
GET /client/orders/viewGET /client/orders/:orderId/reorder-previewPOST /client/orders/one-timePOST /client/orders/recurringPOST /client/orders/permanentPOST /client/orders/:orderId/editPOST /client/orders/:orderId/cancel
Rapid-order flow:
- use
POST /rapid-orders/processfor the single-call transcribe-and-parse flow
Hubs and managers
GET /client/hubsGET /client/cost-centersGET /client/hubs/:hubId/managersGET /client/team-membersPOST /client/shift-managersPOST /client/hubsPUT /client/hubs/:hubIdDELETE /client/hubs/:hubIdPOST /client/hubs/:hubId/assign-nfcPOST /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-DDGET /client/reports/daily-ops?date=YYYY-MM-DDGET /client/reports/spend?date=YYYY-MM-DDGET /client/reports/coverage?date=YYYY-MM-DDGET /client/reports/forecast?date=YYYY-MM-DDGET /client/reports/performance?date=YYYY-MM-DDGET /client/reports/no-show?date=YYYY-MM-DD
5) Staff app screen mapping
Home / dashboard
GET /staff/sessionGET /staff/dashboardGET /staff/profile-completion
Availability
GET /staff/availabilityPUT /staff/availabilityPOST /staff/availability/quick-set
Find shifts
GET /staff/shifts/openPOST /staff/shifts/:shiftId/apply
Rule:
- send the
roleIdfrom the open-shifts response - this is the concrete
shift_roles.id
My shifts
GET /staff/shifts/pendingGET /staff/shifts/assignedGET /staff/shifts/cancelledGET /staff/shifts/completedGET /staff/shifts/:shiftIdPOST /staff/shifts/:shiftId/acceptPOST /staff/shifts/:shiftId/declinePOST /staff/shifts/:shiftId/request-swapPOST /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/todayGET /staff/clock-in/statusPOST /staff/clock-inPOST /staff/clock-outPOST /staff/location-streams
Frontend should respect:
clockInModeallowClockInOverridelatitudelongitudegeofenceRadiusMetersnfcTagId
Clock-in proof rules:
- use
nfcTagIdfor NFC clocking - use
latitude,longitude, andaccuracyMetersfor geolocation clocking - send
overrideReasononly when a geofence override is allowed - send
proofNonceandproofTimestampon attendance writes
Payments
GET /staff/payments/summaryGET /staff/payments/historyGET /staff/payments/chart
Profile
GET /staff/profile/sectionsGET /staff/profile/personal-infoGET /staff/profile/industriesGET /staff/profile/skillsGET /staff/profile/documentsGET /staff/profile/attireGET /staff/profile/tax-formsGET /staff/profile/emergency-contactsGET /staff/profile/certificatesGET /staff/profile/bank-accountsGET /staff/profile/benefitsGET /staff/profile/benefits/historyGET /staff/profile/time-cardGET /staff/profile/privacyPUT /staff/profile/personal-infoPUT /staff/profile/experiencePUT /staff/profile/locationsPOST /staff/profile/emergency-contactsPUT /staff/profile/emergency-contacts/:contactIdPUT /staff/profile/tax-forms/:formTypePOST /staff/profile/tax-forms/:formType/submitPOST /staff/profile/bank-accountsPUT /staff/profile/privacy
Document model rule:
GET /staff/profile/documentsreturns only documentsGET /staff/profile/attirereturns attire itemsGET /staff/profile/tax-formsreturns tax-form rowsGET /staff/profile/certificatesreturns certificates
FAQ
GET /staff/faqsGET /staff/faqs/search?q=...
6) Upload implementation
For documents, attire, and certificates:
POST /upload-filePOST /create-signed-url- upload file bytes to storage with the signed URL
POST /verifications- finalize with:
PUT /staff/profile/documents/:documentId/uploadPUT /staff/profile/attire/:documentId/uploadPOST /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:
source ~/.nvm/nvm.sh
nvm use 23.5.0
cd backend/command-api
npm run seed:v2-demo