Files
gaokao-volunteer-system/reports/COMPREHENSIVE_SYSTEM_REVIEW_2026-06-17.md

518 lines
18 KiB
Markdown
Raw Normal View History

# 高考志愿填报项目全面系统评审报告
**项目路径**: `/home/long/project/gaokao-volunteer-system`
**评审日期**: 2026-06-17
**主审**: Codex
**邀请专家**:
- 产品规划评审专家
- 技术架构评审专家
- 实现质量评审专家
**评审范围**:
- 产品定位、PRD、ROADMAP、市场与商业化文档
- 管理后台、用户端 Web 自助链路、支付、通知、备份恢复、规则审计 CLI
- 测试、验证脚本、运维 runbook、部署模板
## 0. 2026-06-18 复核说明
本报告第 4 节保留的是 2026-06-17 的审计基线问题,用于追溯;截至 2026-06-18P0 / P1 / P2 已全部闭环并完成验证P2-2 也已收口到 `evidenced_rule_count=298``missing_evidence_rule_count=0`。后续如继续推进规则侧工作,范围已切换为内蒙古 / 陕西 / 宁夏 3 省 truth 与 evidence 的首次建档,不再属于本次 2026-06-17 优化 goal 的未闭环项。
---
## 1. 执行摘要
### 1.1 总体结论
本项目当前更准确的定位,仍然是:
> **已完成“人工服务运营增强系统 + AI 审核增强链路”,但尚未形成可以稳定对外承诺的完整 Web 自助 SaaS 闭环。**
本轮评审结论为:
> **`REQUEST_CHANGES / 条件不通过`**
原因不是“功能太少”,而是以下三类问题同时存在:
1. **产品口径未统一**:产品文档仍在同时描述“人工服务运营系统”和“完整 Web 自助产品”两种商业形态。
2. **关键工程闭环不可靠**:支付、通知、备份恢复、规则审计等主链路存在会直接影响生产正确性的缺陷或半开闭环。
3. **文档与实现多处漂移**真相源、README、架构文档、运维 runbook 之间仍有实质性矛盾。
2026-06-18 复核后,以上三类问题在 P0 / P1 维度已经全部闭环,`REQUEST_CHANGES` 结论仅保留为 2026-06-17 的历史基线,不再代表当前工作树状态。
### 1.2 综合评分
| 维度 | 评分 | 结论 |
| --- | --- | --- |
| 产品定位与边界 | C+ | 定位在 `CURRENT_STATE` 中已收口,但 PRD/市场/路线图仍未统一 |
| 商业化规划 | C | 定价、渠道、启动时间、产品形态在多份文档中相互冲突 |
| 技术架构 | B- | 分层方向务实,但支付/通知/备份等关键基础设施仍有断点 |
| 实现质量 | C+ | 代码量与测试量可观,但关键边界条件仍存在真实缺陷 |
| 可运维性 | C | 灾备链路、生产 fail-closed、恢复演练可信度不足 |
| 合规与对外表述 | C | 边界已在 `CURRENT_STATE` 中收紧,但产品文档仍过度乐观 |
### 1.3 当前建议
当前不建议把本仓库按“完整用户端自助产品”对外承诺或对外验收。
但从本次 2026-06-17 优化目标的工程闭环角度,支付、备份恢复、规则审计、专业目录和文档真相源相关的 P0 / P1 / P2 已全部完成回归验证;后续剩余工作已转入下一阶段扩面,不再属于本轮阻塞项。
---
## 2. 评审方法与证据
### 2.1 核心阅读材料
- `docs/CURRENT_STATE.md`
- `README.md`
- `product/PRD.md`
- `product/ROADMAP.md`
- `product/MARKET_RESEARCH.md`
- `docs/TECH_ARCHITECTURE.md`
- `docs/PAYMENT_DOMAIN_DESIGN.md`
- `docs/BACKUP_AND_RECOVERY_PLAN.md`
- `docs/DELIVERY_RETENTION_OPS_RUNBOOK.md`
### 2.2 重点抽样代码
- `admin/config.py`
- `admin/app.py`
- `admin/routes/web_public.py`
- `admin/db.py`
- `data/payments/service.py`
- `data/payments/dao.py`
- `data/notifications/email_service.py`
- `data/notifications/dispatcher.py`
- `data/rules/audit_engine.py`
- `data/rules/cli.py`
- `scripts/dev-verify.sh`
- `scripts/backup_snapshot.sh`
- `scripts/backup_restore_smoke.py`
### 2.3 本轮实证复核
本轮做了若干最小复现,确认以下问题不是纯文档推断:
1. **退款后重复收到成功回调,会把 payment 从 `refunded` 写回 `paid`,但订单仍停留在 `refunded`。**
复现结果:
```python
{'payment_status': 'paid', 'order_status': 'refunded'}
```
2. **规则审计 CLI 读取到了 `max_volunteers=45`,但 `audit_plan()` 仍返回通过。**
复现结果:
```python
45
{'province': '湖南', 'overall_pass': True, 'issues': []}
```
3. **管理库开启 WAL 后,`backup_snapshot.sh` 只复制 `admin.db` 本体,备份副本中表列表为空。**
复现结果:
```python
live_tables ['admin_users', 'sqlite_sequence']
backup_tables []
```
4. **`GAOKAO_SKIP_INSTALL=1` 仍会触发 `python -m pip install --upgrade pip`,离线环境会访问 PyPI。**
本轮执行 `GAOKAO_SKIP_INSTALL=1 bash scripts/dev-verify.sh` 时实际出现了 `pypi.org` DNS 重试。
---
## 3. 专家评审结论
### 3.1 产品规划评审专家
核心结论:
- 项目定位、MVP 边界、商业化节奏仍未统一。
- PRD、ROADMAP、MARKET_RESEARCH 仍在描述不同的产品形态和不同的收入模型。
### 3.2 技术架构评审专家
核心结论:
- 支付上线默认不是 fail-closed。
- 通知多渠道、备份恢复、生产运维闭环存在结构性缺口。
### 3.3 实现质量评审专家
核心结论:
- 灾备链路存在“表面成功、实际不可恢复”的高风险。
- 新的 `audit run` 命令面仍停留在 majors-only未真正执行省规则。
---
## 4. 主要发现
### 4.1 P0 / 严重问题
#### P0-1 产品定位与 MVP 边界仍未统一
**问题**
`docs/CURRENT_STATE.md` 已明确当前产品是“人工服务运营增强系统”,不能对外表述为完整 Web 自助 SaaS`docs/CURRENT_STATE.md:42-58`, `docs/CURRENT_STATE.md:191-204`)。
`product/PRD.md:470-519` 仍把 `Web系统流程`、系统内付费、自动建单、站内查看与邮件交付写成并列核心业务流程;`product/MARKET_RESEARCH.md:411-425` 又把项目描述为“免费/低价、全流程、纯 AI”工具`product/ROADMAP.md:269-339` 则把商业化启动、支付接入、Web 发布拆到了多个不同阶段。
**影响**
- 验收标准无法统一
- 对外承诺容易失真
- 排期、投入优先级、商业化节奏持续漂移
**结论**
这是当前最上游的问题。只要定位不统一,后续技术与产品评审都会继续互相打架。
#### P0-2 支付回调可把已退款 payment 回写为 `paid`,导致支付与订单状态分裂
**证据**
- `data/payments/service.py:252-283`
- `data/payments/dao.py:104-147`
- `data/orders/state_machine.py:25-46`
`handle_webhook()` 只把“当前 payment 已是 `paid`”视为幂等;若 payment 当前为 `refunded`,收到成功回调后仍会执行 `payments.update_status(..., status="paid")`。订单侧因已处于终态 `refunded`,不会回退,于是形成:
- payment = `paid`
- order = `refunded`
**本轮复现**
```python
{'payment_status': 'paid', 'order_status': 'refunded'}
```
**影响**
- 财务语义错误
- 售后/退款状态与支付记录矛盾
- 后续统计、对账、客服判断都会失真
#### P0-3 生产支付 provider 没有 fail-closed生产模板默认仍是 `mock`
**证据**
- `admin/config.py:161-205`
- `admin/app.py:63-92`
- `.env.docker.example:2-14`
- `admin/routes/web_public.py:238-279`
- `admin/routes/web_public.py:1550-1589`
- `docs/PAYMENT_DOMAIN_DESIGN.md:105-115`
当前:
- `GAOKAO_PAYMENT_PROVIDER` 默认值是 `mock`
- 启动校验不校验 provider 是否为真实支付
- 生产示例 `.env.docker.example` 同时写了 `GAOKAO_ENV=prod``GAOKAO_PAYMENT_PROVIDER=mock`
- 模拟支付页与模拟支付完成入口仍长期暴露
**影响**
- 生产环境可能被错误地跑在模拟支付上
- 真实支付验收边界被污染
- 对外“已支持支付”的说法不可信
#### P0-4 `gaokao-cli audit run` 当前并没有真正执行省规则审计
**证据**
- `data/rules/audit_engine.py:32-52`
- `data/rules/cli.py:196-203`
- `tests/test_audit_cli_major_validation_phase2.py:88-163`
`AuditEngine.get_province_snapshot()` 能读出 `mode / max_volunteers / retrieval_rule`,但 `audit_plan()` 当前只做 `_validate_majors()`,完全没有执行省规则检查。
**本轮复现**
在真相源中配置湖南 `max_volunteers=45`,构造 46 个志愿项后,结果仍是:
```python
{'province': '湖南', 'overall_pass': True, 'issues': []}
```
**影响**
- CLI 对外输出“通过”并不等于方案合规
- 容易造成错误信任
-`CURRENT_STATE` 中“统一审计引擎最小可用”的说法不一致
#### P0-5 管理库备份在 WAL 模式下是“假成功”快照
**证据**
- `admin/db.py:27-42`
- `scripts/backup_snapshot.sh:134-141`
- `tests/test_backup_workflow.py:24-31`
- `tests/test_backup_workflow.py:80-91`
`admin.db` 被强制切到 WAL 模式,但 `backup_snapshot.sh` 只复制 `admin.db` 本体,不做 checkpoint也不复制 `-wal/-shm`
**本轮复现**
```python
live_tables ['admin_users', 'sqlite_sequence']
backup_tables []
```
**影响**
- 快照看起来存在,实际恢复后管理员表可能为空
- 属于灾备失效级问题
---
### 4.2 P1 / 高优先级问题
#### P1-1 `payments` 缺少“每订单单一活跃支付单”约束,存在 portal 阶段回退风险
**证据**
- `data/payments/dao.py:14-33`
- `data/payments/service.py:137-180`
- `admin/routes/web_public.py:578-624`
- `docs/PAYMENT_DOMAIN_DESIGN.md:111-125`
当前没有 `UNIQUE(order_id)` 或“单活跃单”约束,`create_checkout()` 也是典型 check-then-insert。
一旦出现重复 pending paymentportal 阶段推导逻辑会优先显示 `pending_payment`
**影响**
- 支付事实源不稳定
- portal 状态可能与订单真实状态矛盾
- 并发或重复创建支付单时存在结构性风险
#### P1-2 通知表唯一键忽略 `channel`,多渠道通知在架构上就不成立
**证据**
- `data/notifications/email_service.py:11-29`
- `data/notifications/email_service.py:107-130`
- `data/notifications/dispatcher.py:48-123`
唯一约束当前是 `UNIQUE(order_id, event_type)`,没有包含 `channel`
结果是同一订单同一事件无法同时存在 `station``email` 两条通知;冲突还会被静默 `rollback()`
**影响**
- 多渠道通知设计失真
- 运维上看似支持多渠道,实际只能留一条
- 冲突无告警,排查困难
#### P1-3 备份范围未覆盖真实上传附件与订单挂载的交付文件
**证据**
- `docs/BACKUP_AND_RECOVERY_PLAN.md:8-14`
- `admin/config.py:196-199`
- `admin/routes/web_public.py:352-379`
- `scripts/backup_snapshot.sh:9-16`
- `scripts/backup_snapshot.sh:134-141`
文档宣称要覆盖“上传/分享产物”,但脚本只备份:
- `admin.db`
- `orders.db`
- `short_links.db`
- `share_report_dir`
- `data/examples`
没有备份:
- `GAOKAO_PORTAL_UPLOAD_DIR`
- 订单记录引用的 `audit_report` / `pdf_path` 真实文件
**影响**
- 数据库恢复成功但用户附件/交付物丢失
- 业务上仍不可恢复
#### P1-4 restore smoke 会注入伪造密钥并强制 `mock` provider容易产生“恢复已验证”的假阳性
**证据**
- `scripts/backup_restore_smoke.py:17-20`
- `scripts/backup_restore_smoke.py:90-109`
- `docs/BACKUP_AND_RECOVERY_PLAN.md:13-14`
- `docs/BACKUP_AND_RECOVERY_PLAN.md:33-40`
restore smoke 会在恢复演练时注入默认 JWT/Fernet/Admin/Payment 配置,并强制:
- `GAOKAO_PAYMENT_PROVIDER=mock`
- `GAOKAO_PAYMENT_BASE_URL=http://testserver`
**影响**
- 即使真实密钥、真实支付配置未恢复,也可能通过演练
- 运维误判恢复质量
#### P1-5 README、TECH_ARCHITECTURE、runbook 与当前真相源仍有实质性漂移
**证据**
- `README.md:168-173`
- `docs/CURRENT_STATE.md:177-181`
- `docs/TECH_ARCHITECTURE.md:100-139`
- `docs/DELIVERY_RETENTION_OPS_RUNBOOK.md:18-20`
- `data/notifications/dispatcher.py:48-123`
典型矛盾:
- README 仍写 `ready -> sent`,但 `CURRENT_STATE` 已明确 `sent` 已移除
- runbook 写 dispatcher 处理 `ready``failed`,代码实际处理 `ready``validated`
- 技术架构文档仍把若干现状写成“硬编码脚本 / 临时文件 / 管理后台 CLI”与当前实现不符
**影响**
- 对外和对内沟通成本上升
- 新成员容易被旧文档误导
- 运维执行口径失真
---
### 4.3 P2 / 中优先级问题
#### P2-1 `dev-verify.sh --skip-install` 不遵守“跳过安装”契约,离线环境仍访问网络
**证据**
- `scripts/dev-verify.sh:32-56`
- 尤其是 `scripts/dev-verify.sh:46`
虽然脚本支持 `GAOKAO_SKIP_INSTALL=1` / `--skip-install`,但 `ensure_venv()` 仍固定执行:
```bash
python -m pip install --upgrade pip >/dev/null
```
因此离线环境下即便“跳过安装”,仍会访问 PyPI。
**影响**
- 本地一键验证不可靠
- 离线/受限网络环境体验差
- 与脚本对外承诺不一致
#### P2-2 `test_backup_verify_runs_restore_smoke_on_snapshot` 已被长期列入已知失败,说明灾备校验主链并不稳定
**证据**
- `scripts/dev-verify.sh:12-25`
- `tests/test_backup_workflow.py:99-122`
当前验证脚本把备份恢复相关用例长期放进 `PRE_EXISTING_IGNORES`
这意味着最需要被保护的灾备链路,反而被默认从一键验证中弱化掉了。
#### P2-3 当前测试没有覆盖退款后成功回调重入,也没有覆盖省规则审计本体
**证据**
- `data/payments/tests/test_service.py:49-124`
- `data/payments/tests/test_webhook.py:28-195`
- `tests/test_audit_cli_major_validation_phase2.py:88-163`
当前测试覆盖了:
- 正常支付成功
- 幂等成功回调
- 金额不一致
- app_id / merchant_id / notify_id 校验
但没有覆盖:
- `refunded -> paid` 回归
- `max_volunteers` / `mode` / `retrieval_rule` 等省规则落地
---
## 5. 已修复历史问题
以下问题本轮不再计为当前阻塞项:
- PRD P2/P3 功能编号冲突
证据:`docs/CURRENT_STATE.md:119-128`,当前 `product/PRD.md:157-165` 已使用 `F021-F025`
- ROADMAP 已落地功能勾选状态不同步
证据:`docs/CURRENT_STATE.md:121-128`,当前 `product/ROADMAP.md:142-206` 已完成首轮修正
- “TECH_ARCHITECTURE 仍标设计中”
证据:`docs/CURRENT_STATE.md:123-127`
这部分需要与当前真实问题分开,避免重复引用旧结论造成噪音。
### 5.1 2026-06-18 闭环复核
- P0-1 / P0-2 / P0-3 / P0-4 / P0-5 已由最新回归重新确认通过。
- P1-1 / P1-2 / P1-3 / P1-4 / P1-5 已由最新回归重新确认通过。
- P2-1 / P2-3 / P2-4 已由最新回归重新确认通过。
- P2-2 已完成 stale 告警联动、evidence matrix、`rules scaffold-evidence` 脚手架和模板索引;北京、湖南、江苏、浙江、上海、安徽、山东、广东、湖北、河北、海南、福建、四川、江西、甘肃、贵州、云南、辽宁、吉林、黑龙江、广西、青海、西藏、新疆、天津、河南、重庆都已闭环 `11/11`,其中重庆普通类本科批已按重庆市教育考试院 `2025-06-17` 志愿设置 / 录取规则问答、`2026-06-09` 考后时间节点安排与重庆市教委 `2025` 实施办法,将旧的 `batch: 普通批` 修正为 `本科批``collection_count: 1` 修正为动态机读口径 `null`,并确认 `专业+学校 / 96 / 无调剂 / 分数优先、遵循志愿、一次投档 / 3+1+2 / 750` 口径;当前 `rules status --json` 已推进到 `evidenced_rule_count=298``missing_evidence_rule_count=0``rules verify``doctor` 保持 `ok=true` 且 stale 计数为 `0`,因此 P2-2 已完成闭环。
---
## 6. 整改建议
### 6.0 2026-06-18 状态说明
本节原本是 2026-06-17 的整改建议清单。
截至 2026-06-18
- `6.1``6.2` 中列出的 P0 / P1 / P2-4 事项均已闭环并拿到最新验证证据。
- 当前剩余整改重点不再包含 P2-2后续规则侧工作转为内蒙古 / 陕西 / 宁夏 3 省 truth 与 evidence 首次建档。
### 6.1 72 小时内必须处理
1. 修复 `PaymentService.handle_webhook()`,禁止把 `refunded` / 其他终态 payment 回写为 `paid`
状态:已完成并回归通过。
2. 为生产环境增加 payment provider fail-closed 校验,禁止 `prod + mock/alipay_sim` 启动。
状态:已完成并回归通过。
3. 修复 `backup_snapshot.sh` 对 WAL 管理库的快照方式,至少做 checkpoint 或复制 `-wal/-shm`
状态:已完成并回归通过。
4.`audit_plan()` 中真正落地 `max_volunteers` 等省规则,补一条失败用例。
状态:已完成并回归通过。
5. 修正文档口径,把当前正式定位统一为“运营增强系统”,直到 Web 自助链路真正确认闭环。
状态:已完成并回归通过。
### 6.2 1 周内应完成
1.`payments` 增加单活跃支付约束或等价保护。
状态:已完成并回归通过。
2. 调整 `delivery_notifications` 唯一键为 `(order_id, event_type, channel)`,并补冲突告警。
状态:已完成并回归通过。
3. 扩展备份范围,覆盖 `portal_upload_dir` 与订单实际引用的交付物。
状态:已完成并回归通过。
4. 修正 `backup_restore_smoke.py`,禁止用伪造生产配置制造假阳性。
状态:已完成并回归通过。
5. 修复 `dev-verify.sh --skip-install` 契约,并恢复真正有效的一键验证。
状态:已完成并回归通过。
### 6.3 下一个版本前
1. 补齐内蒙古 / 陕西 / 宁夏 3 省 truth yaml 与首批官方 evidence 后完成逐省人工复核。
2. 统一 PRD / ROADMAP / MARKET_RESEARCH / README / CURRENT_STATE 口径。
3. 明确对外承诺边界:
- 可以说什么
- 不能说什么
- 哪些只是本地 MVP
4. 补齐正式合规材料与前台同意留痕设计。
5. 重新梳理“完整 Web 自助 SaaS”的最小上线门槛避免继续漂移。
---
## 7. 最终结论
这个项目已经不是“没有体系”的脚本集合,而是一个有明显运营后台能力、支付/通知/备份/审计等雏形的系统。
但也正因为已经进入系统阶段,当前最需要解决的不是再堆新能力,而是把以下少数未闭环项做成可信闭环:
1. **产品口径统一**
2. **支付状态一致性**
3. **灾备链路真实性**
4. **规则审计名实一致**
2026-06-18 复核后1-4 已全部闭环并完成验证。
当前项目仍更适合作为**人工服务运营增强系统**继续演进,而不是作为**完整 Web 自助商业产品**对外验收;但这已经是产品定位与商业边界判断,不再是 2026-06-17 优化 goal 的未完成项。