docs(api): consolidate v2 frontend backend guides

This commit is contained in:
zouantchaw
2026-03-12 14:09:05 +01:00
parent fe43ff23cf
commit b61babe3c6
9 changed files with 740 additions and 910 deletions

View File

@@ -1,5 +1,9 @@
# KROW Workforce API Contracts # KROW Workforce API Contracts
Legacy note:
Use `/Users/wiel/Development/krow-workforce/docs/BACKEND/API_GUIDES/V2/README.md` for the current v2 frontend/backend integration surface.
This document reflects the earlier Data Connect-oriented contract mapping and should not be the source of truth for new v2 client work.
This document captures all API contracts used by the Staff and Client mobile applications. The application backend is powered by **Firebase Data Connect (GraphQL)**, so traditional REST endpoints do not exist natively. For clarity and ease of reading for all engineering team members, the tables below formulate these GraphQL Data Connect queries and mutations into their **Conceptual REST Endpoints** alongside the actual **Data Connect Operation Name**. This document captures all API contracts used by the Staff and Client mobile applications. The application backend is powered by **Firebase Data Connect (GraphQL)**, so traditional REST endpoints do not exist natively. For clarity and ease of reading for all engineering team members, the tables below formulate these GraphQL Data Connect queries and mutations into their **Conceptual REST Endpoints** alongside the actual **Data Connect Operation Name**.
--- ---

View File

@@ -0,0 +1,14 @@
# Backend API Guides
## Use this for current frontend work
- [V2 Backend API Guide](./V2/README.md)
- [V2 Core API](./V2/core-api.md)
- [V2 Command API](./V2/command-api.md)
- [V2 Query API](./V2/query-api.md)
## Legacy reference
- [Initial API contracts](./00-initial-api-contracts.md)
The legacy contract doc reflects the older Data Connect-oriented application shape. Do not use it as the source of truth for new v2 frontend work.

View File

@@ -0,0 +1,120 @@
# V2 Backend API Guide
This is the frontend-facing source of truth for the v2 backend.
If you are building against the new backend, start here.
## 1) Which service to use
| Use case | Service |
| --- | --- |
| File upload, signed URLs, model calls, rapid order helpers, verification flows | `core-api-v2` |
| Business writes and workflow actions | `command-api-v2` |
| Screen reads for the implemented v2 views | `query-api-v2` |
## 2) Live dev base URLs
- Core API: `https://krow-core-api-v2-e3g6witsvq-uc.a.run.app`
- Command API: `https://krow-command-api-v2-e3g6witsvq-uc.a.run.app`
- Query API: `https://krow-query-api-v2-e3g6witsvq-uc.a.run.app`
## 3) Auth and headers
All protected routes require:
```http
Authorization: Bearer <firebase-id-token>
```
All command routes also require:
```http
Idempotency-Key: <unique-per-user-action>
```
All services return the same error envelope:
```json
{
"code": "STRING_CODE",
"message": "Human readable message",
"details": {},
"requestId": "uuid"
}
```
## 4) What frontend can use now
### Ready now
- `core-api-v2`
- upload file
- create signed URL
- invoke model
- rapid order transcribe
- rapid order parse
- create verification
- get verification
- review verification
- retry verification
- `command-api-v2`
- create order
- update order
- cancel order
- assign staff to shift
- accept shift
- change shift status
- clock in
- clock out
- favorite and unfavorite staff
- create staff review
- `query-api-v2`
- order list
- order detail
- favorite staff list
- staff review summary
- assignment attendance detail
### Do not move yet
- reports
- payments and finance screens
- undocumented dashboard reads
- undocumented scheduling reads and writes
- any flow that assumes verification history is durable in SQL
## 5) Important caveat
`core-api-v2` is usable now, but verification job state is not yet persisted to `krow-sql-v2`.
What is durable today:
- uploaded files in Google Cloud Storage
- generated signed URLs
- model invocation itself
What is not yet durable:
- verification job history
- verification review history
- verification event history
That means frontend can integrate with verification routes now, but should not treat them as mission-critical durable state yet.
## 6) Recommended frontend environment variables
```env
CORE_API_V2_BASE_URL=https://krow-core-api-v2-e3g6witsvq-uc.a.run.app
COMMAND_API_V2_BASE_URL=https://krow-command-api-v2-e3g6witsvq-uc.a.run.app
QUERY_API_V2_BASE_URL=https://krow-query-api-v2-e3g6witsvq-uc.a.run.app
```
## 7) Service docs
- [Core API](./core-api.md)
- [Command API](./command-api.md)
- [Query API](./query-api.md)
## 8) Frontend integration rule
Do not point screens directly at database access just because a route does not exist yet.
If a screen is missing from the docs, the next step is to define the route contract and add it to `query-api-v2` or `command-api-v2`.

View File

@@ -0,0 +1,229 @@
# V2 Command API
Use `command-api-v2` for write actions that change business state.
Base URL:
```text
https://krow-command-api-v2-e3g6witsvq-uc.a.run.app
```
## 1) Required headers
```http
Authorization: Bearer <firebase-id-token>
Idempotency-Key: <unique-per-user-action>
Content-Type: application/json
```
## 2) Route summary
| Method | Route | Purpose |
| --- | --- | --- |
| `POST` | `/commands/orders/create` | Create order with shifts and roles |
| `POST` | `/commands/orders/:orderId/update` | Update mutable order fields |
| `POST` | `/commands/orders/:orderId/cancel` | Cancel order and related eligible records |
| `POST` | `/commands/shifts/:shiftId/assign-staff` | Assign workforce to shift role |
| `POST` | `/commands/shifts/:shiftId/accept` | Accept an assigned shift |
| `POST` | `/commands/shifts/:shiftId/change-status` | Move shift to a new valid status |
| `POST` | `/commands/attendance/clock-in` | Record clock-in event |
| `POST` | `/commands/attendance/clock-out` | Record clock-out event |
| `POST` | `/commands/businesses/:businessId/favorite-staff` | Add favorite staff |
| `DELETE` | `/commands/businesses/:businessId/favorite-staff/:staffId` | Remove favorite staff |
| `POST` | `/commands/assignments/:assignmentId/reviews` | Create or update staff review |
| `GET` | `/readyz` | Ready check |
## 3) Order create
```text
POST /commands/orders/create
```
Request body:
```json
{
"tenantId": "uuid",
"businessId": "uuid",
"vendorId": "uuid",
"orderNumber": "ORD-1001",
"title": "Cafe Event Staffing",
"serviceType": "EVENT",
"shifts": [
{
"shiftCode": "SHIFT-1",
"title": "Morning Shift",
"startsAt": "2026-03-12T08:00:00.000Z",
"endsAt": "2026-03-12T16:00:00.000Z",
"requiredWorkers": 2,
"roles": [
{
"roleCode": "BARISTA",
"roleName": "Barista",
"workersNeeded": 2
}
]
}
]
}
```
## 4) Order update
```text
POST /commands/orders/:orderId/update
```
Required body fields:
- `tenantId`
- at least one mutable field such as `title`, `description`, `vendorId`, `serviceType`, `startsAt`, `endsAt`, `locationName`, `locationAddress`, `latitude`, `longitude`, `notes`, `metadata`
You can also send `null` to clear nullable fields.
## 5) Order cancel
```text
POST /commands/orders/:orderId/cancel
```
Example request:
```json
{
"tenantId": "uuid",
"reason": "Client cancelled"
}
```
## 6) Shift assign staff
```text
POST /commands/shifts/:shiftId/assign-staff
```
Example request:
```json
{
"tenantId": "uuid",
"shiftRoleId": "uuid",
"workforceId": "uuid",
"applicationId": "uuid"
}
```
## 7) Shift accept
```text
POST /commands/shifts/:shiftId/accept
```
Example request:
```json
{
"shiftRoleId": "uuid",
"workforceId": "uuid"
}
```
## 8) Shift status change
```text
POST /commands/shifts/:shiftId/change-status
```
Example request:
```json
{
"tenantId": "uuid",
"status": "PENDING_CONFIRMATION",
"reason": "Waiting for worker confirmation"
}
```
Allowed status values:
- `DRAFT`
- `OPEN`
- `PENDING_CONFIRMATION`
- `ASSIGNED`
- `ACTIVE`
- `COMPLETED`
- `CANCELLED`
## 9) Attendance
### Clock in
```text
POST /commands/attendance/clock-in
```
### Clock out
```text
POST /commands/attendance/clock-out
```
Example request body for both:
```json
{
"assignmentId": "uuid",
"sourceType": "NFC",
"sourceReference": "iphone-15-pro-max",
"nfcTagUid": "NFC-DEMO-ANA-001",
"deviceId": "device-123",
"latitude": 37.422,
"longitude": -122.084,
"accuracyMeters": 8,
"capturedAt": "2026-03-11T17:15:00.000Z"
}
```
## 10) Favorite staff
### Add favorite
```text
POST /commands/businesses/:businessId/favorite-staff
```
### Remove favorite
```text
DELETE /commands/businesses/:businessId/favorite-staff/:staffId
```
Request body when adding:
```json
{
"tenantId": "uuid",
"staffId": "uuid"
}
```
## 11) Staff review
```text
POST /commands/assignments/:assignmentId/reviews
```
Example request:
```json
{
"tenantId": "uuid",
"businessId": "uuid",
"staffId": "uuid",
"rating": 5,
"reviewText": "Strong shift performance",
"tags": ["punctual", "professional"]
}
```
## 12) Live status
These routes were live-tested on `2026-03-11` against the deployed dev service and `krow-sql-v2`.

View File

@@ -0,0 +1,203 @@
# V2 Core API
Use `core-api-v2` for backend capabilities that should not live in the client.
Base URL:
```text
https://krow-core-api-v2-e3g6witsvq-uc.a.run.app
```
## 1) Route summary
| Method | Route | Purpose |
| --- | --- | --- |
| `POST` | `/core/upload-file` | Upload file to Google Cloud Storage |
| `POST` | `/core/create-signed-url` | Generate a read URL for an uploaded file |
| `POST` | `/core/invoke-llm` | Run a model call |
| `POST` | `/core/rapid-orders/transcribe` | Turn uploaded audio into text |
| `POST` | `/core/rapid-orders/parse` | Turn order text into structured order data |
| `POST` | `/core/verifications` | Create a verification job |
| `GET` | `/core/verifications/:verificationId` | Fetch verification status |
| `POST` | `/core/verifications/:verificationId/review` | Apply manual review decision |
| `POST` | `/core/verifications/:verificationId/retry` | Retry a verification job |
| `GET` | `/health` | Health check |
## 2) Upload file
Route:
```text
POST /core/upload-file
```
Send multipart form data:
- `file`: required
- `category`: optional string
- `visibility`: `public` or `private`
Example response:
```json
{
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/file.pdf",
"contentType": "application/pdf",
"size": 12345,
"bucket": "krow-workforce-dev-private",
"path": "uploads/<uid>/file.pdf",
"requestId": "uuid"
}
```
## 3) Create signed URL
Route:
```text
POST /core/create-signed-url
```
Example request:
```json
{
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/file.pdf",
"expiresInSeconds": 300
}
```
Example response:
```json
{
"signedUrl": "https://...",
"expiresAt": "2026-03-11T18:30:00.000Z",
"requestId": "uuid"
}
```
## 4) Invoke model
Route:
```text
POST /core/invoke-llm
```
Example request:
```json
{
"prompt": "Summarize this staffing request",
"fileUrls": ["gs://krow-workforce-dev-private/uploads/<uid>/notes.pdf"],
"responseJsonSchema": {
"type": "object",
"properties": {
"summary": { "type": "string" }
},
"required": ["summary"]
}
}
```
Example response:
```json
{
"result": {
"summary": "..."
},
"model": "vertex model name",
"latencyMs": 1200,
"requestId": "uuid"
}
```
## 5) Rapid order helpers
### Transcribe
```text
POST /core/rapid-orders/transcribe
```
Example request:
```json
{
"audioFileUri": "gs://krow-workforce-dev-private/uploads/<uid>/note.m4a",
"locale": "en-US",
"promptHints": ["staffing order", "shift details"]
}
```
### Parse
```text
POST /core/rapid-orders/parse
```
Example request:
```json
{
"text": "Need two baristas tomorrow from 8am to 4pm at Google Mountain View Cafe",
"locale": "en-US",
"timezone": "America/Los_Angeles"
}
```
## 6) Verification routes
### Create verification
```text
POST /core/verifications
```
Example request:
```json
{
"type": "attire",
"subjectType": "staff",
"subjectId": "staff-uuid",
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/attire.jpg",
"rules": {
"label": "black shoes"
}
}
```
### Get verification
```text
GET /core/verifications/:verificationId
```
### Manual review
```text
POST /core/verifications/:verificationId/review
```
Example request:
```json
{
"decision": "APPROVED",
"note": "Manual review passed"
}
```
### Retry
```text
POST /core/verifications/:verificationId/retry
```
## 7) Caveat
Verification state is not yet stored in `krow-sql-v2`.
Use these routes now for frontend integration, but do not depend on verification history being durable until the persistence work lands.

View File

@@ -0,0 +1,151 @@
# V2 Query API
Use `query-api-v2` for implemented read screens in the v2 clients.
Base URL:
```text
https://krow-query-api-v2-e3g6witsvq-uc.a.run.app
```
## 1) Required header
```http
Authorization: Bearer <firebase-id-token>
```
## 2) Route summary
| Method | Route | Purpose |
| --- | --- | --- |
| `GET` | `/query/tenants/:tenantId/orders` | Order list |
| `GET` | `/query/tenants/:tenantId/orders/:orderId` | Order detail with shifts and roles |
| `GET` | `/query/tenants/:tenantId/businesses/:businessId/favorite-staff` | Favorite staff list |
| `GET` | `/query/tenants/:tenantId/staff/:staffId/review-summary` | Staff rating summary and recent reviews |
| `GET` | `/query/tenants/:tenantId/assignments/:assignmentId/attendance` | Attendance session and event detail |
| `GET` | `/readyz` | Ready check |
## 3) Order list
```text
GET /query/tenants/:tenantId/orders
```
Optional query params:
- `businessId`
- `status`
- `limit`
- `offset`
Response shape:
```json
{
"items": [
{
"id": "uuid",
"orderNumber": "ORD-1001",
"title": "Cafe Event Staffing",
"status": "OPEN",
"serviceType": "EVENT",
"startsAt": "2026-03-12T08:00:00.000Z",
"endsAt": "2026-03-12T16:00:00.000Z",
"businessId": "uuid",
"businessName": "Google Mountain View Cafes",
"vendorId": "uuid",
"vendorName": "Legendary Staffing Pool A",
"shiftCount": 1,
"requiredWorkers": 2,
"assignedWorkers": 1
}
],
"requestId": "uuid"
}
```
## 4) Order detail
```text
GET /query/tenants/:tenantId/orders/:orderId
```
Response shape:
```json
{
"id": "uuid",
"orderNumber": "ORD-1001",
"title": "Cafe Event Staffing",
"status": "OPEN",
"businessId": "uuid",
"businessName": "Google Mountain View Cafes",
"vendorId": "uuid",
"vendorName": "Legendary Staffing Pool A",
"shifts": [
{
"id": "uuid",
"shiftCode": "SHIFT-1",
"title": "Morning Shift",
"status": "OPEN",
"startsAt": "2026-03-12T08:00:00.000Z",
"endsAt": "2026-03-12T16:00:00.000Z",
"requiredWorkers": 2,
"assignedWorkers": 1,
"roles": [
{
"id": "uuid",
"roleCode": "BARISTA",
"roleName": "Barista",
"workersNeeded": 2,
"assignedCount": 1
}
]
}
],
"requestId": "uuid"
}
```
## 5) Favorite staff list
```text
GET /query/tenants/:tenantId/businesses/:businessId/favorite-staff
```
Optional query params:
- `limit`
- `offset`
## 6) Staff review summary
```text
GET /query/tenants/:tenantId/staff/:staffId/review-summary
```
Optional query params:
- `limit`
Response includes:
- staff identity
- average rating
- rating count
- recent reviews
## 7) Assignment attendance detail
```text
GET /query/tenants/:tenantId/assignments/:assignmentId/attendance
```
Response includes:
- assignment status
- shift info
- attendance session
- ordered attendance events
- NFC and geofence validation fields
## 8) Current boundary
Frontend should use only these documented reads on `query-api-v2`.
Do not point dashboard, reports, finance, or other undocumented list/detail views here yet.

View File

@@ -1,233 +1,10 @@
# M4 API Catalog (Core Only) # Moved
Status: Active The canonical v2 backend API docs now live here:
Date: 2026-03-11
Owner: Technical Lead
Environment: dev
## Frontend source of truth - `docs/BACKEND/API_GUIDES/V2/README.md`
Use this file and `docs/MILESTONES/M4/planning/m4-core-api-frontend-guide.md` for core endpoint consumption. - `docs/BACKEND/API_GUIDES/V2/core-api.md`
Use `docs/MILESTONES/M4/planning/m4-v2-frontend-migration-guide.md` for actual frontend migration sequencing across v2 services. - `docs/BACKEND/API_GUIDES/V2/command-api.md`
- `docs/BACKEND/API_GUIDES/V2/query-api.md`
## Related next-slice contract This file is kept only as a compatibility pointer.
Verification pipeline design (attire, government ID, certification):
- `docs/MILESTONES/M4/planning/m4-verification-architecture-contract.md`
## 1) Scope and purpose
This catalog defines the currently implemented core backend contract for M4.
## 2) Global API rules
1. Route group in scope: `/core/*`.
2. Compatibility aliases in scope:
- `POST /uploadFile` -> `POST /core/upload-file`
- `POST /createSignedUrl` -> `POST /core/create-signed-url`
- `POST /invokeLLM` -> `POST /core/invoke-llm`
3. Auth model:
- `GET /health` is public in dev
- all other routes require `Authorization: Bearer <firebase-id-token>`
4. Standard error envelope:
```json
{
"code": "STRING_CODE",
"message": "Human readable message",
"details": {},
"requestId": "optional-request-id"
}
```
5. Response header:
- `X-Request-Id`
## 3) Core routes
## 3.1 Upload file
1. Method and route: `POST /core/upload-file`
2. Request format: `multipart/form-data`
3. Fields:
- `file` (required)
- `visibility` (`public` or `private`, optional)
- `category` (optional)
4. Accepted types:
- `application/pdf`
- `image/jpeg`
- `image/jpg`
- `image/png`
5. Max size: `10 MB` (default)
6. Behavior: real upload to Cloud Storage.
7. Success `200`:
```json
{
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/...",
"contentType": "application/pdf",
"size": 12345,
"bucket": "krow-workforce-dev-private",
"path": "uploads/<uid>/...",
"requestId": "uuid"
}
```
8. Errors:
- `UNAUTHENTICATED`
- `INVALID_FILE_TYPE`
- `FILE_TOO_LARGE`
## 3.2 Create signed URL
1. Method and route: `POST /core/create-signed-url`
2. Request:
```json
{
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/file.pdf",
"expiresInSeconds": 300
}
```
3. Security checks:
- bucket must be allowed
- path must be owned by caller (`uploads/<caller_uid>/...`)
- object must exist
- `expiresInSeconds <= 900`
4. Success `200`:
```json
{
"signedUrl": "https://storage.googleapis.com/...",
"expiresAt": "2026-02-24T15:22:28.105Z",
"requestId": "uuid"
}
```
5. Errors:
- `VALIDATION_ERROR`
- `FORBIDDEN`
- `NOT_FOUND`
## 3.3 Invoke model
1. Method and route: `POST /core/invoke-llm`
2. Request:
```json
{
"prompt": "...",
"responseJsonSchema": {},
"fileUrls": []
}
```
3. Behavior:
- real Vertex AI call
- model default: `gemini-2.0-flash-001`
- timeout default: `20 seconds`
4. Rate limit:
- `20 requests/minute` per user (default)
- when exceeded: `429 RATE_LIMITED` and `Retry-After` header
5. Success `200`:
```json
{
"result": {},
"model": "gemini-2.0-flash-001",
"latencyMs": 367,
"requestId": "uuid"
}
```
6. Errors:
- `UNAUTHENTICATED`
- `VALIDATION_ERROR`
- `MODEL_TIMEOUT`
- `MODEL_FAILED`
- `RATE_LIMITED`
## 3.4 Create verification job
1. Method and route: `POST /core/verifications`
2. Auth: required
3. Request:
```json
{
"type": "attire",
"subjectType": "worker",
"subjectId": "worker_123",
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/file.pdf",
"rules": {}
}
```
4. Behavior:
- validates `fileUri` ownership
- requires file existence when `UPLOAD_MOCK=false` and `VERIFICATION_REQUIRE_FILE_EXISTS=true`
- enqueues async verification
5. Success `202`:
```json
{
"verificationId": "ver_123",
"status": "PENDING",
"type": "attire",
"requestId": "uuid"
}
```
6. Errors:
- `UNAUTHENTICATED`
- `VALIDATION_ERROR`
- `FORBIDDEN`
- `NOT_FOUND`
## 3.5 Get verification status
1. Method and route: `GET /core/verifications/{verificationId}`
2. Auth: required
3. Success `200`:
```json
{
"verificationId": "ver_123",
"status": "NEEDS_REVIEW",
"type": "attire",
"requestId": "uuid"
}
```
4. Errors:
- `UNAUTHENTICATED`
- `FORBIDDEN`
- `NOT_FOUND`
## 3.6 Review verification
1. Method and route: `POST /core/verifications/{verificationId}/review`
2. Auth: required
3. Request:
```json
{
"decision": "APPROVED",
"note": "Manual review passed",
"reasonCode": "MANUAL_REVIEW"
}
```
4. Success `200`: status becomes `APPROVED` or `REJECTED`.
5. Errors:
- `UNAUTHENTICATED`
- `VALIDATION_ERROR`
- `FORBIDDEN`
- `NOT_FOUND`
## 3.7 Retry verification
1. Method and route: `POST /core/verifications/{verificationId}/retry`
2. Auth: required
3. Success `202`: status resets to `PENDING`.
4. Errors:
- `UNAUTHENTICATED`
- `FORBIDDEN`
- `NOT_FOUND`
## 3.8 Health
1. Method and route: `GET /health`
2. Success `200`:
```json
{
"ok": true,
"service": "krow-core-api",
"version": "dev",
"requestId": "uuid"
}
```
## 4) Locked defaults
1. Validation library: `zod`.
2. Validation schema location: `backend/core-api/src/contracts/`.
3. Buckets:
- `krow-workforce-dev-public`
- `krow-workforce-dev-private`
4. Model provider: Vertex AI Gemini.
5. Max signed URL expiry: `900` seconds.
6. LLM timeout: `20000` ms.
7. LLM rate limit: `20` requests/minute/user.
8. Verification access mode default: `authenticated`.
9. Verification file existence check default: enabled (`VERIFICATION_REQUIRE_FILE_EXISTS=true`).
10. Verification attire provider default in dev: `vertex` with model `gemini-2.0-flash-lite-001`.
11. Verification government/certification providers: external adapters via configured provider URL/token.

View File

@@ -1,384 +1,9 @@
# M4 Core API Frontend Guide (Dev) # Moved
Status: Active The canonical Core API frontend doc now lives here:
Last updated: 2026-03-11
Audience: Web and mobile frontend developers
Related guide: - `docs/BACKEND/API_GUIDES/V2/core-api.md`
1. `docs/MILESTONES/M4/planning/m4-v2-frontend-migration-guide.md`
Scope note: Start from:
1. This file documents the core API contract only.
2. For service readiness and migration sequencing across `core-api-v2`, `command-api-v2`, and `query-api-v2`, use the v2 frontend migration guide above.
## 1) Base URLs (dev) - `docs/BACKEND/API_GUIDES/V2/README.md`
1. Core API v2: `https://krow-core-api-v2-e3g6witsvq-uc.a.run.app`
2. Legacy core API: `https://krow-core-api-e3g6witsvq-uc.a.run.app`
3. For new frontend integration on this branch, use the v2 URL.
## 2) Auth requirements
1. Send Firebase ID token on protected routes:
```http
Authorization: Bearer <firebase-id-token>
```
2. Health route is public:
- `GET /health`
3. All other routes require Firebase token.
## 3) Standard error envelope
```json
{
"code": "STRING_CODE",
"message": "Human readable message",
"details": {},
"requestId": "uuid"
}
```
## 4) Core API endpoints
## 4.1 Upload file
1. Route: `POST /core/upload-file`
2. Alias: `POST /uploadFile`
3. Content type: `multipart/form-data`
4. Form fields:
- `file` (required)
- `visibility` (optional: `public` or `private`, default `private`)
- `category` (optional)
5. Accepted file types:
- `application/pdf`
- `image/jpeg`
- `image/jpg`
- `image/png`
- `audio/webm`
- `audio/wav`
- `audio/x-wav`
- `audio/mpeg`
- `audio/mp3`
- `audio/mp4`
- `audio/m4a`
- `audio/aac`
- `audio/ogg`
- `audio/flac`
6. Max upload size: `10 MB` (default)
7. Current behavior: real upload to Cloud Storage (not mock)
8. Success `200` example:
```json
{
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/173...",
"contentType": "application/pdf",
"size": 12345,
"bucket": "krow-workforce-dev-private",
"path": "uploads/<uid>/173..._file.pdf",
"requestId": "uuid"
}
```
## 4.2 Create signed URL
1. Route: `POST /core/create-signed-url`
2. Alias: `POST /createSignedUrl`
3. Request body:
```json
{
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/file.pdf",
"expiresInSeconds": 300
}
```
4. Security checks:
- bucket must be allowed (`krow-workforce-dev-public` or `krow-workforce-dev-private`)
- path must be owned by caller (`uploads/<caller_uid>/...`)
- object must exist
- `expiresInSeconds` must be `<= 900`
5. Success `200` example:
```json
{
"signedUrl": "https://storage.googleapis.com/...",
"expiresAt": "2026-02-24T15:22:28.105Z",
"requestId": "uuid"
}
```
6. Typical errors:
- `400 VALIDATION_ERROR` (bad payload or expiry too high)
- `403 FORBIDDEN` (path not owned by caller)
- `404 NOT_FOUND` (object does not exist)
## 4.3 Invoke model
1. Route: `POST /core/invoke-llm`
2. Alias: `POST /invokeLLM`
3. Request body:
```json
{
"prompt": "Return JSON with keys summary and risk.",
"responseJsonSchema": {
"type": "object",
"properties": {
"summary": { "type": "string" },
"risk": { "type": "string" }
},
"required": ["summary", "risk"]
},
"fileUrls": []
}
```
4. Current behavior: real Vertex model call (not mock)
- model: `gemini-2.0-flash-001`
- timeout: `20 seconds`
5. Rate limit:
- per-user `20 requests/minute` (default)
- on limit: `429 RATE_LIMITED`
- includes `Retry-After` header
6. Success `200` example:
```json
{
"result": { "summary": "text", "risk": "Low" },
"model": "gemini-2.0-flash-001",
"latencyMs": 367,
"requestId": "uuid"
}
```
## 4.4 Rapid order transcribe (audio to text)
1. Route: `POST /core/rapid-orders/transcribe`
2. Auth: required
3. Purpose: transcribe uploaded RAPID voice note into text for the RAPID input box.
4. Request body:
```json
{
"audioFileUri": "gs://krow-workforce-dev-private/uploads/<uid>/rapid-request.webm",
"locale": "en-US",
"promptHints": ["server", "urgent"]
}
```
5. Security checks:
- `audioFileUri` must be in allowed bucket
- `audioFileUri` path must be owned by caller (`uploads/<caller_uid>/...`)
- file existence is required in non-mock upload mode
6. Success `200` example:
```json
{
"transcript": "Need 2 servers ASAP for 4 hours.",
"confidence": 0.87,
"language": "en-US",
"warnings": [],
"model": "gemini-2.0-flash-001",
"latencyMs": 412,
"requestId": "uuid"
}
```
7. Typical errors:
- `400 VALIDATION_ERROR` (invalid payload)
- `401 UNAUTHENTICATED` (missing/invalid bearer token)
- `403 FORBIDDEN` (audio path not owned by caller)
- `429 RATE_LIMITED` (model quota per user)
- `502 MODEL_FAILED` (upstream model output/availability)
## 4.5 Rapid order parse (text to structured draft)
1. Route: `POST /core/rapid-orders/parse`
2. Auth: required
3. Purpose: convert RAPID text into structured one-time order draft JSON for form prefill.
4. Request body:
```json
{
"text": "Need 2 servers ASAP for 4 hours",
"locale": "en-US",
"timezone": "America/New_York",
"now": "2026-02-27T12:00:00.000Z"
}
```
5. Success `200` example:
```json
{
"parsed": {
"orderType": "ONE_TIME",
"isRapid": true,
"positions": [
{ "role": "server", "count": 2 }
],
"startAt": "2026-02-27T12:00:00.000Z",
"endAt": null,
"durationMinutes": 240,
"locationHint": null,
"notes": null,
"sourceText": "Need 2 servers ASAP for 4 hours"
},
"missingFields": [],
"warnings": [],
"confidence": {
"overall": 0.72,
"fields": {
"positions": 0.86,
"startAt": 0.9,
"durationMinutes": 0.88
}
},
"model": "gemini-2.0-flash-001",
"latencyMs": 531,
"requestId": "uuid"
}
```
6. Contract notes:
- unknown request keys are rejected (`400 VALIDATION_ERROR`)
- when information is missing/ambiguous, backend returns `missingFields` and `warnings`
- frontend should use output to prefill one-time order and request user confirmation where needed
## 4.6 Create verification job
1. Route: `POST /core/verifications`
2. Auth: required
3. Purpose: enqueue an async verification job for an uploaded file.
4. Request body:
```json
{
"type": "attire",
"subjectType": "worker",
"subjectId": "<worker-id>",
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/file.pdf",
"rules": {
"dressCode": "black shoes"
}
}
```
5. Success `202` example:
```json
{
"verificationId": "ver_123",
"status": "PENDING",
"type": "attire",
"requestId": "uuid"
}
```
6. Current machine processing behavior in dev:
- `attire`: live vision check using Vertex Gemini Flash Lite model.
- `government_id`: third-party adapter path (falls back to `NEEDS_REVIEW` if provider is not configured).
- `certification`: third-party adapter path (falls back to `NEEDS_REVIEW` if provider is not configured).
## 4.7 Get verification status
1. Route: `GET /core/verifications/{verificationId}`
2. Auth: required
3. Purpose: polling status from frontend.
4. Success `200` example:
```json
{
"verificationId": "ver_123",
"status": "NEEDS_REVIEW",
"type": "attire",
"review": null,
"requestId": "uuid"
}
```
## 4.8 Review verification
1. Route: `POST /core/verifications/{verificationId}/review`
2. Auth: required
3. Purpose: final human decision for the verification.
4. Request body:
```json
{
"decision": "APPROVED",
"note": "Manual review passed",
"reasonCode": "MANUAL_REVIEW"
}
```
5. Success `200` example:
```json
{
"verificationId": "ver_123",
"status": "APPROVED",
"review": {
"decision": "APPROVED",
"reviewedBy": "<uid>"
},
"requestId": "uuid"
}
```
## 4.9 Retry verification
1. Route: `POST /core/verifications/{verificationId}/retry`
2. Auth: required
3. Purpose: requeue verification to run again.
4. Success `202` example: status resets to `PENDING`.
## 5) Frontend fetch examples (web)
## 5.1 Signed URL request
```ts
const token = await firebaseAuth.currentUser?.getIdToken();
const res = await fetch('https://krow-core-api-v2-e3g6witsvq-uc.a.run.app/core/create-signed-url', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
fileUri: 'gs://krow-workforce-dev-private/uploads/<uid>/file.pdf',
expiresInSeconds: 300,
}),
});
const data = await res.json();
```
## 5.2 Model request
```ts
const token = await firebaseAuth.currentUser?.getIdToken();
const res = await fetch('https://krow-core-api-v2-e3g6witsvq-uc.a.run.app/core/invoke-llm', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt: 'Return JSON with status.',
responseJsonSchema: {
type: 'object',
properties: { status: { type: 'string' } },
required: ['status'],
},
}),
});
const data = await res.json();
```
## 5.3 Rapid audio transcribe request
```ts
const token = await firebaseAuth.currentUser?.getIdToken();
const res = await fetch('https://krow-core-api-v2-e3g6witsvq-uc.a.run.app/core/rapid-orders/transcribe', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
audioFileUri: 'gs://krow-workforce-dev-private/uploads/<uid>/rapid-request.webm',
locale: 'en-US',
promptHints: ['server', 'urgent'],
}),
});
const data = await res.json();
```
## 5.4 Rapid text parse request
```ts
const token = await firebaseAuth.currentUser?.getIdToken();
const res = await fetch('https://krow-core-api-v2-e3g6witsvq-uc.a.run.app/core/rapid-orders/parse', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: 'Need 2 servers ASAP for 4 hours',
locale: 'en-US',
timezone: 'America/New_York',
}),
});
const data = await res.json();
```
## 6) Notes for frontend team
1. Use canonical `/core/*` routes for new work.
2. Aliases exist only for migration compatibility.
3. `requestId` in responses should be logged client-side for debugging.
4. For 429 on model route, retry with exponential backoff and respect `Retry-After`.
5. Verification routes are now available in dev under `/core/verifications*`.
6. Current verification processing is async and returns machine statuses first (`PENDING`, `PROCESSING`, `NEEDS_REVIEW`, etc.).
7. Full verification design and policy details:
`docs/MILESTONES/M4/planning/m4-verification-architecture-contract.md`.

View File

@@ -1,303 +1,10 @@
# M4 V2 Frontend Migration Guide # Moved
Status: Active The canonical frontend-facing v2 backend docs now live here:
Last updated: 2026-03-11
Audience: Web and mobile frontend developers
## 1) Purpose - `docs/BACKEND/API_GUIDES/V2/README.md`
This document tells frontend exactly how to migrate toward the v2 backend services on this branch. - `docs/BACKEND/API_GUIDES/V2/core-api.md`
- `docs/BACKEND/API_GUIDES/V2/command-api.md`
- `docs/BACKEND/API_GUIDES/V2/query-api.md`
It is intentionally strict about readiness: This file is kept only as a compatibility pointer.
1. `core-api-v2` is ready for frontend integration now for uploads, signed URLs, model calls, and verification workflows.
2. `command-api-v2` now has a first real write slice backed by the v2 SQL schema and verified through live smoke tests.
3. `query-api-v2` now has a first real read slice backed by the v2 SQL schema and verified through live smoke tests.
Frontend should not assume all three services are ready just because they are deployed.
## 2) Live dev service URLs
1. Core API v2: `https://krow-core-api-v2-e3g6witsvq-uc.a.run.app`
2. Command API v2: `https://krow-command-api-v2-e3g6witsvq-uc.a.run.app`
3. Query API v2: `https://krow-query-api-v2-e3g6witsvq-uc.a.run.app`
## 3) Readiness summary
| Service | Status | Frontend guidance |
| --- | --- | --- |
| `core-api-v2` | Ready now with persistence caveat | Use for file upload, signed URLs, model calls, rapid order helpers, and verification flows |
| `command-api-v2` | First production slice | Use for documented v2 write flows only |
| `query-api-v2` | First production slice | Use for documented v2 read flows only |
## 4) Non-negotiable migration rules
1. Do not point undocumented read screens to `query-api-v2` yet.
2. Do not replace undocumented order, shift, or staffing mutations with `command-api-v2` yet.
3. Do move all new service-style frontend work to `core-api-v2`.
4. Do use command/query v2 for the routes listed in this document when building the new v2 clients.
5. Any new frontend abstraction should separate:
- `core service client`
- `command service client`
- `query service client`
- `legacy Data Connect access`
6. Build the frontend with switchable adapters so the command/query cutover is a client config change, not a rewrite.
## 5) Auth and headers
All protected v2 routes currently require Firebase ID token:
```http
Authorization: Bearer <firebase-id-token>
```
All services return:
1. `X-Request-Id` response header
2. Standard error envelope:
```json
{
"code": "STRING_CODE",
"message": "Human readable message",
"details": {},
"requestId": "uuid"
}
```
Additional rule for command routes:
```http
Idempotency-Key: <unique-per-user-action>
```
## 6) What frontend can migrate now
### 6.1 Move to `core-api-v2` now
1. File uploads
2. Signed download URL generation
3. Rapid order voice transcription
4. Rapid order structured parsing
5. Generic model invocation
6. Verification job creation
7. Verification status polling
8. Manual verification review and retry
### 6.2 Keep on existing stack for now
1. Business reads
2. Staff reads
3. Shift lists and details outside the documented order detail shape
4. Applications lists and details not yet served by query v2
5. Payments and reporting reads
### 6.3 Move to command/query v2 now for the new v2 clients
1. Order creation
2. Order update
3. Order cancel
4. Shift assign staff
5. Shift accept
6. Shift status change
7. Attendance clock-in and clock-out
8. Favorite staff add and remove
9. Staff review create
10. Order list
11. Order detail
12. Favorite staff list
13. Staff review summary
14. Assignment attendance detail
## 7) Core API v2 routes frontend can use today
Use this service for backend capabilities that should not run directly from the client.
Important caveat:
1. File storage is real and backed by Google Cloud Storage.
2. Verification job state is not yet persisted to the v2 SQL schema.
3. Frontend can integrate with these routes now, but do not treat verification history as mission-critical durable state yet.
Base URL:
```text
https://krow-core-api-v2-e3g6witsvq-uc.a.run.app
```
Routes:
1. `POST /core/upload-file`
2. `POST /core/create-signed-url`
3. `POST /core/invoke-llm`
4. `POST /core/rapid-orders/transcribe`
5. `POST /core/rapid-orders/parse`
6. `POST /core/verifications`
7. `GET /core/verifications/:verificationId`
8. `POST /core/verifications/:verificationId/review`
9. `POST /core/verifications/:verificationId/retry`
10. `GET /health`
For request and response examples, use:
1. `docs/MILESTONES/M4/planning/m4-core-api-frontend-guide.md`
2. `docs/MILESTONES/M4/planning/m4-api-catalog.md`
## 8) Command API v2 routes ready for the first migration slice
These routes are deployed and backed by the v2 SQL schema. They enforce auth, policy gate, and idempotency.
Base URL:
```text
https://krow-command-api-v2-e3g6witsvq-uc.a.run.app
```
Routes:
1. `POST /commands/orders/create`
2. `POST /commands/orders/:orderId/update`
3. `POST /commands/orders/:orderId/cancel`
4. `POST /commands/shifts/:shiftId/change-status`
5. `POST /commands/shifts/:shiftId/assign-staff`
6. `POST /commands/shifts/:shiftId/accept`
7. `POST /commands/attendance/clock-in`
8. `POST /commands/attendance/clock-out`
9. `POST /commands/businesses/:businessId/favorite-staff`
10. `DELETE /commands/businesses/:businessId/favorite-staff/:staffId`
11. `POST /commands/assignments/:assignmentId/reviews`
12. `GET /health`
13. `GET /readyz`
Implemented now:
1. `POST /commands/orders/create`
2. `POST /commands/orders/:orderId/update`
3. `POST /commands/orders/:orderId/cancel`
4. `POST /commands/shifts/:shiftId/change-status`
5. `POST /commands/shifts/:shiftId/assign-staff`
6. `POST /commands/shifts/:shiftId/accept`
7. `POST /commands/attendance/clock-in`
8. `POST /commands/attendance/clock-out`
9. `POST /commands/businesses/:businessId/favorite-staff`
10. `DELETE /commands/businesses/:businessId/favorite-staff/:staffId`
11. `POST /commands/assignments/:assignmentId/reviews`
Live verification completed on 2026-03-11:
1. order create
2. order update
3. order cancel
4. shift assign staff
5. shift accept
6. shift status change
7. attendance clock-in
8. attendance clock-out
9. favorite add
10. favorite list
11. review create
12. review summary
13. order list/detail
14. attendance detail
Order creation request contract:
```json
{
"tenantId": "uuid",
"businessId": "uuid",
"vendorId": "uuid",
"orderNumber": "ORD-1001",
"title": "Cafe Event Staffing",
"serviceType": "EVENT",
"shifts": [
{
"shiftCode": "SHIFT-1",
"title": "Morning Shift",
"startsAt": "2026-03-11T08:00:00.000Z",
"endsAt": "2026-03-11T16:00:00.000Z",
"requiredWorkers": 2,
"roles": [
{
"roleCode": "BARISTA",
"roleName": "Barista",
"workersNeeded": 2
}
]
}
]
}
```
Order creation success response:
```json
{
"orderId": "uuid",
"orderNumber": "ORD-1001",
"status": "OPEN",
"shiftCount": 1,
"shiftIds": ["uuid"],
"idempotencyKey": "abc-123",
"requestId": "uuid"
}
```
Important:
1. This is the first real write slice, not the full command surface.
2. Frontend should migrate only the documented routes.
3. Reuse one idempotency key per user action and never retry with a new key unless the UI is creating a brand new action.
4. The old `501` placeholders for order update, order cancel, shift status change, and shift assign staff are now implemented.
## 9) Query API v2 routes ready for the first migration slice
Base URL:
```text
https://krow-query-api-v2-e3g6witsvq-uc.a.run.app
```
Current routes:
1. `GET /health`
2. `GET /healthz`
3. `GET /readyz`
4. `GET /query/tenants/:tenantId/orders`
5. `GET /query/tenants/:tenantId/orders/:orderId`
6. `GET /query/tenants/:tenantId/businesses/:businessId/favorite-staff`
7. `GET /query/tenants/:tenantId/staff/:staffId/review-summary`
8. `GET /query/tenants/:tenantId/assignments/:assignmentId/attendance`
Frontend can point the new v2 clients to these routes now. Frontend should not point any undocumented screen, list, detail page, dashboard, or reporting view to `query-api-v2` yet.
## 10) Recommended frontend adapter shape
Frontend should isolate backend calls behind service adapters instead of calling routes inline in screens.
Suggested split:
1. `coreApiClient`
2. `commandApiClient`
3. `queryApiClient`
4. `legacyDataConnectClient`
Suggested cutover plan:
1. Move service-style operations to `coreApiClient` first.
2. Add `commandApiClient` now as the write path for the documented v2 write routes.
3. Add `queryApiClient` now as the read path for the documented v2 read routes.
4. Keep everything else on `legacyDataConnectClient` until the replacement route exists.
5. Expand migration route-by-route instead of big-bang switching whole apps.
## 11) Frontend implementation checklist
1. Add three environment variables:
- `CORE_API_V2_BASE_URL`
- `COMMAND_API_V2_BASE_URL`
- `QUERY_API_V2_BASE_URL`
2. Add shared auth header injection using Firebase ID token.
3. Add shared response envelope parsing.
4. Add request ID logging in frontend network layer.
5. Add `Idempotency-Key` generation utility for command calls.
6. Build command/query clients behind feature flags or adapter switches.
7. Start integration with `core-api-v2`, `command-api-v2`, and `query-api-v2` for the documented routes only.
## 12) Frontend do and do not
Do:
1. Treat `core-api-v2` as the real backend entrypoint for uploads, model work, and verification.
2. Treat documented command/query v2 routes as the real backend entrypoint for the first v2 domain slice.
3. Build migration-safe abstractions now.
4. Keep old reads and writes isolated so they can be swapped cleanly later.
Do not:
1. Hardcode v2 command success as if business action is complete.
2. Point undocumented dashboards or reports to query v2 yet.
3. Remove current Data Connect code until the replacement route actually exists and is verified.
## 13) Practical migration sequence
1. Replace existing upload helpers with `core-api-v2`.
2. Replace signed URL generation with `core-api-v2`.
3. Point rapid order helpers to `core-api-v2`.
4. Point attire and document verification flows to `core-api-v2`.
5. Introduce command client wrapper with idempotency header support.
6. Point new v2 order creation, shift accept, attendance, favorites, and reviews flows to `command-api-v2`.
7. Point new v2 order list/detail, favorites, review summary, and attendance detail screens to `query-api-v2`.
8. Point new v2 order update, order cancel, shift assign, and shift status flows to `command-api-v2`.
9. Keep payments, reports, and remaining scheduling mutations on the legacy stack until the replacement routes exist.