feat: 添加 Analytics 分析功能(行为追踪、错误码、协议更新)

This commit is contained in:
qzl
2026-04-02 11:52:23 +08:00
parent b101826de5
commit 7b6dbe72c3
24 changed files with 682 additions and 52 deletions
+7 -7
View File
@@ -110,7 +110,7 @@ data: <json>
"type": "STEP_STARTED",
"threadId": "...",
"runId": "...",
"stepName": "router" | "worker" | "memory"
"stepName": "router" | "worker"
}
```
@@ -121,7 +121,7 @@ data: <json>
"type": "STEP_FINISHED",
"threadId": "...",
"runId": "...",
"stepName": "router" | "worker" | "memory"
"stepName": "router" | "worker"
}
```
@@ -137,7 +137,7 @@ data: <json>
"messageId": "...",
"toolCallId": "...",
"toolCallName": "...",
"stage": "worker" | "memory"
"stage": "worker"
}
```
@@ -152,7 +152,7 @@ data: <json>
"toolCallId": "...",
"toolCallName": "...",
"args": {},
"stage": "worker" | "memory"
"stage": "worker"
}
```
@@ -166,7 +166,7 @@ data: <json>
"messageId": "...",
"toolCallId": "...",
"toolCallName": "...",
"stage": "worker" | "memory"
"stage": "worker"
}
```
@@ -179,7 +179,7 @@ data: <json>
"runId": "...",
"messageId": "...",
"role": "tool",
"stage": "worker" | "memory",
"stage": "worker",
"tool_name": "...",
"tool_call_id": "...",
"tool_call_args": {},
@@ -239,7 +239,7 @@ SSE 协议中的工具名字段保持后端原样,不做服务端翻译:
"runId": "...",
"messageId": "...",
"role": "assistant",
"stage": "worker" | "memory",
"stage": "worker",
"status": "success" | "partial_success" | "failed",
"answer": "...",
"key_points": [],
+146
View File
@@ -0,0 +1,146 @@
# Analytics Events And Dashboard Protocol
本文档定义 analytics 采集与查询协议,覆盖移动端/前端事件上报、Dashboard 登录与按日数据读取。
## 1. Scope
- 事件写入接口:`POST /api/v1/analytics/events`
- Dashboard 登录接口:`POST /api/v1/analytics/login`
- 按日数据读取接口:`GET /api/v1/analytics/data/{YYYY-MM-DD}`
- 存储介质:服务端 JSONL 文件(由 `SOCIAL_ANALYTICS__DATA_PATH` 指定)
## 2. Event Ingestion
### Endpoint
- Method: `POST`
- Path: `/api/v1/analytics/events`
### Request Body
```json
{
"client_time": "2026-04-02T10:00:00Z",
"sdk_version": "1.0.0",
"events": [
{
"event_id": "evt-1",
"event_type": "page_view",
"timestamp": "2026-04-02T10:00:00Z",
"user_id": "user-1",
"device_id": "device-1",
"session_id": "session-1",
"platform": "android",
"app_version": "0.1.2",
"app_build": "5",
"env": "prod",
"page_name": "home",
"trace_id": "trace-1",
"request_id": "request-1",
"attributes": {
"from": "banner"
},
"metrics": {
"latency_ms": 123
},
"context": {
"network_type": "wifi",
"os_version": "Android 14",
"device_model": "Pixel",
"locale": "zh-CN",
"timezone": "Asia/Shanghai"
}
}
]
}
```
### Response Body
```json
{
"received": 1,
"queued": true
}
```
语义说明:
- `received` 表示本次接收的事件条数。
- `queued=true` 表示事件已被服务端接收并触发写入流程;该字段不承诺具体调度方式(请求内写入或队列写入)。
## 3. Dashboard Login
### Endpoint
- Method: `POST`
- Path: `/api/v1/analytics/login`
### Request Body
```json
{
"password": "<analytics-password>"
}
```
### Response Body
```json
{
"success": true,
"data_base_url": "/api/v1/analytics/data",
"token": "<bearer-token>"
}
```
语义说明:
- `token` 为短时效 Bearer Token。
- `data_base_url` 为前端读取按日数据的基路径。
## 4. Read Daily Data
### Endpoint
- Method: `GET`
- Path: `/api/v1/analytics/data/{date}`
- Header: `Authorization: Bearer <token>`
- `date` 格式要求:`YYYY-MM-DD`
### Success Response
- Status: `200`
- Content-Type: `application/x-ndjson`
- Body: 当日 JSONL 文本(每行一个事件 JSON)
## 5. Error Contract
错误响应必须遵循 RFC7807 + 稳定错误码规范,错误码注册表见:
- `docs/protocols/common/http-error-codes.md`
analytics 相关错误码包括:
- `ANALYTICS_LOGIN_PASSWORD_INVALID`
- `ANALYTICS_AUTH_HEADER_MISSING`
- `ANALYTICS_AUTH_SCHEME_INVALID`
- `ANALYTICS_AUTH_TOKEN_MISSING`
- `ANALYTICS_TOKEN_MALFORMED`
- `ANALYTICS_TOKEN_SIGNATURE_INVALID`
- `ANALYTICS_TOKEN_PAYLOAD_INVALID`
- `ANALYTICS_TOKEN_EXPIRED`
- `ANALYTICS_DATE_FORMAT_INVALID`
- `ANALYTICS_FILE_NOT_FOUND`
## 6. Storage Contract
- 后端写入路径由 `SOCIAL_ANALYTICS__DATA_PATH` 控制,默认:`backend/data/analytics`
- 按日存储文件名:`{YYYY-MM-DD}.jsonl`
- 生产部署推荐将宿主机目录挂载到容器内该路径,避免容器重建导致数据丢失。
## 7. Compatibility Strategy
- 策略:**backward-compatible additive change**。
- 允许在事件对象中新增可选字段(`attributes` / `metrics` / `context` 内部字段)。
- 不允许移除现有必填字段或修改既有字段语义;若必须变更,需新增版本化协议文档并提供迁移说明。
+15 -21
View File
@@ -84,6 +84,16 @@ When creating/modifying/deprecating any code, this table must be updated in the
| `AUTH_REFRESH_TOKEN_MISSING` | auth | 401 | Refresh token is missing for logout/refresh |
| `AUTH_USER_NOT_FOUND` | auth | 404 | User lookup by phone returns no match |
| `AUTH_UNAUTHORIZED` | auth | 401 | Authorization header or token is invalid |
| `ANALYTICS_LOGIN_PASSWORD_INVALID` | analytics | 401 | Analytics dashboard password is invalid |
| `ANALYTICS_AUTH_HEADER_MISSING` | analytics | 401 | Authorization header is missing when reading analytics data |
| `ANALYTICS_AUTH_SCHEME_INVALID` | analytics | 401 | Authorization scheme is invalid; Bearer token required |
| `ANALYTICS_AUTH_TOKEN_MISSING` | analytics | 401 | Bearer token is missing |
| `ANALYTICS_TOKEN_MALFORMED` | analytics | 401 | Analytics token format is malformed |
| `ANALYTICS_TOKEN_SIGNATURE_INVALID` | analytics | 401 | Analytics token signature verification failed |
| `ANALYTICS_TOKEN_PAYLOAD_INVALID` | analytics | 401 | Analytics token payload cannot be parsed |
| `ANALYTICS_TOKEN_EXPIRED` | analytics | 401 | Analytics token is expired |
| `ANALYTICS_DATE_FORMAT_INVALID` | analytics | 400 | Analytics date must use YYYY-MM-DD format |
| `ANALYTICS_FILE_NOT_FOUND` | analytics | 404 | Analytics day file does not exist |
| `JWT_VERIFIER_NOT_CONFIGURED` | auth | 503 | JWT verifier configuration is missing |
| `AUTOMATION_JOB_LIMIT_EXCEEDED` | automation_jobs | 400 | User-created automation jobs exceed allowed limit |
| `AUTOMATION_SYSTEM_JOB_MODIFICATION_FORBIDDEN` | automation_jobs | 403 | System bootstrap job cannot be modified |
@@ -150,29 +160,13 @@ When creating/modifying/deprecating any code, this table must be updated in the
| `FRIENDSHIP_NOT_FOUND` | friendships | 404 | Friendship record not found |
| `FRIENDSHIP_REMOVE_REQUIRES_ACCEPTED` | friendships | 400 | Only accepted friendships can be removed |
## Registry Coverage Check Script
## Registry Coverage Check
Use the checker script to ensure this registry and frontend code mapping stay aligned:
当前仓库未内置自动校验脚本,维护流程按以下约束执行:
```bash
python3 scripts/check_error_code_registry.py
```
Optional arguments:
- `--doc`: custom registry markdown path
- `--mapper`: custom frontend mapper path (default: `apps/lib/core/network/error_code_mapper.dart`)
Output always includes three result groups:
- doc has code but frontend has no mapping
- frontend maps code but doc has no such code
- duplicate codes
Exit code policy:
- `0`: no inconsistency found
- non-`0`: at least one inconsistency found or input path invalid
- 更新本文件错误码时,同步检查前端映射文件:`apps/lib/data/network/error_code_mapper.dart`
- 任何新增/变更/废弃错误码必须在同一 PR 中完成「协议文档 + 前端映射 + 后端返回码」三方对齐
- 若后续补充自动校验脚本,需在本节追加命令与输出约定
## Agent Error Code Set
+1
View File
@@ -11,6 +11,7 @@ scheduler computation, and Flutter settings pages.
- `owner_id`: UUID
- `title`: string
- `bootstrap_key`: string | null (引导配置键,用于标识预设任务模板)
- `is_system`: boolean (`bootstrap_key != null` 时为 `true`,只读派生字段)
- `config`: object
- `input_template`: string
- `enabled_tools`: string[]
+1 -2
View File
@@ -60,7 +60,7 @@ Base URL: `/api/v1/inbox/messages`
"phone": "string | null"
},
"summary": "string",
"permission": "int (1=view, 4=edit, 8=invite)",
"permission": "int (1=view, 2=invite, 4=edit, 8=delete, 15=owner)",
"action": "pending"
}
```
@@ -141,7 +141,6 @@ Base URL: `/api/v1/inbox/messages`
"message_type": "InboxMessageType",
"schedule_item_id": "uuid | null",
"friendship_id": "uuid | null",
"group_id": "uuid | null",
"content": "CalendarInviteContent | CalendarUpdateContent | CalendarDeleteContent | FriendshipContent | null",
"is_read": "boolean",
"status": "InboxMessageStatus",
+30
View File
@@ -4,6 +4,18 @@
Defines the backend/frontend data contract for `/api/v1/todos`.
## Endpoints
| Method | Path | Description |
|---|---|---|
| POST | `/api/v1/todos` | Create todo |
| GET | `/api/v1/todos` | List todos (supports status/priority filter) |
| GET | `/api/v1/todos/{todo_id}` | Get todo detail |
| PATCH | `/api/v1/todos/reorder` | Batch reorder todos |
| PATCH | `/api/v1/todos/{todo_id}` | Update todo |
| POST | `/api/v1/todos/{todo_id}/complete` | Mark todo completed |
| DELETE | `/api/v1/todos/{todo_id}` | Delete todo |
## Field Definitions
- `id`: string (UUID)
@@ -31,6 +43,24 @@ Defines the backend/frontend data contract for `/api/v1/todos`.
- optional: `title`, `description`, `priority`, `order`, `status`, `schedule_item_ids`
- `order` is interpreted inside the todo's final `priority` quadrant.
### List Todos (`GET /api/v1/todos`)
- query `status`: `pending | done | canceled` (optional)
- query `priority`: integer in `[1, 4]` (optional)
### Reorder Todos (`PATCH /api/v1/todos/reorder`)
- body: `{ items: Array<{ id, priority, order }> }`
- each item requires:
- `id`: UUID
- `priority`: integer in `[1, 4]`
- `order`: integer `>= 0`
### Complete Todo (`POST /api/v1/todos/{todo_id}/complete`)
- body: `{}`
- effect: sets todo status to `done` and updates `completed_at`
## Ordering Rules
- Todo list API returns items sorted by `priority ASC`, then `order ASC`.
+26 -1
View File
@@ -12,6 +12,7 @@ Base URL: `/api/v1/users`
|---|---|---|
| GET | `/me` | 获取当前用户信息 |
| PATCH | `/me` | 更新当前用户信息 |
| POST | `/me/avatar` | 上传头像图片并更新头像地址 |
| POST | `/search` | 搜索用户 |
| GET | `/{user_id}` | 获取指定用户信息 |
@@ -106,7 +107,31 @@ Base URL: `/api/v1/users`
---
## 4) GET `/{user_id}`
## 4) POST `/me/avatar`
上传头像(`multipart/form-data`)。
### Request
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `file` | file | 是 | 图片文件(`image/jpeg` / `image/png` / `image/webp` |
### Response
```json
{
"url": "https://..."
}
```
说明:
- 上传成功后后端会同步更新当前用户 `avatar_url`
- 文件大小上限由后端配置 `storage.avatar.max_size_mb` 控制。
---
## 5) GET `/{user_id}`
获取指定用户信息。