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,233 +1,10 @@
# M4 API Catalog (Core Only)
# Moved
Status: Active
Date: 2026-03-11
Owner: Technical Lead
Environment: dev
The canonical v2 backend API docs now live here:
## Frontend source of truth
Use this file and `docs/MILESTONES/M4/planning/m4-core-api-frontend-guide.md` for core endpoint consumption.
Use `docs/MILESTONES/M4/planning/m4-v2-frontend-migration-guide.md` for actual frontend migration sequencing across v2 services.
- `docs/BACKEND/API_GUIDES/V2/README.md`
- `docs/BACKEND/API_GUIDES/V2/core-api.md`
- `docs/BACKEND/API_GUIDES/V2/command-api.md`
- `docs/BACKEND/API_GUIDES/V2/query-api.md`
## Related next-slice contract
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.
This file is kept only as a compatibility pointer.

View File

@@ -1,384 +1,9 @@
# M4 Core API Frontend Guide (Dev)
# Moved
Status: Active
Last updated: 2026-03-11
Audience: Web and mobile frontend developers
The canonical Core API frontend doc now lives here:
Related guide:
1. `docs/MILESTONES/M4/planning/m4-v2-frontend-migration-guide.md`
- `docs/BACKEND/API_GUIDES/V2/core-api.md`
Scope note:
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.
Start from:
## 1) Base URLs (dev)
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`.
- `docs/BACKEND/API_GUIDES/V2/README.md`

View File

@@ -1,303 +1,10 @@
# M4 V2 Frontend Migration Guide
# Moved
Status: Active
Last updated: 2026-03-11
Audience: Web and mobile frontend developers
The canonical frontend-facing v2 backend docs now live here:
## 1) Purpose
This document tells frontend exactly how to migrate toward the v2 backend services on this branch.
- `docs/BACKEND/API_GUIDES/V2/README.md`
- `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:
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.
This file is kept only as a compatibility pointer.