合并主项目最新改动并解决风控前端冲突
This commit is contained in:
@@ -1162,6 +1162,7 @@ GET /internal/metrics
|
||||
| T007 | `GET /api/v1/users/me/transactions` | `trade:txn:read`(已登录) | 否 | `200` | 成交记录列表 |
|
||||
| T008 | `GET /api/v1/users/me/transactions/{txn_no}` | `trade:txn:read`(资源所有者) | 否 | `200` | 成交详情 |
|
||||
| T009 | `GET /api/v1/users/me/cash-ledger` | `account:read:self`(已登录) | 否 | `200` | 资金账本(按 id 倒序游标分页) |
|
||||
| P001 | `GET /api/v1/products` | 仅要求有效令牌(访客令牌即可,不校验权限码) | 否 | `200` | 否 |
|
||||
|
||||
> **T001 – T009 的四点说明**:
|
||||
>
|
||||
@@ -1190,6 +1191,28 @@ GET /internal/metrics
|
||||
|
||||
业务域接口 `/customer-service/handover-tickets/**`、`/advisory-plans/**`、`/sim-orders/**`、`/risk-scans/**` 和 `/risk-alerts/**` 的具体方法、请求体、领域状态机和错误码分别由对应业务文档登记;它们仍必须遵守本文第 3-5、11 和 12 节。
|
||||
|
||||
> **P001(公开产品列表)的四点说明**:
|
||||
>
|
||||
> - **鉴权口径:要求令牌但不校验权限码。** 访客令牌的角色是 `visitor`、**不带任何权限**
|
||||
> (见 §4.2 与 `app/core/security.py`),因此这里不能用权限码把关,否则访客永远 401。
|
||||
> 这与 `/api/v1/agent-runs`、`/api/v1/conversations` 面向访客的做法一致 ——
|
||||
> 产品信息本身是公开信息,要求令牌只为复用统一入口、限流与追踪,不是为了授权。
|
||||
> 数据面只暴露 `fin_product`(`status='上市'`)与 `fin_market_price` 的最新一行,
|
||||
> **不含任何账户、持仓或客户字段**。
|
||||
> - **载荷**:`data.products[]` + `data.count`。产品字段与 `fin_product` 同名
|
||||
> (`product_code`/`product_name`/`exchange_code`/`product_category`/`risk_level`/
|
||||
> `fund_manager`/`current_nav`/`current_nav_at`/`lot_size`/`price_tick`/`min_amount`/
|
||||
> `management_fee_rate`/`custodian_fee_rate`/`status`),
|
||||
> 另加 `latest_close`/`latest_trade_date`/`quote_source`(来自 `fin_market_price`)
|
||||
> 与 `change_pct`。金额与费率一律为**字符串**(与既有接口口径一致)。
|
||||
> - **`change_pct` 可能为 `null`,调用方必须显示"暂无"而不得当成 `0`。**
|
||||
> 当日涨跌幅需要**两个交易日**的收盘价,而行情可能只同步过一天。
|
||||
> 把 `null` 读成 `0` 等于对客户说"今天平盘",那是编出来的结论。
|
||||
> - **首版不提供历史净值/走势曲线**:`fin_nav_history` 目前为空,走势图数据源尚未接入。
|
||||
> 首页推荐位、产品列表页、产品详情页共用本端点;此前它们读的是前端手写的
|
||||
> `app/static/portal/common/mock-data.js`(8 只演示数据,其中 6 只不在
|
||||
> `fin_product` 里),该文件已随本次接入删除。
|
||||
|
||||
## 20. 变更流程
|
||||
|
||||
任何新增或修改接口必须同时更新:
|
||||
|
||||
+19
-11
@@ -67,9 +67,10 @@ python -m app.worker
|
||||
| **投顾** | `employee-advisor/dashboard/`(2449 B) | ✅ 本轮新增 |
|
||||
| **运营** | `employee-operations/dashboard/`(1968 B) | ✅ 本轮新增 |
|
||||
|
||||
**12 个关键静态资源全部 200**:`api-client.js` / `auth.js` / `login-controller.js` / `permission-guard.js` /
|
||||
`layout/app-shell.js` / `mock-data.js` / `customer-service-widget/widget.js` / `widget.css` /
|
||||
**13 个关键静态资源全部 200**:`api-client.js` / `auth.js` / `login-controller.js` / `permission-guard.js` /
|
||||
`layout/app-shell.js` / `visitor-token.js` / `product-notes.js` / `customer-service-widget/widget.js` / `widget.css` /
|
||||
`base.css` / `tokens.css` / `operations.css` / `auth-layout.css` ✅
|
||||
(`common/mock-data.js` 已于 2026-09-13 随公开产品接口接入**删除**,实测返回 404 ✅)
|
||||
|
||||
---
|
||||
|
||||
@@ -77,13 +78,22 @@ python -m app.worker
|
||||
|
||||
| # | 操作 | 预期 | 证据 |
|
||||
|---|---|---|---|
|
||||
| 2-1 | 打开 `/portal/guest/home/` | 首屏含品牌与产品摘要 | ⚠️待点验 |
|
||||
| 2-2 | **看页面的数据来源提示条** | 产品列表页与详情页顶部都有浅色提示条,写明"公开产品接口尚未提供…演示数据,**非真实行情**" | ✅ 页面 HTML 与三个 JS 资源实测都带 `data-source-notice` / `MOCK_SOURCE_NOTICE`<br>⚠️ 渲染位置待点验 |
|
||||
| 2-3 | 进产品列表 / 详情 | 能筛选、能按排名排序(`?view=ranking`)、详情有净值走势 | ⚠️待点验(数据来自 `common/mock-data.js`,**非真实接口**) |
|
||||
| 2-1 | 打开 `/portal/guest/home/` | 首屏含品牌与产品摘要 | ⚠️待点验(推荐位取接口返回的前 3 只) |
|
||||
| 2-2 | **看页面的数据来源提示条** | 产品列表页与详情页顶部都有浅色提示条,写明数据来自平台产品库与行情源同步结果 | ✅ 三个页面都写 `[data-source-notice]`;接口侧由 `tests/integration/test_public_products_endpoint_mysql.py` 守着<br>⚠️ 渲染位置待点验 |
|
||||
| 2-3 | 进产品列表 / 详情 | 列表显示**产品库全部 20 只**(不再是 8 只);能筛选、能按 `?view=ranking` 排序 | ✅ 接口实测 `count=20`;`?view=ranking` 按 `change_pct` 排序、缺数据的排最后<br>⚠️ 渲染待点验 |
|
||||
| 2-4 | 点登录入口 | 进 `/portal/customer/login/` | ⚠️待点验 |
|
||||
|
||||
> **关于 mock**:访客三页用 `common/mock-data.js`,因为**公开产品 HTTP 接口尚未实现**。
|
||||
> 页面显著标注了来源 —— 这个标注**不能删**:删掉不会让数据变真,只会让客户以为看到的是真实净值。
|
||||
> **公开产品数据已接真实接口**(2026-09-13):`GET /api/v1/products`(编号 **P001**,见 `docs/05` §19),
|
||||
> 产品与净值取自 `fin_product`、行情取自 `fin_market_price`。
|
||||
> 此前三页读的是 `common/mock-data.js` —— 那份数据只有 8 只,且**其中 6 只根本不在产品库里**
|
||||
> (如把海富通的 `511360` 标成"南方短融ETF"),净值也是编的。该文件已删除。
|
||||
>
|
||||
> **两条不能想当然的口径**(改前端前先读):
|
||||
> 1. `change_pct` **可能是 `null`**(行情只同步过一个交易日时算不出涨跌)。
|
||||
> 页面必须显示"暂无"—— `formatPercent` 收到 `null` 会渲染成 `+0.00%`,
|
||||
> 那等于告诉客户"今天平盘"。
|
||||
> 2. **历史净值走势图没有数据源**:`fin_nav_history` 目前 0 行,详情页**不画曲线**并显式说明。
|
||||
> 此前那条曲线是 mock 里 12 个编造点位 —— 走势图最容易被当成真数据。
|
||||
|
||||
### 2.5 访客智能客服浮窗 ⭐ 本轮重点
|
||||
|
||||
@@ -230,10 +240,6 @@ python -m app.worker
|
||||
| 8-5 | 多标签 | 各页面独立。**注意**:`auth.js` 现在以 cookie 为权威(跨标签同步),所以**同一浏览器两个账号不能并存** ✅实测代码逻辑 |
|
||||
| 8-6 | 排版 | 文字不重叠、内容不溢出、表格行高稳定 ⚠️待点验 |
|
||||
| 8-7 | 缓存 | 产品列表/详情页的 CSS/JS 已带 `?v=20260913-4`;若改了资源仍看不到效果,请硬刷新 ⚠️待点验 |
|
||||
| 8-8 | **`GET /api/v1/knowledge/list` 不套 `data` 信封** | 它直接返回 `{"items": [...], "count": N}`,而多数端点返回 `{"code":…, "data": {…}}`。按 `data.items` 解包会得到 0 条、看着像"库里没数据" ✅实测(联调时踩过一次,误判成接口故障) |
|
||||
| 8-9 | 知识治理端点 | 上传是 `POST /api/v1/knowledge/upload`(**不是** `/documents`,用后者会 405);删除是 `DELETE /api/v1/knowledge/{id}`,语义是标记 `expired` + 投向量删除事件,**不是**物理删除 |
|
||||
| 8-10 | **各端点的 `data` 形状不统一**(写联调脚本时别猜) | 实测:账户看板 `data.account` + `data.summary`、持仓 `data.holdings`、成交明细 `data.transactions`、资金流水 **`data.entries`**、角色列表 `data`(裸数组)、知识列表 `items`(**不套 `data`**)。我写全流程脚本时连续猜错三个字段名 ✅实测 |
|
||||
| 8-11 | 创建类接口返回 **201** 而非 200 | 下单 `T002`、创建会话 `C001`、访客令牌 `V001` 都是 201。判"成功"要用 `status in (200,201)` ✅实测 |
|
||||
|
||||
---
|
||||
|
||||
@@ -303,6 +309,8 @@ MIN_GAP = 0.07 # top1 领先次优的最小间隙
|
||||
(保留 `search_knowledge` 给登录客户)。
|
||||
6. **访客页的"演示数据"声明被删掉、但假数据还在渲染** —— 已恢复 `MOCK_SOURCE_NOTICE`、
|
||||
两个页面的提示条与样式,并给 `link`/`script` 加版本参数(此前会被浏览器缓存)。
|
||||
**2026-09-13 已彻底解决**:公开产品接口(P001)落地后 `common/mock-data.js` 整体删除,
|
||||
页面改读真实数据 —— 只要数据是假的就总有人想删那条声明,接口接上才是根治。
|
||||
7. **发布脚本会静默丢提示词** —— `publish_customer_service_config.py` 只继承
|
||||
`platform_config_item`,把 `customer_service_chitchat` 提示词漏在了旧版本里。
|
||||
已改用 `effective_snapshot()` 读全三张受管表、补提示词搬运与条数硬校验;丢失的提示词已按原文恢复。
|
||||
|
||||
+26
-2
@@ -88,11 +88,11 @@
|
||||
| 510500 | 中证500ETF南方 | SSE | ETF | R4 | 7.6027 | -1.79% | 2026-09-11 |
|
||||
| 511070 | 公司债ETF南方 | SSE | ETF | R2 | 103.0145 | +0.01% | 2026-09-11 |
|
||||
| 511810 | 货币ETF南方 | SSE | ETF | R1 | 0.2332 ⚠️ | 0.00% | 2026-09-13 |
|
||||
| 515450 | 红利低波50ETF南方 | SSE | ETF | R3 | 1.4027 | -0.43% | 2026-09-11 |
|
||||
| 588890 | 科创芯片ETF南方 | SSE | ETF | R4 | 1.2327 | -1.36% | 2026-09-11 |
|
||||
| 160105 | 南方积极配置混合(LOF) | SZSE | LOF | R3 | 1.2514 | -1.34% | 2026-09-11 |
|
||||
| 160127 | 南方新兴消费增长股票(LOF)A | SZSE | LOF | R4 | 0.8364 | -0.64% | 2026-09-11 |
|
||||
| 160128 | 南方金利定开债券A | SZSE | LOF | R2 | 1.0260 | 0.00% | 2026-09-11 |
|
||||
| 160129 | 南方金利定开债券C | SZSE | LOF | R2 | 1.0240 | 0.00% | 2026-09-11 |
|
||||
| 160142 | 南方优势产业(LOF) | SZSE | LOF | R3 | 1.0623 | -2.09% | 2026-09-11 |
|
||||
| 160143 | 南方创业板2年定期开放混合 | SZSE | LOF | R3 | 1.6105 | -1.14% | 2026-09-11 |
|
||||
| 501018 | 南方原油A | SSE | LOF | R5 | 2.0750 | +3.86% | 2026-09-10 |
|
||||
@@ -106,6 +106,30 @@
|
||||
> (库里存 6 位小数,如 `0.916700`,数据源给 4 位 `0.9167`,是同一笔数),
|
||||
> **2 只不一致** —— `510300` 与 `511810`,见下方 3.1 与第四节。
|
||||
|
||||
> **2026-09-13 变更:`160129` → `515450`**
|
||||
>
|
||||
> 原 `160129`(南方金利定开债券C)已从清单移除,替换为 **`515450` 红利低波50ETF南方**
|
||||
> (SSE / ETF / R3,管理费 0.50%、托管费 0.10%,净值 1.4027)。
|
||||
>
|
||||
> **为什么必须换**:`160129` 是 `160128`(金利定开债券 **A** 类)的 **C 类份额**,
|
||||
> 而 C 类份额只在场外销售、**不在交易所挂牌** —— 行情源对它永远返回空,下单只能走
|
||||
> 净值降级(`source=eastmoney_nav_fallback`)。这既掩盖了"该产品并不交易"这一事实,
|
||||
> 又让成交价带上折溢价偏差。**它本就不该出现在场内清单里。**
|
||||
>
|
||||
> **选型依据**:把南方基金全部 **882 个代码**逐个问过腾讯行情源(该源只对交易所上市
|
||||
> 证券返回数据),确认真实上市交易的只有 **109 个**;其中 R1/R2 的场内产品
|
||||
> (159700、160128、511070、511810)**原先已在清单内**,所以替换品只能来自 R3 及以上。
|
||||
> 选 `515450` 是因为它**仍属南方基金**、成交额约 1.3 亿元流动性充足、红利低波定位偏
|
||||
> 稳健,与它替换掉的债券 LOF 定位最接近;客户风险等级已覆盖 R3(原有 `510300` 即 R3)。
|
||||
>
|
||||
> **处理方式**:复用 `fin_product.id = 9100005` 而非删除重建,使 `fin_holding` /
|
||||
> `fin_sim_order` / `fin_transaction` / `fin_market_price` 的既有引用自动跟随,
|
||||
> 不产生孤儿数据。那笔历史成交保留 `quote_source='eastmoney_nav_fallback'` ——
|
||||
> 它确实是当时的事实,不该被粉饰。
|
||||
>
|
||||
> 同时移出的还有 `hq.py` 的 `FUND_TYPE_GROUPS`(`160129` 原在"债券型"组)
|
||||
> 与 `tools/import_hq_test_products.py` 的场内映射,两处都留了注释防止被加回来。
|
||||
|
||||
问:平台上有哪些场内基金?产品代码是什么?
|
||||
|
||||
答:本平台模拟交易范围内共有 20 只场内基金,包含 13 只 ETF 和 7 只 LOF,
|
||||
@@ -241,7 +265,6 @@ python tools/backfill_product_snapshot.py --codes 511810 --apply --overwrite
|
||||
| 160105 | 南方积极配置混合(LOF) | 1.20 | 0.20 | — |
|
||||
| 160127 | 南方新兴消费增长股票(LOF)A | 1.20 | 0.20 | — |
|
||||
| 160128 | 南方金利定开债券A | 0.50 | 0.15 | — |
|
||||
| 160129 | 南方金利定开债券C | 0.50 | 0.15 | — |
|
||||
| 160142 | 南方优势产业(LOF) | 1.20 | 0.20 | — |
|
||||
| 160143 | 南方创业板2年定期开放混合 | 1.20 | 0.20 | — |
|
||||
| 501018 | 南方原油A | 1.00 | 0.20 | — |
|
||||
@@ -250,6 +273,7 @@ python tools/backfill_product_snapshot.py --codes 511810 --apply --overwrite
|
||||
| 510500 | 中证500ETF南方 | 0.15 | 0.05 | — |
|
||||
| 511070 | 公司债ETF南方 | 0.15 | 0.05 | — |
|
||||
| 511810 | 货币ETF南方 | 0.30 | 0.05 | **0.25** |
|
||||
| 515450 | 红利低波50ETF南方 | 0.50 | 0.10 | — |
|
||||
| 588890 | 科创芯片ETF南方 | 0.50 | 0.10 | — |
|
||||
|
||||
**规律**:宽基/债券 ETF 多为 0.15% 管理费,行业主题 ETF 多为 0.50%,
|
||||
|
||||
@@ -86,11 +86,11 @@ LOF 与主动管理型较高(如南方积极配置混合 1.20%/年、托管费
|
||||
| 510500 | 中证500ETF南方 | 上交所 | ETF | R4 | 7.6027 | 2026-09-11 |
|
||||
| 511070 | 公司债ETF南方 | 上交所 | ETF | R2 | 103.0145 | 2026-09-11 |
|
||||
| 511810 | 货币ETF南方 | 上交所 | ETF | R1 | 0.2661 | 2026-09-11 |
|
||||
| 515450 | 红利低波50ETF南方 | 上交所 | ETF | R3 | 1.4027 | 2026-09-11 |
|
||||
| 588890 | 科创芯片ETF南方 | 上交所 | ETF | R4 | 1.2327 | 2026-09-11 |
|
||||
| 160105 | 南方积极配置混合(LOF) | 深交所 | LOF | R3 | 1.2514 | 2026-09-11 |
|
||||
| 160127 | 南方新兴消费增长股票(LOF)A | 深交所 | LOF | R4 | 0.8364 | 2026-09-11 |
|
||||
| 160128 | 南方金利定开债券A | 深交所 | LOF | R2 | 1.0260 | 2026-09-11 |
|
||||
| 160129 | 南方金利定开债券C | 深交所 | LOF | R2 | 1.0240 | 2026-09-11 |
|
||||
| 160142 | 南方优势产业(LOF) | 深交所 | LOF | R3 | 1.0623 | 2026-09-11 |
|
||||
| 160143 | 南方创业板2年定期开放混合 | 深交所 | LOF | R3 | 1.6105 | 2026-09-11 |
|
||||
| 501018 | 南方原油A | 上交所 | LOF | R5 | 2.0750 | 2026-09-10 |
|
||||
@@ -139,11 +139,11 @@ LOF 与主动管理型较高(如南方积极配置混合 1.20%/年、托管费
|
||||
| 510500 | 中证500ETF南方 | 0.15 | 0.05 | — |
|
||||
| 511070 | 公司债ETF南方 | 0.15 | 0.05 | — |
|
||||
| 511810 | 货币ETF南方 | 0.30 | 0.05 | 0.25 |
|
||||
| 515450 | 红利低波50ETF南方 | 0.50 | 0.10 | — |
|
||||
| 588890 | 科创芯片ETF南方 | 0.50 | 0.10 | — |
|
||||
| 160105 | 南方积极配置混合(LOF) | 1.20 | 0.20 | — |
|
||||
| 160127 | 南方新兴消费增长股票(LOF)A | 1.20 | 0.20 | — |
|
||||
| 160128 | 南方金利定开债券A | 0.50 | 0.15 | — |
|
||||
| 160129 | 南方金利定开债券C | 0.50 | 0.15 | — |
|
||||
| 160142 | 南方优势产业(LOF) | 1.20 | 0.20 | — |
|
||||
| 160143 | 南方创业板2年定期开放混合 | 1.20 | 0.20 | — |
|
||||
| 501018 | 南方原油A | 1.00 | 0.20 | — |
|
||||
|
||||
+305
@@ -0,0 +1,305 @@
|
||||
# 演示流程(照着走)
|
||||
|
||||
> **读者**:负责演示的人。本文按"操作 → 看到什么 → 这体现什么"三段式写,
|
||||
> 可以直接照着念。
|
||||
> **主线时长**:约 8 分钟;含讲解约 15 分钟。
|
||||
> **全部内容均已实测**(2026-09-13);标 ⚠️ 的地方是容易翻车的点。
|
||||
|
||||
---
|
||||
|
||||
## 0. 演示前准备
|
||||
|
||||
### 0.1 准备演示数据(首次、或换了机器才需要)
|
||||
|
||||
```powershell
|
||||
python tools/seed_demo_data.py
|
||||
```
|
||||
|
||||
10 步:账号权限 → 演示口令 → 客户账户 → **场内行情** → 风控预警样本 → 投顾数据 →
|
||||
三类发布配置 → 知识库素材。脚本会逐步打印完成/失败。
|
||||
|
||||
> ⚠️ 第 2 步**不是幂等的**:重跑等于重设密码(bcrypt 每次加盐不同)。
|
||||
|
||||
### 0.2 一条必须知道的硬规则:**行情有效期只有 15 分钟**
|
||||
|
||||
下单要求行情快照落在 **15 分钟内**(`app/service/trade_service.py` 的 `MAX_QUOTE_AGE`),
|
||||
**系统没有任何自动刷新机制** —— 超时后**所有委托直接返回 `503 行情已过期`**。
|
||||
|
||||
演示时踩过这个坑:明明上午刷过行情,下午演示第一单就 503。
|
||||
|
||||
**怎么办**:`start.ps1` **已经会替你刷新一次**(见 0.3),所以正常不用管。
|
||||
万一演示中途下单报 503 —— 在新窗口跑一次就行,**不用重启任何服务**(已实测):
|
||||
|
||||
```powershell
|
||||
python tools/sync_market_prices.py
|
||||
```
|
||||
|
||||
它按产品 upsert(幂等),几秒内把 20 只产品行情全部刷新,15 分钟窗口重新计时。
|
||||
|
||||
> 不想让启动脚本联网刷行情:`start.ps1 -SkipPriceSync`
|
||||
|
||||
### 0.3 启动平台
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File start.ps1
|
||||
```
|
||||
|
||||
它按顺序做四件事:**找解释器 → 检查 MySQL/Redis/Milvus → 刷新行情 → 起两个窗口**,然后打印访问入口与账号。
|
||||
它会**开两个窗口**:
|
||||
|
||||
| 窗口 | 作用 | 少了它会怎样 |
|
||||
|---|---|---|
|
||||
| API | 所有接口与页面 | 什么都没有 |
|
||||
| **Worker** | Agent 对话、知识向量同步、记忆抽取、风控扫描 | 客服对话一直"超时";新知识不进 Milvus 且**无任何报错** |
|
||||
|
||||
### 0.4 开场前自检(务必做)
|
||||
|
||||
```powershell
|
||||
python tools/e2e_smoke_test.py --read-only
|
||||
```
|
||||
|
||||
看最后一行:**40/40 通过**才开始演示。有 FAIL 就按 §4 排查。
|
||||
|
||||
### 0.5 打开第一个页面
|
||||
|
||||
<http://127.0.0.1:8000/portal/>
|
||||
|
||||
---
|
||||
|
||||
## 1. 主线场景
|
||||
|
||||
### 场景 1 · 访客咨询与知识边界(1.5 min)
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **打开** | <http://127.0.0.1:8000/portal/guest/products/> |
|
||||
| **操作** | 点右下角客服浮窗 → 输入「场内基金的管理费率是多少」→ 发送 |
|
||||
| **预期** | **约 3–4 秒**返回:本平台 20 只场内基金的管理费率 0.15%~1.20%/年,并列出 ETF 与 LOF 的差异 |
|
||||
|
||||
**这体现什么**:客服不是"模型随便聊",而是**检索已发布知识后作答**,答案可追溯;
|
||||
延迟稳定在 3–4 秒(一次意图分类 + 一次向量检索)。
|
||||
|
||||
**接着再问一句(体现安全边界)**:「我的账户里有多少钱?」
|
||||
→ 预期:回复"该服务需要登录后才能查询您的个人信息",**不编造账户数字**。
|
||||
|
||||
> 产品页的数据来自**真实接口**(`GET /api/v1/products`):产品与净值取自 `fin_product`,
|
||||
> 行情由 `tools/sync_market_prices.py` 从行情源同步,页面底部有来源声明。
|
||||
>
|
||||
> ⚠️ 两个**可能被问到、但其实不是故障**的地方:
|
||||
> - 产品列表的「最近涨跌」列当前显示 **"暂无"** —— 当日涨跌要**两个交易日**的收盘价才算得出,
|
||||
> 而行情库目前只有一个交易日。跑过第二次行情同步后自然会显示。我们**不编这个数**。
|
||||
> - 产品详情的**历史净值走势图显示"尚未接入"** —— `fin_nav_history` 目前是空的。
|
||||
> 此前那条曲线是演示数据里编的 12 个点位,已随接口接入一并去掉。
|
||||
|
||||
### 场景 2 · 客户资产(1 min)
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **打开** | <http://127.0.0.1:8000/portal/customer/login/> |
|
||||
| **账号** | `cust_t` / `123456` |
|
||||
| **预期** | 自动进资产总览:总资产约 10 万、可用资金、持仓市值(7 只持仓) |
|
||||
|
||||
**这体现什么**:持仓按**真实行情**计价(不是写死的假数);页面底部有数据来源说明。
|
||||
|
||||
点左侧「我的持仓」「资金流水」「成交明细」各看一眼即可。
|
||||
|
||||
### 场景 3 · 客户下单(1.5 min)⭐ 重点
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **打开** | 客户页 → 交易记录 → 或直接用接口 |
|
||||
| **说明** | 前端下单表单待完善,本场用接口演示更直观(见下) |
|
||||
|
||||
```powershell
|
||||
# 演示用:买入 100 份沪深300ETF
|
||||
$body = '{"product_code":"510300","order_side":"buy","quantity":100}'
|
||||
$r = Invoke-RestMethod -Uri http://127.0.0.1:8000/api/v1/auth/tokens -Method Post `
|
||||
-Body '{"username":"cust_t","password":"123456"}' -ContentType application/json
|
||||
Invoke-RestMethod -Uri http://127.0.0.1:8000/api/v1/users/me/orders -Method Post `
|
||||
-Headers @{ Authorization = "Bearer $($r.data.access_token)"; "Idempotency-Key" = [guid]::NewGuid().ToString("N") } `
|
||||
-Body $body -ContentType application/json | ConvertTo-Json -Depth 4
|
||||
```
|
||||
|
||||
**预期**:`status=已成交`、`executed_price=4.579`(**真实行情价**)、
|
||||
成交金额 457.90、手续费 0.05、实际扣款 457.95(`net_amount`)。
|
||||
|
||||
**这体现什么**:
|
||||
- **成交价来自外部行情**,不是模拟随机数;
|
||||
- 下单前会做**适当性校验**(风险等级匹配),不匹配直接拒绝;
|
||||
- 成交后持仓、资金流水、成交明细**三处同时落账**(可当场刷新场景 2 的页面看变化)。
|
||||
|
||||
> ⚠️ 如果返回 `503 FUND_QUOTE_UNAVAILABLE` → 跑 §0.2 的行情同步。
|
||||
|
||||
### 场景 4 · 客服对话与转人工(1 min)
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **操作** | 客户页右下角浮窗 → 问「基金定投是什么」→ 点「转人工客服」 |
|
||||
| **预期** | 先得到知识库答案;转人工返回 `202`,工单进入管理员队列 |
|
||||
|
||||
**这体现什么**:客户**主动**请求人工与"答不上来"是两条不同路径 —— 前者建工单,
|
||||
后者按既定口径引导拨打客服热线(**不建工单**,符合我们"答不了就转人工、不硬答"的原则)。
|
||||
|
||||
### 场景 5 · 风控预警处置(2 min)⭐ 重点
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **打开** | <http://127.0.0.1:8000/portal/employee-console/login/> → `risk_t` / `666666` |
|
||||
| **预期** | 概览:未闭环预警数、高风险数、待处理、已超时 |
|
||||
|
||||
**操作顺序(这是核心闭环)**:
|
||||
|
||||
1. 点预警队列里的某条 → 打开详情;
|
||||
2. 详情里有**八类证据**入口:客户、产品、交易、资金流水、持仓、登录记录、预警、通知;
|
||||
3. 点「确认接收」→ 状态变为已确认;
|
||||
4. 点「进入调查」→ 状态变为调查中;
|
||||
5. 点「完成结案」→ 状态变为**已结案**,并且**按风险等级扣减客户行为分**。
|
||||
|
||||
**这体现什么**:预警处置是**有状态机、有留痕、有连带影响**的 ——
|
||||
不是改个字段。每一步都记审计(谁、何时、做了什么)。
|
||||
|
||||
> 若队列里没有「待处理」的预警(都已被处置过),跑
|
||||
> `python tools/e2e_smoke_test.py` —— 它会自动造一条待处理预警并跑完整闭环。
|
||||
|
||||
**补一步「风控助手」(30 秒,很值得演)**:点上方「风控助手」标签 → 点预设的
|
||||
「当前风险概览」按钮 → Agent 调 `get_risk_overview` **只读工具**返回未闭环预警概览,
|
||||
结尾并声明"以上仅为查询与复核线索,不构成任何已确认、误报、关闭或升级的处置结论,
|
||||
最终请由风控专员人工复核并留痕"。
|
||||
|
||||
**这体现什么**:Agent 只做**只读查询与研判草案**,处置动作一律留给人工。
|
||||
实测这条问法命中的是 `risk_overview` 意图、置信度 **1.0000** ——
|
||||
是配置好的意图分派,不是让模型自由发挥。
|
||||
|
||||
### 场景 6 · 风控日报(1 min)
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **操作** | 风控工作台 → 日报 → 生成 |
|
||||
| **预期** | 文本**流式**逐段出现(SSE),完成后可填多个邮箱发送 |
|
||||
|
||||
**这体现什么**:长任务走 SSE 流式,而不是让页面转圈等 30 秒。
|
||||
|
||||
### 场景 7 · 投顾工作台(1 min)
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **打开** | <http://127.0.0.1:8000/portal/employee-advisor/dashboard/> |
|
||||
| **账号** | `advisor_t` / `abc12345` |
|
||||
| **预期** | 一张「投资目标方案书 · 客户 9001」卡片,含发布时间与方案内容 |
|
||||
|
||||
**这体现什么**:投顾看到的是**自己服务的客户**的已发布交付物。
|
||||
数据范围按 `sys_customer_assignment` 归属关系判定(不是按 `data_scope` ——
|
||||
那会把 all 级权限放大成"看全部客户")。
|
||||
|
||||
> 方案书的**审核与发布都要求管理员**(`admin=True`),投顾自己发不出来。
|
||||
> 这是有意的复核环节,不是缺陷。
|
||||
|
||||
### 场景 8 · 管理员治理(1.5 min)
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **打开** | <http://127.0.0.1:8000/portal/employee-console/workspace/> |
|
||||
| **账号** | `admin_t` / `88888888` |
|
||||
| **预期** | 四个指标卡 + 六个标签页 |
|
||||
|
||||
**挨个点一遍,每处一句话**:
|
||||
|
||||
| 标签页 | 讲解要点 |
|
||||
|---|---|
|
||||
| 角色权限 | 五个角色,权限数分别是 admin 59 / advisor 28 / customer 26 / risk_operator 10 / operator 2 |
|
||||
| 配置发布 | 工具白名单、提示词**走发布状态机**(校验→审核→激活),不是改配置文件 |
|
||||
| 审计 | 每一次权限判定、工具调用都有记录 |
|
||||
| 转人工工单 | 场景 4 建的工单在这里;**不返回客户标识与原始对话**(脱敏) |
|
||||
| 模型端点 | 当前用 `deepseek-flash`(意图分类)+ `qwen` 向量(embedding) |
|
||||
|
||||
**这体现什么**:**权限变更必须过审核流程并留痕** —— 这是金融场景的硬要求,
|
||||
所以平台刻意**不提供**"直接改权限"的接口。
|
||||
|
||||
---
|
||||
|
||||
## 2. 备选场景(时间充足时)
|
||||
|
||||
| 场景 | 怎么演 | 体现什么 |
|
||||
|---|---|---|
|
||||
| 配置发布四态 | 管理员工作台建一个草稿版本 → 提交校验 → 审核 → 激活 | 改配置是走流程的,可回滚 |
|
||||
| 五角色权限对比 | 用五个账号分别登录,看入口守卫各跳哪里 | 越权在**前端就被挡**,服务端还有一层 |
|
||||
| 知识入库 | `python tools/seed_knowledge_demo.py` 后复测场景 1 | 知识是**可运营**的,不是写死的 |
|
||||
| 平台体检 | `python tools/e2e_smoke_test.py` | 40 项全绿,交付质量可自证 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 可能被问到的问题(建议话术)
|
||||
|
||||
**Q:这是真实行情吗?**
|
||||
A:行情取自公开数据源(腾讯行情),成交价用的就是它。但**交易本身是模拟的** ——
|
||||
平台是"场内基金模拟交易",不下真实单。
|
||||
|
||||
**Q:Agent 会不会乱答?**
|
||||
A:不会。客服只回答**检索到的已发布知识**,且有置信度门槛:
|
||||
命中分数 ≥0.75 直接答;0.55~0.75 之间还要求领先次优 ≥0.07;
|
||||
不满足就引导人工。**宁可转人工也不答错** —— 这是刻意的取舍。
|
||||
|
||||
**Q:为什么有些问题答不上来?**
|
||||
A:知识库是人工审核入库的,目前覆盖交易规则、20 只产品、费率与常见问答。
|
||||
问不到的地方会转人工,**这是设计而不是故障**。
|
||||
|
||||
**Q:数据安全怎么保证?**
|
||||
A:三层 —— 前端按权限隐藏入口;服务端每次请求**重新解析权限与数据范围**(令牌里不带权限);
|
||||
工单等管理面接口**不返回客户标识与原始对话**。所有判定都有审计。
|
||||
|
||||
**Q:为什么不让管理员直接改权限?**
|
||||
A:金融场景要求权限变更留痕可追溯,所以统一走配置发布流程(草稿→校验→审核→激活)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 出问题怎么办
|
||||
|
||||
| 现象 | 原因 | 怎么办 |
|
||||
|---|---|---|
|
||||
| 客户下单返回 `503 行情已过期` | 行情快照过期(**有效期仅 15 分钟**) | `python tools/sync_market_prices.py` —— **立即生效,无需重启服务** |
|
||||
| 客服一直"繁忙/超时" | **Worker 没在跑** | 看 `start.ps1` 起的第二个窗口;或 `python -m app.worker` |
|
||||
| 改了页面看不到效果 | 浏览器缓存 | `Ctrl+F5` 硬刷新 |
|
||||
| 知识库问答答不上 | 向量没同步 | 确认 Worker 在跑,然后跑 `tools/seed_knowledge_demo.py` |
|
||||
| 平台起不来 | MySQL 没起 | 看 `start.ps1` 的依赖检查输出 |
|
||||
| 风控队列没有"待处理"预警 | 演示样本都被处置过了 | `python tools/e2e_smoke_test.py`(自动造一条) |
|
||||
|
||||
**一条命令定位**:
|
||||
|
||||
```powershell
|
||||
python tools/e2e_smoke_test.py
|
||||
```
|
||||
|
||||
它逐条打印 6 条线 40 项的结果,FAIL 的那条就是问题所在。
|
||||
|
||||
---
|
||||
|
||||
## 5. 速查
|
||||
|
||||
**账号**
|
||||
|
||||
| 角色 | 用户名 | 密码 | 登录入口 |
|
||||
|---|---|---|---|
|
||||
| 客户 | `cust_t` | `123456` | `/portal/customer/login/` |
|
||||
| 风控专员 | `risk_t` | `666666` | `/portal/employee-console/login/` |
|
||||
| 管理员 | `admin_t` | `88888888` | 同上 |
|
||||
| 投顾 | `advisor_t` | `abc12345` | 同上(→ 投顾工作台) |
|
||||
| 运营 | `offsite_t` | `offsite123` | 同上(→ 运营工作台) |
|
||||
|
||||
**常用命令**
|
||||
|
||||
```powershell
|
||||
python tools/seed_demo_data.py # 准备演示数据(10 步,首次/换机器)
|
||||
python tools/sync_market_prices.py # 刷行情(15 分钟有效期,下单 503 时补跑)
|
||||
powershell -ExecutionPolicy Bypass -File start.ps1 # 起 API + Worker(自动刷行情)
|
||||
python tools/e2e_smoke_test.py # 全量体检(40 项)
|
||||
python tools/e2e_smoke_test.py --read-only # 只读体检,不动数据
|
||||
```
|
||||
|
||||
**已知的空数据**(演示时别点进去尴尬)
|
||||
|
||||
| 位置 | 现状 |
|
||||
|---|---|
|
||||
| 运营工作台 | 场外邮件 0 条、邮箱未初始化(需要真实邮件源) |
|
||||
| 管理员 · 画像候选 | 0 条(需要客户对话触发画像抽取) |
|
||||
|
||||
**端口**:API `8000` / MySQL `3306` / Redis `6379` / Milvus `19530`
|
||||
Reference in New Issue
Block a user