把当前状态整理成可交接的一份:分支与门禁、三条线合进来的内容、平台侧补齐的登录与 RBAC 只读接口、修掉的真缺陷、演示账号与环境口径、新增工具索引、联调清单、悬置决策项。 其中三条是这一轮实际踩出来的,值得留档: 1. 环境数据不随代码合并(config_release / sys_role / sys_permission / Milvus schema / advisor_product_*)—— 三条组员线各自都在这上面栽过一次; 2. 合并后必须**单独**跑 alembic upgrade head 与 tools/check_authoritative_docs.py: 三家合并里两次带进文档重号、两次库与代码版本不一致(一次"版本号跑了表没建"、 一次"表没建版本号也没跑"),两者都靠 upgrade 收敛,重号只有守卫能发现; 3. 投顾演示数据里"方案"那步配不出来,缺的是**证据来源**(source_url / document_sha256), 必须来自真实的销售适当性披露或基金合同文件;不伪造这两个字段是关键红线。 另记下环境口径:mypy 与测试数必须带环境读,NL 那边 184 错与本机 0 错的差异根因是 对方的 .venv 没满足 pyproject 的 sqlalchemy>=2.0,<3 / mypy>=1.14,<2,不是代码质量问题。 文档守卫:41 份无编号冲突。
9.7 KiB
平台侧交接与联调准备
读者:接手平台侧的人,以及联调前要确认状态的人 时点:2026-09-11 一句话:三条组员线(袁聪的场外/推广、NL 的客服画像与知识管理、投顾)已并入
qyqy_develop,库已跟上(89 张业务表),登录与 RBAC 只读接口已补齐; 等组员继续推送后按本文 §5 的清单联调。
1. 当前状态(2026-09-11 实测)
| 项 | 值 |
|---|---|
| 分支 | qyqy_develop(本地 ahead 若干,待推送) |
| 工作区 | 干净 |
| 数据库 | 89 张业务表,alembic current = head = 20260911_merge_adv_risk_heads |
ruff check app tests tools |
干净 |
mypy app |
228 个文件 0 错 |
pytest tests/unit tests/contract |
1207 passed, 2 skipped, 0 failed |
pytest tests/integration |
99 passed |
tools/check_authoritative_docs.py |
40 份文档,无编号冲突 |
| 后台进程 | 无(登录测试台已关闭,端口已释放) |
mypy与测试数在本项目必须带环境读:架构师环境用D:\conda\envs\jr_py313\python.exe,NL 那边用本机.venv。此前出现过 "他报 184 个错、这边 0 个错"的对不上,根因是对方的虚拟环境没满足pyproject.toml的sqlalchemy>=2.0,<3/mypy>=1.14,<2,不是代码质量问题。 讨论这个数字前先对版本。
2. 这一轮做了什么
2.1 合进来的三条线
| 来源 | 内容 |
|---|---|
| 袁聪 | 场外基金运营(offsite_* 10 张)、推广(promotion_* 7 张)、NL2SQL、行情 |
| NL | 客服画像出口、知识库管理三端点、合规语境豁免、知识向量链路、检索字段运行时探测 |
| 投顾 | 21 张 advisor_* 表、投顾 Agent、组合分析、产品对比、投资目标、方案生成/审核/发布 |
2.2 平台侧补齐的
- 登录:
POST /api/v1/auth/tokens(bcrypt 校验 + 服务端签发 + 限流 + 成功/失败都审计)。 令牌里只放sub,角色/权限/数据范围由IdentityService每次请求查库解析 —— 所以权限变更立即生效,现有鉴权链路一行未改。 - RBAC 只读:
GET /admin/roles、/admin/roles/{code}、/admin/roles/{code}/permissions、/admin/users/{user_id}/roles(后一个直接复用IdentityService.resolve,回答"这个人为什么 403")。 - 投顾角色:
advisor(id=9004)+ 16 个投顾权限(id 9020–9035)。 投顾拿 10 项工作流权限;治理类 6 项只给admin。 - 迁移:跑了两次
alembic upgrade head,业务表 51 → 89。
2.3 修掉的真缺陷
| 问题 | 性质 |
|---|---|
aiosqlite 未声明 |
袁聪 6 个测试必挂,报错指向 SQLAlchemy 内部而非"缺依赖" |
python-docx 未声明 |
知识入库解析 .docx 时 ModuleNotFoundError |
| 3 个 mypy 错 | 全在 offsite_fund_service.py / offsite_document_recognition_adapter.py,各一行 |
| 7 项 ruff | 含 NL 的 conftest 漏 import(F821)、发布脚本死变量(F841) |
| 2 处文档重号 | 21-、22- 被投顾线占用 → 让号到 30-/31- |
.gitignore 编码混合 |
之前用 Add-Content -Encoding utf8 追加造成的,read 工具报 invalid UTF-8 |
3. 演示账号与环境口径
3.1 账号(sys_user.username,不是用户 id)
| user id | username | 密码 | 角色 | 能进什么界面 |
|---|---|---|---|---|
| 9001 | cust_t |
123456 |
customer |
客户:会话、适当性、知识问答、自己的画像 |
| 9002 | risk_t |
666666 |
risk_operator |
风控:预警队列、证据、日报 |
| 9003 | admin_t |
88888888 |
admin |
管理:配置发布、模型端点、审计、RBAC 清单 |
| 9020 | advisor_t |
abc12345 |
advisor |
投顾:组合分析、产品对比、投资目标、方案发布 |
密码由
tools/set_user_password.py设置,仅限演示环境。
3.2 环境数据不随代码合并(三方都踩过这条)
| 数据 | 说明 |
|---|---|
config_release |
各环境自己发。整版本替换语义:新版本没带上的配置项等于被删除;同 key 的继承项必须被本次定义覆盖,否则旧值会被子集校验 422 拦下整次发布。 |
sys_role / sys_permission / sys_user |
各环境自己建。所以"我这儿能登录的账号,别人那台不一定有"。 |
| Milvus 集合 schema | 因环境而异(一边是 doc_id/content/visibility,另一边是 knowledge_id/snippet/无 visibility)。检索层已改运行时探测,禁止硬编码字段名。 |
advisor_product_* |
投顾的证据数据,靠外部披露文件导入,仓库里没有。 |
3.3 命令口径
# 架构师环境
D:\conda\envs\jr_py313\python.exe -m pytest -q
# 组员环境(.venv 被 .gitignore 忽略、不进仓库)
.\.venv\Scripts\python.exe -m pytest -q
跑真机验证前先确认 Docker Desktop 在运行(Milvus 依赖它,它不常驻)。
4. 平台侧新增的工具(按用途索引)
| 工具 | 用途 |
|---|---|
tools/set_user_password.py |
设置/查看登录密码(--list 只读) |
tools/create_test_user.py |
建可登录的测试账号(用户+角色+密码),并验证权限能解析出来 |
tools/grant_advisor_role.py |
建 advisor 角色与 16 个权限(只增不删,带 --dry-run) |
tools/publish_profile_tool_whitelist.py |
补发客服白名单(画像工具),继承全部受管表 |
tools/login_console.py |
浏览器登录测试台(http://127.0.0.1:8099) |
tools/seed_advisor_demo.py |
投顾演示数据(产品目录+测评+归属),并报告方案那步卡在哪 |
tools/probe_release_state.py |
只读:生效配置版本与 agent_tools 明细 |
tools/probe_auth_state.py |
只读:sys_user 的密码状态(只出前缀与长度,不出完整哈希) |
tools/probe_knowledge_collections.py |
只读:Milvus 集合 schema 与行数 |
tools/seed_test_rbac.py是 DELETE 重建语义,它的DELETE FROM sys_permission WHERE id BETWEEN 9001 AND 9099会清掉grant_advisor_role.py建的投顾权限。要在种子里固化投顾权限,请并进它的PERMISSIONS常量,而不是两个脚本各建一套。
5. 等组员推完之后的联调清单
git fetch origin --prune
# 1) 先试合,看冲突。加 --no-commit 是为了留出验证机会,别直接让它落提交
git merge --no-commit --no-ff origin/<他们的分支>
# 2) 合并后必跑(表与文档都是环境/仓库数据,容易漏)
python -m alembic upgrade head
python tools/audit_schema.py # 期望 no missing or unexpected
python tools/check_authoritative_docs.py # 期望 no number collision
# 3) 门禁
ruff check app tests tools
mypy app
pytest tests/unit tests/contract -q
pytest tests/integration -q
# 4) 真机联调
python tools/seed_advisor_demo.py # 投顾数据(方案那步见 §6)
python tools/login_console.py --port 8099 # 浏览器登录测试台
为什么迁移与文档守卫要单独列:三家合并里,有两次带进了文档重号、两次库与代码
版本不一致(一次"版本号跑了、表没建",一次"表没建、版本号也没跑")。两者都靠
alembic upgrade head 收敛,而重号只有守卫能发现。
跑验收前必须先停常驻 Worker
python -m app.worker 与验收脚本共享 agent_run 队列,它会抢走 run,导致假失败。
(见 docs/20 §5、docs/19 §7。)
6. 悬置的决策项(需要业务/架构拍板)
- 画像与测评的等级口径不一致:
fin_customer_profile.investor_type = C2, 而tools/seed_advisor_demo.py补的测评是C5。前者决定画像展示、后者决定适当性裁决, 两者会同时出现在界面上。演示前需统一(把测评改成 C2,或把画像也改成 C5——后者要改既有行)。 - 投顾方案暂时配不出来:
authoritative_tradable_products是 fail closed 的, 没有带source_url/document_sha256的 verified 适当性参考就排除全部产品。 那些行必须来自真实的销售适当性披露 / 基金合同文件(import_product_governance_reference.py的两个 CSV,不在仓库里)。不伪造这两个字段是证据链红线。 拿到文件后按seed_advisor_demo.py打印的三条命令补。 operator角色只有 1 项权限(offsite:write),而bootstrap.py有 8 处引用它。 与advisor之前同类:角色在、权限不全。好在那些入口通常也允许admin,故不是全挂。memory_sync_outbox没有消费端:ProjectionReconciliationService有定义、 无实例化点;GraphProjectionWorker同样没有实例化点。组件写好了、线没接。- 权限的可写接口(B2)未做,且不应随手做:必须带三条红线 —— 审计留痕、禁止自我提权、保护内置角色(否则可能把自己锁在门外)。 当前只做了只读(§2.2)。
7. 平台侧的边界(别重复实现)
docs/05 §11 把"JWT 签发、刷新、注销"划给统一身份认证模块。平台现在只做登录
(§2.2 已注明这是该句的唯一例外):刷新与注销仍留给那个模块,
app/core/security.py 已经留好 RevocationStore 协议,接上 Redis 即可。
认证是平台级能力,不是某个业务域的事。业务分支不要自己加登录或鉴权路由,
否则会绕开公共鉴权(AGENTS.md 规则 7)。
本文所有数字均为 2026-09-11 实测;若与代码不一致,以代码与 docs/05-接口文档.md 为准。