docs: 更新 HTTP 错误码、用户积分、占卜运行及用户资料协议文档
This commit is contained in:
@@ -12,6 +12,7 @@ This document is the source of truth for backend RFC7807 `code` values consumed
|
||||
| `AUTH_REFRESH_TOKEN_INVALID` | 401 | Invalid/expired refresh token | Clear local session and return login |
|
||||
| `AUTH_REFRESH_TOKEN_MISSING` | 401 | Refresh token missing on logout | Treat as local logout and clear session |
|
||||
| `AUTH_USER_NOT_FOUND` | 404 | User not found | Show not-found message where applicable |
|
||||
| `AUTH_UNAUTHORIZED` | 401 | Missing or invalid auth credentials | Force logout and redirect to login |
|
||||
|
||||
## Agent Points
|
||||
|
||||
@@ -23,16 +24,41 @@ This document is the source of truth for backend RFC7807 `code` values consumed
|
||||
|
||||
| code | status | meaning | frontend handling |
|
||||
|---|---:|---|---|
|
||||
| `AGENT_SESSION_RUN_LIMIT_EXCEEDED` | 409 | Session already reached max run count (start + 1 follow-up) | Show run-limit message and require starting a new session |
|
||||
| `AGENT_SESSION_RUN_LIMIT_EXCEEDED` | 409 | Session already reached max message count (2 user messages per session: initial divination + 1 follow-up) | Show run-limit message and require starting a new session |
|
||||
| `AGENT_RUNTIME_MODE_INVALID` | 422 | Missing or invalid `forwardedProps.runtime_mode` in run request | Show invalid-request message and retry from current page |
|
||||
| `AGENT_DIVINATION_PAYLOAD_REQUIRED` | 422 | Missing required `forwardedProps.divinationPayload` in run request | Prompt user to restart casting flow and resubmit |
|
||||
| `AGENT_OUTPUT_DIVINATION_INVALID` | 422 | Worker output contains invalid `divination_derived` payload shape | Show generic history parse error and suggest retrying latest run |
|
||||
| `AGENT_SESSION_ID_INVALID` | 422 | Invalid session/thread id format | Show invalid-session message and force refresh history |
|
||||
| `AGENT_SESSION_NOT_FOUND` | 404 | Session does not exist (including follow-up on non-existing thread) | Show session-not-found message and refresh history |
|
||||
| `AGENT_USER_ID_INVALID` | 422 | Invalid user id in request context | Show invalid-request message |
|
||||
| `AGENT_AUDIO_UNSUPPORTED_FORMAT` | 400 | Audio format is not accepted by transcribe endpoint | Show format hint and ask user to retry with wav audio |
|
||||
| `AGENT_AUDIO_TOO_LARGE` | 400 | Audio file exceeds transcribe size limit | Show size-limit message and ask user to shorten audio |
|
||||
| `AGENT_AUDIO_EMPTY` | 400 | Uploaded audio payload is empty | Show retry hint and keep input unchanged |
|
||||
| `AGENT_ASR_UNAVAILABLE` | 502 | Upstream ASR service unavailable | Show retry message and allow fallback to text input |
|
||||
| `AGENT_PAYLOAD_INVALID` | 422 | Parsed run input payload is invalid | Show invalid-request message and retry from current page |
|
||||
| `AGENT_RUN_INPUT_INVALID` | 422 | Run request body fails validation | Show invalid-request message and retry |
|
||||
| `AGENT_RUN_MESSAGES_INVALID` | 422 | Run request messages contract violation | Show invalid-request message and retry |
|
||||
| `AGENT_INVALID_RUN_ID` | 422 | Invalid or missing `runId` query parameter | Show invalid-request message and retry |
|
||||
| `AGENT_INVALID_LAST_EVENT_ID` | 422 | Invalid `Last-Event-ID` header format | Retry without the header |
|
||||
| `AGENT_SSE_CONNECTION_LIMIT` | 429 | Too many concurrent SSE connections per user | Show connection-limit message and reduce concurrent streams |
|
||||
| `AGENT_FORBIDDEN` | 403 | User does not own the session resource | Force refresh and show unauthorized message |
|
||||
| `AGENT_ATTACHMENT_EMPTY` | 422 | Uploaded attachment payload is empty | Show retry hint and keep input unchanged |
|
||||
| `AGENT_ATTACHMENT_TOO_LARGE` | 413 | Attachment file exceeds size limit | Show size-limit message and ask user to use smaller file |
|
||||
| `AGENT_ATTACHMENTS_TOO_MANY` | 422 | Too many attachments in single message | Show attachment limit message |
|
||||
| `AGENT_ATTACHMENT_UNSUPPORTED_TYPE` | 422 | Attachment mime type is not supported | Show unsupported type message |
|
||||
| `AGENT_ATTACHMENT_UPLOAD_FAILED` | 502 | Backend failed to upload attachment to storage | Show retry toast |
|
||||
| `AGENT_ATTACHMENT_STORAGE_UNAVAILABLE` | 503 | Attachment storage service unavailable | Show retry message |
|
||||
| `AGENT_ATTACHMENT_BUCKET_INVALID` | 422 | Attachment bucket name is invalid | Show generic error and force refresh |
|
||||
| `AGENT_ATTACHMENT_PATH_SCOPE_INVALID` | 422 | Attachment path does not belong to user scope | Show generic security error and force refresh |
|
||||
| `AGENT_SIGNED_URL_GENERATION_FAILED` | 502 | Backend failed to generate attachment signed URL | Show retry toast |
|
||||
| `AGENT_SIGNED_IMAGE_URL_INVALID` | 422 | Signed image URL is invalid or expired | Show error and retry image load |
|
||||
|
||||
## Agent Internal (Binary URL Validation)
|
||||
|
||||
| code | status | meaning | frontend handling |
|
||||
|---|---:|---|---|
|
||||
| `INVALID_BINARY_URL_HOST` | 422 | Binary URL host is not allowed | Show error and retry |
|
||||
| `INVALID_BINARY_URL_BUCKET` | 422 | Binary URL bucket name is invalid | Show error and retry |
|
||||
| `INVALID_BINARY_URL_PATH_SCOPE` | 422 | Binary URL path does not belong to allowed scope | Show error and retry |
|
||||
|
||||
## Profile
|
||||
|
||||
@@ -51,8 +77,17 @@ This document is the source of truth for backend RFC7807 `code` values consumed
|
||||
| `AVATAR_SIGNED_URL_FAILED` | 502 | Backend failed to generate avatar signed upload URL | Show retry toast and keep previous avatar |
|
||||
| `AVATAR_UPLOAD_FAILED` | 502 | Backend failed to upload avatar bytes to storage | Show retry toast and keep previous avatar |
|
||||
|
||||
Compatibility strategy:
|
||||
## Global
|
||||
|
||||
- Additive changes only for new codes.
|
||||
- Existing codes must keep semantic meaning.
|
||||
- Frontend must map by `code`, not by `detail` text.
|
||||
| code | status | meaning | frontend handling |
|
||||
|---|---:|---|---|
|
||||
| `REQUEST_VALIDATION_ERROR` | 422 | Request validation failed | Show invalid-request message |
|
||||
| `INTERNAL_ERROR` | 500 | Unexpected internal server error | Show generic error and allow retry |
|
||||
|
||||
## Tool (Internal Agent Runtime)
|
||||
|
||||
| code | status | meaning | frontend handling |
|
||||
|---|---:|---|---|
|
||||
| `MISSING_RUNTIME_ARGS` | 500 | Tool call missing required runtime arguments | Show error and retry |
|
||||
| `TOOL_REJECTED` | 403 | Tool execution was rejected | Show tool rejection message |
|
||||
| `TOOL_PENDING_APPROVAL` | 202 | Tool execution awaiting approval | Show pending approval state |
|
||||
|
||||
@@ -4,9 +4,9 @@ This protocol defines the canonical data contract for user profile, points accou
|
||||
|
||||
Protocol verification status:
|
||||
|
||||
- Last audited migration: `backend/alembic/versions/20260410_0005_add_points_audit_and_register_bonus_claims.py`
|
||||
- Last audited migration: `backend/alembic/versions/20260411_0003_points_audit_and_register_bonus_claims.py`
|
||||
- Last audited models: `backend/src/models/profile.py`, `backend/src/models/user_points.py`, `backend/src/models/points_ledger.py`, `backend/src/models/points_audit_ledger.py`, `backend/src/models/register_bonus_claims.py`, `backend/src/models/agent_chat_session.py`, `backend/src/models/agent_chat_message.py`
|
||||
- Current status: partially aligned (register bonus still runs in DB trigger, audit ledger tables are additive and ready)
|
||||
- Current status: aligned with register bonus moved to application service
|
||||
|
||||
## Scope
|
||||
|
||||
@@ -139,16 +139,14 @@ JSON constraints:
|
||||
- `grant`: no extra metadata shape requirement
|
||||
- `adjust`: requires `ext.ticket_id` non-empty
|
||||
|
||||
## Signup initialization contract (current + target)
|
||||
## Signup initialization contract
|
||||
|
||||
- Current trigger:
|
||||
- Trigger: `auth.users` after insert
|
||||
- DB trigger (`auth.users` after insert):
|
||||
- Function: `public.initialize_profile_and_invite_code_on_signup()`
|
||||
- Side effects include profile init + invite code init + register points (currently fixed to 60)
|
||||
- Target migration:
|
||||
- remove register points grant from DB trigger
|
||||
- grant register bonus in application service with eligibility ledger `register_bonus_claims`
|
||||
- keep trigger focused on profile/invite initialization only
|
||||
- Side effects: profile init + invite code init
|
||||
- Application service (in `POST /auth/email-session`):
|
||||
- `grant_register_bonus_if_eligible()` grants register bonus via `register_bonus_claims` ledger
|
||||
- Bonus amount from `config.points_policy.register_bonus_points`
|
||||
|
||||
### sessions
|
||||
|
||||
|
||||
@@ -18,9 +18,12 @@ Protocol verification status:
|
||||
## Route overview
|
||||
|
||||
- Submit run: `POST /api/v1/agent/runs`
|
||||
- Cancel run: `POST /api/v1/agent/runs/{threadId}/cancel?runId=...`
|
||||
- Stream events: `GET /api/v1/agent/runs/{threadId}/events?runId=...`
|
||||
- History snapshot: `GET /api/v1/agent/history`
|
||||
- Delete session: `DELETE /api/v1/agent/sessions/{threadId}`
|
||||
- Upload attachment: `POST /api/v1/agent/attachments`
|
||||
- Get attachment signed URL: `GET /api/v1/agent/attachments/signed-url?bucket=...&path=...`
|
||||
- Audio transcribe: `POST /api/v1/agent/transcribe`
|
||||
|
||||
## Run request contract
|
||||
@@ -81,8 +84,8 @@ Protocol verification status:
|
||||
### `divinationPayload` strict rules
|
||||
|
||||
- `divinationMethod`: enum, allowed values `手动起卦 | 自动起卦`
|
||||
- `questionType`: non-empty string, recommended Chinese category labels
|
||||
- `question`: non-empty string
|
||||
- `questionType`: non-empty string, max 32 chars, recommended Chinese category labels
|
||||
- `question`: non-empty string, max 300 chars
|
||||
- `divinationTimeIso`: RFC3339 datetime with timezone offset
|
||||
- `yaoLines`: exactly 6 items, order is `初爻 -> 上爻`
|
||||
- `yaoLines` item enum: `少阳 | 少阴 | 老阳 | 老阴`
|
||||
@@ -301,6 +304,82 @@ Rules:
|
||||
- Success: `204 No Content`.
|
||||
- Idempotent: already deleted or not found also returns `204 No Content`.
|
||||
|
||||
## Run cancel contract
|
||||
|
||||
### `POST /api/v1/agent/runs/{threadId}/cancel?runId=...`
|
||||
|
||||
- Authorization: current user must own the session.
|
||||
- Request: `runId` query parameter required.
|
||||
- Success response:
|
||||
|
||||
```json
|
||||
{
|
||||
"threadId": "uuid",
|
||||
"runId": "run_xxx",
|
||||
"accepted": true
|
||||
}
|
||||
```
|
||||
|
||||
Error codes (see common registry):
|
||||
|
||||
- `AGENT_SESSION_NOT_FOUND`
|
||||
- `AGENT_FORBIDDEN`
|
||||
|
||||
## Attachment upload contract
|
||||
|
||||
### `POST /api/v1/agent/attachments`
|
||||
|
||||
- Authorization: authenticated user.
|
||||
- Request: `multipart/form-data` with fields:
|
||||
- `threadId` (string, required)
|
||||
- `file` (binary, required)
|
||||
- Max file size: 5MB
|
||||
- Success response:
|
||||
|
||||
```json
|
||||
{
|
||||
"attachment": {
|
||||
"bucket": "agent-inputs",
|
||||
"path": "agent-inputs/{userId}/{filename}",
|
||||
"mimeType": "image/png",
|
||||
"url": "https://...signed..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Error codes (see common registry):
|
||||
|
||||
- `AGENT_ATTACHMENT_EMPTY`
|
||||
- `AGENT_ATTACHMENT_TOO_LARGE`
|
||||
- `AGENT_ATTACHMENT_STORAGE_UNAVAILABLE`
|
||||
- `AGENT_SESSION_NOT_FOUND`
|
||||
- `AGENT_FORBIDDEN`
|
||||
|
||||
## Attachment signed URL contract
|
||||
|
||||
### `GET /api/v1/agent/attachments/signed-url?bucket=...&path=...`
|
||||
|
||||
- Authorization: authenticated user.
|
||||
- Query params:
|
||||
- `bucket` (string, required)
|
||||
- `path` (string, required)
|
||||
- Path must be under `agent-inputs/{userId}/` scope.
|
||||
- Success response:
|
||||
|
||||
```json
|
||||
{
|
||||
"bucket": "agent-inputs",
|
||||
"path": "agent-inputs/{userId}/{filename}",
|
||||
"url": "https://...signed..."
|
||||
}
|
||||
```
|
||||
|
||||
Error codes (see common registry):
|
||||
|
||||
- `AGENT_ATTACHMENT_BUCKET_INVALID`
|
||||
- `AGENT_ATTACHMENT_PATH_SCOPE_INVALID`
|
||||
- `AGENT_SIGNED_URL_GENERATION_FAILED`
|
||||
|
||||
## Transcribe contract
|
||||
|
||||
### `POST /api/v1/agent/transcribe`
|
||||
|
||||
@@ -9,7 +9,7 @@ Protocol verification status:
|
||||
- Backend service source: `backend/src/v1/users/service.py`
|
||||
- Frontend mapping source: `apps/lib/features/settings/data/apis/profile_api.dart`
|
||||
- Storage config source: `backend/src/core/config/settings.py`
|
||||
- Current status: profile/avatar aligned; account deletion backend implemented (frontend wiring pending)
|
||||
- Current status: aligned (profile/avatar/account deletion all implemented)
|
||||
|
||||
## Compatibility strategy
|
||||
|
||||
@@ -82,7 +82,7 @@ Rules:
|
||||
|
||||
- At least one field must be provided.
|
||||
- `display_name` must be non-empty after trim.
|
||||
- `bio` can be empty string and should be normalized to `null` only if agreed by API implementation.
|
||||
- `bio`: empty string after trim is normalized to `null`.
|
||||
- `avatar_path` must stay in current user prefix: `avatars/{current_user.id}/`.
|
||||
|
||||
Response:
|
||||
@@ -208,12 +208,12 @@ Behavior contract:
|
||||
|
||||
### Deletion scope (current product contract)
|
||||
|
||||
The delete operation must remove data owned by the authenticated user in the following domains:
|
||||
The delete operation removes data owned by the authenticated user in the following domains:
|
||||
|
||||
- Identity: `auth.users` row for current user.
|
||||
- Profile: `profiles` row.
|
||||
- Points: `user_points`, `points_ledger` rows linked to user.
|
||||
- Chat: `sessions`, `messages` rows linked to user/session ownership.
|
||||
- Identity: `auth.users` row for current user (cascade delete).
|
||||
- Profile: `profiles` row (FK cascade via `auth.users.id`).
|
||||
- Points: `user_points`, `points_ledger` rows (FK cascade via `auth.users.id`).
|
||||
- Chat: `sessions` rows are soft-deleted (`deleted_at` set); `messages` cascade via `sessions.id FK`. After deletion, sessions are hidden from history but not physically removed.
|
||||
- Avatar storage objects under prefix `avatars/{user_id}/`.
|
||||
|
||||
Notes:
|
||||
|
||||
Reference in New Issue
Block a user