Commit Graph
3 Commits
Author SHA1 Message Date
lzf_0626 2c5fe9cdef 把风控扫描演示数据接进一键准备(第 12 步),并让编排支持给步骤传参
## 改动(`tools/seed_demo_data.py`)

1. **`STEPS` 增加第四个字段「额外命令行参数」**。这不是可有可无的装饰:
   `seed_risk_demo_data.py` **不带参数时只打印计划、不连数据库**(默认是干跑模式),
   不给它传 `--apply` 的话,接进编排只会打印一句"确认无误后使用 --apply 正式写入"
   然后退出码 0 —— **看起来像成功,实际什么都没准备**。这类"假成功"最难查,
   所以参数必须能传得进去。
2. **新增第 12 步「风控扫描演示数据」**,带 `--apply --dry-run-scan`:先写入上游
   业务数据,再跑一次规则干跑并把结果回滚。净效果是「写入上游数据 + 顺带验证
   5 个场景都真的命中预期规则」。
3. `run_step` / `--list` / 主循环相应支持第四项;执行时把参数**打印出来**,
   这样手跑时一眼能看出这一步到底会不会落库。

## 为什么放第 12 步,而不是插在「风控预警样本」旁边

避免**改动后续步骤的编号**。文档与肌肉记忆里已经有 `--only 4,10`、`--from 4`
这类用法,插队会让它们全部错位。而且它本身是独立号段(客户 12001-12005、
产品 159991-159995),放最后不影响任何既有步骤。

## 第 6 步与第 12 步不是重复(docstring 已写明)

- 第 6 步 `seed_risk_alert_demo_data.py`:**直接摆好**三条现成预警,
  保证风控页面一打开就有东西可看;
- 第 12 步 `seed_risk_demo_data.py`:**只造上游**,刻意不写 `fin_risk_alert`,
  让风控扫描器按规则生成 —— 演示覆盖的是**规则 → 证据 → 通知**完整链路,
  而不是"预先摆好的假预警"。

## 实测

- `--list` -> **12 步**,第 12 步末尾显示 `[--apply --dry-run-scan]`
- `--only 12 --dry-run` -> 只打印、不执行(并且打印出了参数)
- `--only 12` -> **真跑通**,退出码 0:

      [12/12] 风控扫描演示数据  用时 3.8s  退出码 0
      [命中] 客户 12001:RW-003 (高)
      [命中] 客户 12002:RW-007 (高)
      [命中] 客户 12003:RW-007 (中)
      [命中] 客户 12004:RW-012 (高)
      [命中] 客户 12005:RW-015、RW-018 (低)

- `ruff check tools/seed_demo_data.py` -> All checks passed
2026-09-14 20:50:55 +08:00
lzf_0626 7208713c17 feat(portal): 接入历史净值,产品详情页恢复真实走势图
`fin_nav_history` 一直是**空表**,所以产品详情页画不出走势图 —— 此前那条曲线是
前端 `mock-data.js` 里编的 12 个点位,接入公开产品接口时把它去掉了
(走势图最容易被当成真实业绩),页面改为显示"尚未接入"。本次补上完整链路。

## 1. 取数(app/infrastructure/fund_market_adapter.py)

新增 `fetch_nav_history()`:东方财富历史净值接口(`api.fund.eastmoney.com/f10/lsjz`)
分页取序列。

- **为什么不复用 `fetch_kline`**:它走 `push2his.eastmoney.com`,
  该域名在本环境实测连接被拒(`RemoteProtocolError`);
- **为什么不复用 `hq.get_southern_fund_nav_history`**:那个函数校验**南方基金白名单**,
  而 `fin_product` 里有非南方基金的产品(510300 是华泰柏瑞的),调它会直接 `ValueError`。

⚠️ 实现里踩到一个坑:接口**会忽略请求中的 `pageSize`**(实测固定每次返回 20 条)。
最初按硬编码的 30 判断"是否最后一页",于是 `len(items) < 30` 永远成立、只取到第一页 ——
走势图看上去"有数据",其实只有最近 20 天,而且毫无报错。
改为按首屏**实际条数** + `TotalCount` 推算页数后,同样区间取到 124 条。

## 2. 落库(tools/sync_nav_history.py,新增)

写入 `fin_nav_history`,按 `(product_id, nav_date)` 幂等 upsert。
实测:20 只产品 / **2513 行** / 2026-03-17 ~ 09-13;重跑**新写入 0 行**。

## 3. 接口(P002)

`GET /api/v1/products/{product_code}/nav-history`,编号 **P002**,已登记 `docs/05` §19。
鉴权口径与 P001 相同(要求有效令牌、不校验权限码,访客令牌可用);`days` 有界 1–365。

**表为空时返回 `count=0` 与空数组,而不是报错** —— 调用方据此显示"尚未接入",
**不得回退到编造曲线**。产品不存在或未上市 → `404`(否则前端分不清"没有数据"
和"没有这只产品")。

## 4. 前端

详情页按序列画 SVG 折线,期数标题改为动态("近 N 个交易日")。
表为空时仍显示"尚未接入"占位,并补上此前缺失的 `.detail-chart__empty` 样式。
`product-detail.js` / `.css` / `index.html` 的缓存版本参数一并 bump 到 `-7`。

## 5. 演示数据

`tools/seed_demo_data.py` 增加第 5 步「历史净值」(现 **11 步**),
否则换台机器演示时走势图又会是空的。

验证:P002 实测 515450 / 510300 各 120 个净值点;ruff 通过;mypy 251 文件 0 错;
unit+contract 1391 passed;integration 108 passed;e2e 冒烟 40/40。
2026-09-13 23:38:13 +08:00
lzf_0626 bfd3964ef8 feat(demo): 演示数据一键准备、启动脚本与演示流程文档
交付"别人能自己把系统跑起来做演示"所需的四件东西:

- tools/seed_demo_data.py      演示数据一键准备:10 步按依赖排序
  (此前散在 10 个脚本里,没人知道该跑哪些、按什么顺序跑,且知识库那步
  根本没有脚本、靠手工调接口)
- tools/seed_knowledge_demo.py 知识库演示素材灌入,幂等(先删同 source_file 再灌)
- start.ps1                    启动 API + Worker,含依赖检查与**自动刷新行情**
- docs/44-演示流程.md           8 个主线场景的照读流程 + 排障表 + 账号/命令速查

两条硬约束同时写进了脚本和文档:

1. **Worker 必须常驻**:没有它客服对话一直停在 queued(前端只显示"超时")、
   新知识不进 Milvus 且**没有任何报错**。
2. **行情有效期仅 15 分钟**(`trade_service.MAX_QUOTE_AGE`):超时后所有委托
   直接 503「行情已过期」,而系统**没有自动刷新机制**。故 start.ps1 启动时刷一次,
   文档另给"演示中途 503 时补刷、无需重启服务"的处置方法(已实测)。

实测证据:
- start.ps1 在 8099 完整启动,`/docs` 与 `/portal/` 均 HTTP 200(测试进程已清理)
- `tools/e2e_smoke_test.py` → 40/40 通过
- `tools/seed_demo_data.py --dry-run` → 10 步全部正常列出
- 文档中的下单命令实跑:510300 成交价 4.579、金额 457.90、手续费 0.05
2026-09-13 21:56:27 +08:00