# Mobile Coding Agent Spec

This document is the frontend handoff spec for an AI coding agent working on the mobile applications against the v2 backend.

Use this as the primary implementation brief.

Base URL:

- `https://krow-api-v2-933560802882.us-central1.run.app`

Supporting docs:

- `/Users/wiel/Development/krow-workforce/docs/BACKEND/API_GUIDES/V2/authentication.md`
- `/Users/wiel/Development/krow-workforce/docs/BACKEND/API_GUIDES/V2/unified-api.md`
- `/Users/wiel/Development/krow-workforce/docs/BACKEND/API_GUIDES/V2/mobile-frontend-implementation-spec.md`
- `/Users/wiel/Development/krow-workforce/docs/BACKEND/API_GUIDES/V2/staff-shifts.md`

## 1) Non-negotiable rules

- Use the unified base URL only.
- Do not call `/query/*`, `/commands/*`, or `/core/*` directly from frontend.
- Send `Authorization: Bearer <firebase-id-token>` on protected routes.
- Send `Idempotency-Key` on every write route.
- Treat `order`, `shift`, `shiftRole`, and `assignment` as different objects.
- For staff shift applications, `roleId` must come from the response of `GET /staff/shifts/open`.

## 2) What is implemented now

Safe to build against now:

- client auth/session
- client dashboard, billing, coverage, hubs, vendors, managers, team members, orders, reports
- client coverage reviews, worker rating, block/unblock, late-worker cancellation
- client swap review and dispatch-team management
- staff auth/session
- staff dashboard, availability, payments, shifts, profile, tax forms, bank accounts, benefits, documents, attire, certificates
- staff clock-in, clock-out, location streaming, swap request, completed-shift submission
- upload, signed URL, verification, and rapid-order processing

Not part of this implementation spec:

- backend `/auth/refresh`
- SMS or email notification fallback
- AI-driven report insights
- AI-driven personalized shift matching
- full NFC attestation enforcement
- chat backend

## 3) Auth implementation

### Client app

Use:

- `POST /auth/client/sign-in`
- `POST /auth/client/sign-up`
- `GET /auth/session`
- `POST /auth/client/sign-out`

Do not build a separate refresh route.

Token refresh remains on the Firebase client SDK side.

### Staff app

Use:

- `POST /auth/staff/phone/start`
- `POST /auth/staff/phone/verify`
- `GET /auth/session`
- `POST /auth/staff/sign-out`

Important:

- `POST /auth/staff/phone/start` can return `mode = CLIENT_FIREBASE_SDK`
- when that happens, the app must complete Firebase phone verification on-device
- after that, the app must call `POST /auth/staff/phone/verify` with the Firebase `idToken`

Do not assume staff auth is a fully backend-managed OTP flow.

## 4) Core data model assumptions

- `order`: client-facing staffing request
- `shift`: a scheduled work instance under an order
- `shiftRole`: a role slot inside a shift
- `application`: worker applies to a `shiftRole`
- `assignment`: worker is actually attached to a shift

Rules:

- `GET /staff/shifts/open` returns opportunities, not assignments
- `GET /staff/shifts/assigned` returns active assigned shifts
- `GET /client/orders/view` is the timeline/read model for client
- `POST /client/orders/:orderId/edit` and `POST /client/orders/:orderId/cancel` apply to future shifts only

## 5) Client app screen mapping

### Home

- `GET /client/session`
- `GET /client/dashboard`
- `GET /client/reorders`

### Billing

- `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`

Coverage review payload:

```json
{
  "assignmentId": "uuid",
  "rating": 4,
  "comment": "Strong performance on the shift",
  "markAsBlocked": false
}
```

Rules:

- worker rating happens through `POST /client/coverage/reviews`
- the same endpoint also supports `markAsFavorite` to add or remove a worker from business favorites
- blocking a worker is done through the same endpoint using `markAsBlocked`
- dispatch ranking order is:
  1. `CORE`
  2. `CERTIFIED_LOCATION`
  3. `MARKETPLACE`

Swap management flow:

1. worker requests swap
2. backend moves original assignment to `SWAP_REQUESTED`
3. replacement workers see the shift in `GET /staff/shifts/open`
4. client/ops reads `GET /client/coverage/swap-requests`
5. client/ops reads `GET /client/coverage/dispatch-candidates`
6. client/ops resolves or cancels the swap request
7. if unresolved and expired, backend auto-cancels it

### 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`
- `POST /rapid-orders/process`

Rules:

- use `POST /rapid-orders/process` for the single-call rapid-order flow
- recent orders should expect total price and hourly rate fields
- order edit and cancel only affect future shifts

### 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`

Rules:

- `POST /client/shift-managers` creates an invited manager identity
- if `hubId` is present, backend links the manager to that hub too

### 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`

Important:

- these are operational reports
- this is not the same as the separate AI insights research issue

## 6) Staff app screen mapping

### Home

- `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:

- use `roleId` from the open-shifts response

### 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`

Staff shift detail and list rules:

- assigned shifts include `clientName`, `hourlyRate`, `totalRate`, `startTime`, `endTime`
- shift detail includes `clientName`, `latitude`, `longitude`, `hourlyRate`, `totalRate`
- completed shifts include `date`, `clientName`, `startTime`, `endTime`, `hourlyRate`, `totalRate`

### 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`

Clock-in payload rules:

- if using NFC, send `nfcTagId`
- if using geo, send `latitude`, `longitude`, `accuracyMeters`
- send `overrideReason` only when geo override is allowed
- send `proofNonce` and `proofTimestamp` on attendance writes
- send `attestationProvider` and `attestationToken` only if the device has them

Clock-in read rules:

`GET /staff/clock-in/shifts/today` returns fields including:

- `clientName`
- `hourlyRate`
- `totalRate`
- `latitude`
- `longitude`
- `clockInMode`
- `allowClockInOverride`
- `geofenceRadiusMeters`
- `nfcTagId`

Policy values:

- `NFC_REQUIRED`
- `GEO_REQUIRED`
- `EITHER`

### 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`

Profile data rules:

- `GET /staff/profile/documents` returns documents only
- `GET /staff/profile/attire` returns attire only
- `GET /staff/profile/tax-forms` returns tax forms only
- `GET /staff/profile/certificates` returns certificates only
- benefit summary and benefit history are separate endpoints

### FAQ

- `GET /staff/faqs`
- `GET /staff/faqs/search?q=...`

## 7) Upload flows

### General upload pattern

For documents, attire, and certificates:

1. `POST /upload-file`
2. `POST /create-signed-url`
3. upload bytes to storage
4. `POST /verifications`
5. finalize using the appropriate staff route

Staff upload routes:

- `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`

Rules:

- backend treats verification-linked file state as the source of truth
- frontend may still send `fileUri` or `photoUrl`, but verification linkage wins

## 8) What the coding agent should not assume

- do not invent a backend refresh route
- do not assume swap is staff-only; there is now a client/ops review side
- do not assume documents and attire share the same read endpoint
- do not assume backend direct CRUD on internal services
- do not assume AI reports, SMS fallback, or full NFC attestation are available

## 9) Suggested implementation order for the coding agent

1. auth/session flows
2. client home + orders + coverage
3. staff home + shifts + clock-in
4. profile sections and upload flows
5. reports and billing polish
6. swap review and dispatch-team management

## 10) Definition of done for frontend integration

Frontend implementation is aligned when:

- every screen calls the unified v2 routes only
- every write sends an `Idempotency-Key`
- staff shift apply uses `roleId` from open shifts
- clock-in respects `clockInMode`
- swap request uses the staff endpoint and swap review uses the client coverage endpoints
- documents, attire, certificates, and tax forms use their correct route families
