Files
zyt/artifacts/prescription-ai-visibility-backend-implementation.md
T
2026-10-17 16:51:48 +08:00

64 lines
5.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.
# 处方 AI 一致度授权:后端实施记录
日期:2026-10-17。仅修改 server 后端及本报告;未提交、未部署、未连接生产数据库或模型服务。
## 行为
- 新服务 `server/app/common/service/prescriptionai/PrescriptionAiVisibility.php` 使用 ConfigService 一条 JSON:`type=prescription_ai_visibility` / `name=agreement_policy`,字段仅 `role_ids:int[]`、`admin_ids:int[]`。
- 默认空、缺失或格式错误策略全部不可查看一致度。角色或单用户命中任一即可;查看没有 root、通配符或管理权限豁免。
- 账号每次重新检查 `disable=0`、`delete_time IS NULL`;角色关系实时查询并排除软删除角色。配置读取无长期缓存,授权或撤销下次请求立即生效。
- 独立管理权限为 `tcm.prescriptionAi/manageVisibility`。root 可管理,其余账号须持此权限;三个管理入口均在服务端统一验证,防止未注册路由中间件默认放行产生越权。所有入口仍由控制器重载有效账号,拒绝未知参数与错误 HTTP 方法。
- statuses 顶层及各 item、reports 顶层及各 batch、detail 顶层均返回 `agreement_visible`。未授权时共享 Logic 投影删除整个 comparison、扁平 score/herb_score、比较状态/原因/版本、比较类型/基线等派生数据;失败模型生成错误原因保留。
- full 模型正文使用固定字段及嵌套结构投影,拒绝历史正文未知 raw/result/score、调试对象、伪造 progress 等旁路。报告、候选方案、来源与覆盖说明、进度、医生原方、复核意见保留。
- statistics 在扫描/聚合之前拒绝没有白名单资格的账号;原有动作 RBAC 和处方/患者/来源范围校验仍执行。后台分析、比较、手动重试与复核的既有权限流程未加指标限制。
## 固定接口
| HTTP | `tcm.prescriptionAi/` 后 action | 数据 |
| --- | --- | --- |
| GET | capabilities | `{agreement_visible:boolean, can_manage_visibility:boolean}`,登录账号自查 |
| GET | getVisibilityConfig | `{role_ids:number[],admin_ids:number[]}`,仅管理者 |
| POST | setVisibilityConfig | 接收且仅接收上述两数组,返回去重排序后的策略;仅管理者 |
| GET | visibilityOptions | `{roles:[{id,name}],admins:[{id,name,account}]}`,仅管理者 |
选项及保存列表上界:500 个角色、5000 个后台用户。选项只返回活跃记录,超过上界明确报错,不静默截断。保存只验证新提交的名单,因此失效 ID 可从旧名单中删除后保存,不会被旧数据阻塞。角色无 disable/status 列,按软删除判断。
## 迁移
新增 `server/database/migrations/2026_10_17_prescription_ai_agreement_visibility.sql`:
- 幂等创建系统设置下 type C 的“处方AI一致度授权”菜单,perms 为 `tcm.prescriptionAi/manageVisibility`,component 为 `setting/prescription_ai_visibility/index`。
- 幂等预置一条空 JSON 策略,不自动授权任何非 root 角色,不填入查看白名单。
- 不新增业务表,不改变既有报告或队列数据。上线时需要先执行该迁移;本次仅在隔离测试数据库中执行并重放验证。
## 修改文件
1. `server/app/common/service/prescriptionai/PrescriptionAiVisibility.php`(新):策略、管理校验、实时匹配、有限选项、输出投影。
2. `server/app/adminapi/controller/tcm/PrescriptionAiController.php`:四个接口。
3. `server/app/adminapi/logic/tcm/PrescriptionAiLogic.php`:统一能力标记、指标裁剪、统计授权、正文投影。
4. `server/database/migrations/2026_10_17_prescription_ai_agreement_visibility.sql`(新):幂等菜单及空策略。
5. `server/tests/PrescriptionAiVisibilityTest.php`(新):无应用初始化的纯离线策略/投影回归。
6. `server/tests/PrescriptionAiQueueTest.php`:隔离真实 ORM、Cipher、Logic、Controller 及迁移回归。
## 验证结果
PHP 8.2.9;新增/修改的 5 个 PHP 文件全部 `php -l` 通过。`git diff --check -- server` 通过。全仓 diffcheck 中另有并行桌面端文件换行问题,已通知主代理,本任务未修改 app 文件。
纯离线:
- `php server/tests/PrescriptionAiVisibilityTest.php`:22 checks。
- `php server/tests/PrescriptionAiProgressTest.php`:38 checks。
- `php server/tests/PrescriptionAiComparisonTest.php`:266 checks。
- `php server/tests/PrescriptionAiStatisticsTest.php`:64 checks。
- `php server/tests/PrescriptionAiConfigurationTest.php`:通过。
隔离 MySQL:主代理建立的 `127.0.0.1:33447`,root 空密码,显式 `ZYT_AI_TEST_MYSQL_PORT=33447`。这些脚本不 App::initialize,不读生产 .env,创建并最终删除各自唯一 `prescription_ai_test_*` 临时库:
- `php server/tests/PrescriptionAiQueueTest.php`:113 checks。
- `php server/tests/PrescriptionAiQueueTest.php --legacy-progress-schema`:111 checks。
- `php server/tests/PrescriptionAiPipelineTest.php`:125 checks。
新增集成覆盖:默认空名单含 root 拒绝查看、root 管理与查看分离、独立非 root 管理权限、GET/POST/未知字段、伪 root/星号 token、配置越权拒绝、角色/个人任一授权、多角色、即时撤销、软删除角色、禁用/删除账号、无效策略、活跃最小选项与超限、菜单禁用即时撤销、allowlist 不替代动作 RBAC、真实加密旧正文注入及嵌套旁路、三个读取出口完整裁剪、统计拒绝、保留报告/候选/原方/复核/失败原因、限制指标后仍可重试/复核、迁移执行两次。
报告是实现交付,不表示生产迁移已经执行。测试 MySQL 进程由主代理负责最终关闭。