feat: Implement attire photo capture, update AttireItem entity, and streamline the photo upload and state management flow.
This commit is contained in:
245
docs/MILESTONES/M4/planning/m4-core-api-frontend-guide.md
Normal file
245
docs/MILESTONES/M4/planning/m4-core-api-frontend-guide.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# M4 Core API Frontend Guide (Dev)
|
||||
|
||||
Status: Active
|
||||
Last updated: 2026-02-24
|
||||
Audience: Web and mobile frontend developers
|
||||
|
||||
## 1) Base URLs (dev)
|
||||
1. Core API: `https://krow-core-api-e3g6witsvq-uc.a.run.app`
|
||||
|
||||
## 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`
|
||||
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 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.5 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.6 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.7 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-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-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();
|
||||
```
|
||||
|
||||
## 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`.
|
||||
Reference in New Issue
Block a user