diff --git a/docs/21-投顾Agent迁移TODO.md b/docs/21-投顾Agent迁移TODO.md index 9e430bd..173b74c 100644 --- a/docs/21-投顾Agent迁移TODO.md +++ b/docs/21-投顾Agent迁移TODO.md @@ -133,7 +133,8 @@ Ruff 通过,MyPy(138 个源文件)通过。阶段十提交:`0d42779`; 阶段十二测试结果:专项 `12 passed`;单元/契约 `499 passed, 3 warnings`;Ruff 通过;MyPy (142 个源文件)通过;OpenAPI 已确认新增 3 个管理员画像治理路由。数据库结构未新增迁移, -复用阶段四已建立的画像标签、漂移复核和 Outbox 表;真实库端到端审核验收待独立迁移库执行。 +复用阶段四已建立的画像标签、漂移复核和 Outbox 表;独立迁移库真实端到端审核已通过: +第二次问卷提交生成 1 条待复核记录,管理员审核通过后可查询 8 条内部标签。 阶段十三已完成全端验收(代码提交前):单元测试 `491 passed, 3 warnings`,契约测试 `8 passed`, Ruff 和 MyPy 通过;独立迁移库 `jr_agent_qyqy_migration` 使用 `root` 账号执行 @@ -462,12 +463,12 @@ python tools/audit_constraints.py - [x] 验证空库迁移。(独立迁移库按基线迁移链执行 `alembic upgrade head` 成功) - [ ] 验证已有测试库迁移。 - [x] 验证首次登录问卷流程。(真实 HTTP 验收:查询 `200`、首次提交 `201`、业务接口拦截解除) -- [ ] 验证投资目标创建和确认流程。 -- [ ] 验证产品推荐流程。(服务专项测试通过,真实库端到端待补) -- [ ] 验证持仓分析流程。(服务专项测试通过,真实库端到端待补) -- [ ] 验证动态资产配置流程。(服务专项测试通过,真实库端到端待补) -- [ ] 验证推荐审核发布流程。(服务专项测试通过,真实库端到端待补) -- [ ] 验证画像漂移复核流程。(服务专项测试通过,真实库端到端待补) +- [x] 验证投资目标创建和确认流程。(真实 HTTP:创建 `201`、确认 `200`;目标书审核/发布均 `200`) +- [ ] 验证产品推荐流程。(真实 HTTP 可生成待审核方案,但 0 个候选;历史行情无成交额,流动性门槛按失败关闭) +- [x] 验证持仓分析流程。(真实 HTTP 返回 `ready`,2 条场内模拟持仓、集中度预警;行业数据按实际缺失降级) +- [ ] 验证动态资产配置流程。(真实 HTTP 返回 `ready`,但指标覆盖 `0.00`、`dynamic=false`,当前为静态降级) +- [x] 验证推荐审核发布流程。(真实 HTTP 审核和发布均 `200`;当前方案无产品,原因见推荐数据门槛) +- [x] 验证画像漂移复核流程。(真实 HTTP:问卷 `201`、发现 1 条待复核、审核 `200`、管理员标签查询 8 条) - [x] 验证行情主源失败切换备用源。(专项测试通过) - [x] 验证 Redis 不可用时的降级。(真实 HTTP 限流链路实测放行;专项测试通过) - [x] 验证 Neo4j 不可用时的降级。(专项测试通过) diff --git a/tools/seed_test_rbac.py b/tools/seed_test_rbac.py index 6f47043..5485337 100644 --- a/tools/seed_test_rbac.py +++ b/tools/seed_test_rbac.py @@ -44,10 +44,27 @@ PERMISSIONS: tuple[tuple[int, str, str, str, str], ...] = ( (9015, "config:review", "config", "review", "all"), (9016, "config:activate", "config", "activate", "all"), (9017, "model-endpoint:manage", "model-endpoint", "manage", "all"), + (9018, "investment-goal:write:self", "investment-goal", "write", "self"), + (9019, "investment-goal:confirm:self", "investment-goal", "confirm", "self"), + (9020, "investment-goal:read:self", "investment-goal", "read", "self"), + (9021, "product-recommendation:generate:self", "product-recommendation", "generate", "self"), + (9022, "product-recommendation:read:self", "product-recommendation", "read", "self"), + (9023, "portfolio-analysis:read:self", "portfolio-analysis", "read", "self"), + (9024, "asset-allocation:generate:self", "asset-allocation", "generate", "self"), + (9025, "profile-governance:read", "profile-governance", "read", "all"), + (9026, "profile-governance:review", "profile-governance", "review", "all"), + (9027, "investment-goal:review", "investment-goal", "review", "all"), + (9028, "investment-goal:publish", "investment-goal", "publish", "all"), + (9029, "product-recommendation:review", "product-recommendation", "review", "all"), + (9030, "product-recommendation:publish", "product-recommendation", "publish", "all"), + (9031, "asset-allocation:backtest", "asset-allocation", "backtest", "all"), ) # 客户:业务侧自助能力(自己的会话、反馈、转人工、自己的记忆画像)。 -CUSTOMER_PERMISSIONS = (9001, 9002, 9003, 9004, 9005, 9006, 9007, 9008, 9009, 9011) +CUSTOMER_PERMISSIONS = ( + 9001, 9002, 9003, 9004, 9005, 9006, 9007, 9008, 9009, 9011, + 9018, 9019, 9020, 9021, 9022, 9023, 9024, +) # 风控专员:业务侧只读 + 跨客户记忆 + 审计只读,不含配置写权限。 RISK_PERMISSIONS = (9001, 9002, 9003, 9010, 9011, 9012) # 平台管理员:管理面全套(配置发布四态 + 模型端点 + 审计)。 @@ -88,8 +105,6 @@ async def seed() -> None: await session.execute(text("DELETE FROM sys_user_role WHERE user_id IN (9001,9002,9003)")) await session.execute(text("DELETE FROM sys_permission WHERE id BETWEEN 9001 AND 9099")) await session.execute(text("DELETE FROM sys_role WHERE id IN (9001,9002,9003)")) - await session.execute(text("DELETE FROM sys_user WHERE id IN (9001,9002,9003)")) - for user_id, user_no, user_name, user_type in USERS: await session.execute( text( @@ -97,6 +112,8 @@ async def seed() -> None: " professional_investor_status, fund_account_status, status," " created_at, updated_at)" " VALUES (:id,:no,:name,'x',:type,'none','closed','正常',:now,:now)" + " ON DUPLICATE KEY UPDATE user_no=VALUES(user_no), username=VALUES(username)," + " user_type=VALUES(user_type), status=VALUES(status), updated_at=VALUES(updated_at)" ), {"id": user_id, "no": user_no, "name": user_name, "type": user_type, "now": now}, )