Files
group_xinghuo_jinrong/docs/superpowers/specs/2026-09-12-agent-frontend-e2e-design.md
T
zhanghongyu_0626 2296a4a002 feat(api): Add convert_meta_api for retrieving latest NAV date and enhance created_at field handling
- Introduced `convert_meta_api` endpoint to fetch the latest NAV date for conversion processes, restricted to users with the "risk_officer" role.
- Updated `created_at` field in `AgentMessage` to use UTC timezone for consistency in timestamp handling.
- Added `get_max_product_nav_date` method in `CoreReadOnlyRepository` to support the new API functionality.
- Enhanced Milvus template loading in `MilvusTemplateVectorStore` to ensure collections are loaded when they exist.

This update improves the API's capability to handle conversion metadata and ensures accurate timestamp management across the application.
2026-09-13 12:40:44 +08:00

98 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 顾问前端 + 风控转换线 + 风控前端 端到端验收 · 设计
- **日期**:2026-09-12
- **分支**:`merger` @ `c09b987`
- **性质**:**验证轮**。不改任何业务代码,产出可复现的通过矩阵与缺陷清单。
- **报告**:`docs/memory/tests/2026-09-12-agent-frontend-e2e/TEST-LOG-2026-09-12-FE-001.md`
- **计划**:`docs/superpowers/plans/2026-09-12-agent-frontend-e2e.md`
## 1. 为什么要做这一轮
前三件事各自独立地把「上一轮的结论」推翻了:
| # | 事实 | 后果 |
| --- | --- | --- |
| 1 | 顾问前端四页(合规 / 话术模板 / KYC / 市场异动)已就绪,但**从未在真实浏览器里点过** | 前两轮都是 API-only,页面渲染、交互、默认值完全没覆盖 |
| 2 | `03fce88` 把「基金转换 T+1」整条线并入 `merger`(110 文件,仅后端),`c09b987` 补上前端页 + 迁移 | 新功能**从未做过端到端**,前后端契约未对账 |
| 3 | 第一轮顾问报告写于 `03fce88` **之前**,结论「D1/D2 未修 ⇒ 不建议合入」在当前 HEAD 上已不成立 | 旧报告失真,必须重跑改写 |
## 2. 范围
**做**
- **A · 顾问前端**:`/app/advisor/{home,compliance,templates,kyc,market-alerts}` 逐页点按
- **B · 风控转换线**:`POST /api/simulate/trade`(convert) · `GET /api/simulate/trade/convert/{id}` · `.../cancel` · `POST /api/admin/convert/confirm`,外加风控四端点 RBAC
- **C · 风控前端**:`/app/risk/{home,alerts,suitability,aml-scan,simulate,convert}` 逐页点按
**不做(明示)**
- 两个 SSE 对话页(`/app/advisor/chat`、`/app/risk/chat`)—— 依赖实时 LLM,不确定性强,标 SKIP 并写理由
- `app/service/agent_tools.py` / `agent_graph.py` —— 经 `agent_graph.py:158` 引用但**无任何 HTTP 路由可达**,产生 0 个用例;只记录已知签名错配(D4)
- 性能 / 响应式 / 可访问性专项
- 既有 `test_sprint*` 红项(属 fixture 基建,另一条线)
## 3. 方法:两条独立跑道
```
Part A / C · 浏览器跑道 Part B · API 跑道
────────────────────────── ──────────────────────
Chromium (channel:'chrome') httpx.Client
↓ http://localhost:5173 ↓ http://127.0.0.1:8000
Vite dev server (proxy /api) uvicorn app.main:app
↓ ↓
└─────── 同一套 MySQL + Redis + Milvus + DeepSeek ───────┘
```
**浏览器跑道必须走 Vite(5173)**,不能直连 8000:`app/` 没有 CORS 中间件;且前端 `sha256Hex` 走 WebCrypto,需要安全上下文。
两条跑道**同因同果**才叫验证成立 —— 若浏览器侧失败而 API 侧同名用例通过,说明前端调用与文档契约有分歧,须单独成条。
### 3.1 关键设计决策
| 决策 | 理由 |
| --- | --- |
| **先跑 Part B,再跑 Part C** | Part C 的转换页需要 B 造出的 `convert_request` / `risk_alert` 数据;反过来会空跑 |
| **断言后端与断言渲染必须拆成两条用例** | 例:模拟交易的 `alert_ids`,后端**正确**返回而页面**渲染错误**。合成一条会把渲染缺陷误记成接口缺陷(本轮 B5.1/B5.2 即此拆分) |
| **用轮询等真实行,不用固定 `waitForTimeout` 冒充空表判定** | 固定等待会把「还没加载出来」误判成「确实是空表」 |
| **切角色前清 `localStorage`** | 不清则 `#/login` 会重定向回上个角色首页,后续用例全跑在错误身份上 |
| **登录用例带一次「去掉 reload 兜底」的回归** | `reload` 会掩盖登录崩溃回归(BUG-1);不能默认带着跑 |
| **已确认正确的行为要写成正反对照** | 例:复制门闸拒绝 BLOCK 内容**是门闸生效,不是缺陷**;只写负例容易把正确行为记成 FAIL |
### 3.2 环境前置自检(防假失败)
本轮开工时**曾抓到 merge 前的旧 uvicorn 进程**(PID 27348 启动于 16:55:24,早于代码落地 17:52–17:59)。若未重启,全部转换用例会**假失败**。
因此跑测前必须:`/openapi.json` 含 `/api/admin/convert/confirm` 等转换路径;`/health` 返回 `{"status":"ok"}`。
## 4. 契约口径(本轮实测固化,易误判)
| 场景 | 正确期望 | 常见误判 |
| --- | --- | --- |
| 合法 convert 受理 | **HTTP 202** + `convert_group_id` + `status='accepted'` | 误期 200 |
| 幂等重放 | **也是 202**,同 `convert_group_id`,`idempotent=true`(首跑 `false`) | 误期 409 |
| 适当性阻断 | **200 + `blocked=true`** | 误期 202 |
| 未确认单的字段 | **不得含** `out_nav` / `convert_amount` / `in_qty` / `nav_date` | —— |
| `accept_date` 格式非法 | **422** `REQUEST_VALIDATION_FAILED`(FastAPI 查询校验,pre-handler) | 误期 400 |
| 撤单顺序 | **必须在 `confirm_batch` 之前** —— 确认把单推进 `nav_pending`,而 `nav_pending` 不可撤(409 `CANCEL_NOT_ALLOWED`) | 先确认再撤 |
| `POST /api/simulate/trade` 响应 | **裸 body**,**不套** `{code,message,data,trace_id}` 外壳;前端需 `j?.data ?? j` | 按统一外壳取 `data` |
| `X-Agent-Type` | JWT 通道下 `/api/chat*` 与 `/api/risk/*` **必填**;缺失 401 / 域外值 400 / 跨域 403 | —— |
| 基金转换业务约束 | **同销售机构 + 同管理人 + 同 TA**;违约 400 `CROSS_ENTITY_NOT_SUPPORTED` | —— |
## 5. 交付物
| 产物 | 位置 |
| --- | --- |
| 主报告(12 节模板) | `docs/memory/tests/2026-09-12-agent-frontend-e2e/TEST-LOG-2026-09-12-FE-001.md` |
| 包索引 | 同目录 `README.md` |
| 机器可读矩阵 | 同目录 `_raw/{advisor-api,risk-api}.md` |
| 风控 API 冒烟(64 用例) | `scripts/dev/risk_e2e_smoke.py`(仓库内) |
| 顾问 API 冒烟(63 用例) | `scripts/dev/advisor_e2e_smoke.py`(复用不改) |
| 浏览器 E2E(47 用例) | `C:/Users/Windows/e2e-jinrong/{09,10,11}-*.mjs`(**仓库外**) |
| 顾问报告 v1.1 | `docs/memory/tests/2026-09-12-advisor-agent-e2e/TEST-LOG-2026-09-12-ADV-001.md` |
## 6. 已知取舍
- **浏览器脚本在仓库外** —— 为不改 `web/package.json` 而刻意如此。代价:他人 clone 拿不到这三支脚本,复现性有缺口。已挂 `docs/memory/TODO.md` 的「E2E 最小集进仓库」P0。
- **测试写脏开发库** —— 每轮新增 `core_trade` / `convert_request` / `risk_alert` / `audit_log` 行,默认保留取证数据。转换用例会占用 `CUST-9527` 的 `PROD-110022` 可用份额,重跑前若耗尽需重灌。
- **不执行任何 DROP 重建** —— 不跑 `prepare_all.ps1` / `reset.ps1`,避免误删双库。