17 KiB
gaokao-volunteer-system 系统性 Review 报告(2026-06-14)
历史快照(2026-06-14)。当前真相源请优先阅读:
docs/CURRENT_STATE.md→docs/ACTIVE_EXECUTION_BOARD_2026-06-13.md→docs/ACTIVE_REMEDIATION_2026-06-13.md→docs/P0_P1_P2_REMEDIATION_PLAN_2026-06-14.md。
评审对象: /home/long/project/gaokao-volunteer-system
评审方式: 当前文档真相核对 + 关键源码结构审查 + 安全/测试/运维专项审查 + 本地门禁复核
评审标准: 严格标准;以"真实业务闭环、数据安全、验证可信度、可运维性"为主轴
当前真相源: docs/CURRENT_STATE.md
1. 结论
结论:项目已经具备较完整的“运营后台 + 订单 + 支付抽象 + portal + 分享 + 渠道同步 + 交付事件”骨架,核心订单状态机与 DAO 边界也明显优于很多同规模项目;但按严格标准看,系统仍未达到“关键链路一致性可靠、支付/删除/交付语义闭环、质量门禁可信、灾备与部署可验证”的稳态。
总体评级:有明显工程基础,但不建议把当前版本描述为“已完成的、可放心放量的商业闭环系统”。
最重要判断:
- 订单/支付/退款/交付仍有多处语义裂缝,主系统真相源不统一。
- 隐私删除/匿名化与文档承诺不一致,存在误报“已匿名化/已删除”的合规风险。
- CI / 本地 / coverage gate / Docker / 备份恢复没有形成一致、可复现、可证明的验证链。
- 支付回调与分享公开面仍有显著安全收敛空间。
本次未发现必须立即停机级别的 P0 远程利用证据,但存在多项 P1,足以阻止“系统已成熟闭环”的结论。
2. 评审范围
2.1 文档与约束
README.mddocs/CURRENT_STATE.mddocs/LEGAL_PRIVACY_BASELINE.mddocs/DATA_RETENTION_AND_DELETION.mddocs/BACKUP_AND_RECOVERY_PLAN.mddocs/DELIVERY_SERVICE_DESIGN.mddocker-compose.ymlDockerfile.github/workflows/ci.ymlcodecov.ymlpytest.iniscripts/dev-verify.shscripts/backup_verify.shscripts/check_coverage_gate.py
2.2 核心代码链路
admin/app.pyadmin/auth.pyadmin/config.pyadmin/password.pyadmin/db.pyadmin/routes/auth.pyadmin/routes/orders.pyadmin/routes/web_public.pydata/orders/dao.pydata/orders/state_machine.pydata/orders/public_flow.pydata/orders/deletion_service.pydata/orders/intake_store.pydata/orders/crypto.pydata/orders/masking.pydata/payments/service.pydata/payments/dao.pydata/payments/providers/alipay.pydata/payments/providers/alipay_sim.pydata/channel_sync/webhook_server.pydata/share/permission.pydata/customer_portal/token.pydata/notifications/dispatcher.py
2.3 测试与验证样本
admin/tests/test_web_public_alipay_sim_e2e.pyadmin/tests/test_order_status_page.pyadmin/tests/test_routes_orders.pydata/payments/tests/test_webhook.pytests/test_delivery_dispatcher.pytests/test_retention_cleanup.pytests/test_t5_performance.py
3. 严重级别定义
- P0: 已存在可直接导致系统失控/严重数据泄漏/资金错误且缺乏现实缓解
- P1: 高优先级问题;会破坏主链路一致性、支付/隐私/恢复可信度,阻止成熟上线结论
- P2: 中优先级问题;不会立即击穿主链,但会持续积累运维、测试或安全债务
- P3: 正向亮点或低优先改进项
4. 关键问题清单
4.1 P1 问题
P1-1 支付回调存在双写裂缝:payment 已记 paid,但 order 可能未推进
证据
data/payments/service.py::PaymentService.handle_webhook()先更新payments.status=paiddata/payments/dao.py::PaymentDAO.update_status()内部立即commit- 随后才在新的
OrdersDAO上下文里把订单从pending推到paid
风险
这是典型跨表双写一致性问题。任一时刻如果支付表提交成功、订单推进失败(订单异常、锁冲突、状态先被别处推进、进程中断),系统会留下:
payments.status = paidorders.status != paid
之后 portal、退款、统计、人工判断都会基于不同真相源工作。
结论
这是当前最重要的业务一致性问题之一。
P1-2 删除/匿名化与文档承诺不一致,存在“看起来已删,实际上没删”的合规风险
证据
docs/DATA_RETENTION_AND_DELETION.md要求订单、资料提交、报告文件、通知/支付审计都应清理或匿名化data/orders/deletion_service.py::OrderDeletionService.anonymize_order()仅更新orders主表部分字段- 未覆盖:
data/orders/intake_store.py中order_intakes.payload_jsondata/payments/dao.py中payments.callback_payloadaudit_report/pdf_path对应文件
风险
系统当前容易把“订单主表去标识化”误报成“订单数据已匿名化完成”。对于高考场景中的未成年人/监护人资料,这是明显不够的。
结论
当前删除/匿名化能力不足以支撑强隐私合规表述。
P1-3 真实支付宝回调校验过弱,只验签 + 金额,不校验应用/商户/状态边界
证据
admin/routes/web_public.py的/api/public/payments/alipay/notify直接把表单解析结果交给PaymentService.handle_webhook()data/payments/service.py::handle_webhook()只校验:签名、payment_id、金额一致data/payments/providers/alipay.py仅标准化out_trade_no/trade_no/total_amount/trade_status并做 RSA 验签- 未见对
app_id、商户标识、允许状态白名单、notify_id、gmt_payment等做二次校验
风险
系统会把“签名有效且金额匹配”的回调近似当成“业务上确认为成功支付”。这对真实支付系统不够。
结论
真实支付回调仍未达到严格上线标准。
P1-4 Webhook server 的数据库连接缓存按模块全局单例保存,且不区分 db_path
证据
data/channel_sync/webhook_server.py中_DB_CONN为模块级单例_get_db(db_path)只在_DB_CONN is None时首次打开连接;后续不同db_path直接复用旧连接make_server(..., db_path=...)虽允许传不同库路径,但连接缓存不会切换
风险
同一进程先后启动多个 webhook server / 测试实例 / 不同 DB 场景时,后者可能静默写入前一个库。问题隐蔽,影响审计、幂等和订单入库正确性。
结论
这是高风险的状态污染问题。
P1-5 退款域模型未闭环:状态机有 refunded,支付服务只把 payment 记到 refund_pending
证据
data/orders/state_machine.py支持订单进入refunded终态data/payments/service.py::request_refund()仅把 payment 更新到refund_pending- 未见生产调用路径把订单主状态同步推进到
refunded admin/routes/web_public.pyportal 阶段判断优先看 payment 的退款状态,而不是订单主状态
风险
订单域与支付域的退款真相源分裂。之后交付限制、统计、保留期清理、人工判断都可能不一致。
结论
退款闭环目前不完整。
P1-6 公开分享 edit/admin 权限是 allow-by-default,未来新增字段极易外泄
证据
data/share/permission.py中edit/admin的visible_fields=Nonerender_report_payload()在该模式下除 denylist 外默认全部透传_ALWAYS_HIDDEN_FIELDS仅覆盖少数内部字段,不覆盖未来可能新增的手机号、身份证、顾问备注等
风险
一旦报告 payload 新增敏感字段,公开分享链接可能自动带出这些信息,而不需要任何显式审批。
结论
分享策略对未来演进不够安全。
P1-7 覆盖率门禁口径互相冲突,验证链本身不可信
证据
.github/workflows/ci.yml:--cov-fail-under=60scripts/dev-verify.sh:--cov-fail-under=80scripts/check_coverage_gate.py:overall=80%、core=100%codecov.yml:也声明整体 80%、核心 100%
风险
同一改动可能出现:
- CI 通过
- 本地失败
- codecov 标准不同
- gate 脚本又给出另一套结论
这种门禁不稳定,会持续削弱团队对测试结论的信任。
结论
当前质量门禁存在制度级不一致。
P1-8 备份恢复只做到“复制文件 + 打印表名”,还不是恢复演练
证据
docs/BACKUP_AND_RECOVERY_PLAN.md自认仅是“最小恢复基线”,并明确尚无自动化恢复验证scripts/backup_verify.sh只复制 DB / 文件,然后验证 SQLite 文件可打开、文件可枚举- 未见 CI 或自动化测试真正执行“恢复后启动应用并验证 portal / 订单 / 报告”
风险
当前只能证明“文件能拷贝”,不能证明“系统能恢复并可用”。这对任何需要对外交付或数据保留承诺的系统都不够。
结论
灾备能力目前停留在文档与文件级验证,不是服务级验证。
4.2 P2 问题
P2-1 公共下单先写订单、后建支付,失败时会遗留孤儿 pending 订单
证据
admin/routes/web_public.py::create_public_order_endpoint()先create_public_order(),再PaymentService.create_checkout()data/orders/public_flow.py直接先把订单写入库data/payments/service.py::create_checkout()再独立创建 payment
风险
支付初始化失败时,用户请求失败,但库里已经有订单,且没有补偿动作。
P2-2 渠道同步仍在走已声明被替代的 dao_extension,存在双实现漂移风险
证据
data/orders/dao.py已提供OrdersDAO.upsert_by_external_id()data/channel_sync/webhook_server.py与data/channel_sync/poller.py仍直接使用data.channel_sync.dao_extension.upsert_by_external_id
风险
同一业务规则同时存在两套实现,后续修改很容易只修一套。
P2-3 交付执行器把“文件存在”直接标记为 sent,语义过度乐观
证据
data/notifications/dispatcher.py::dispatch_ready_events()校验文件存在后直接mark_sentdocs/DELIVERY_SERVICE_DESIGN.md又明确说明“邮件/渠道真实发送执行器”尚未完成
风险
sent 更像“已投递成功”,但当前实际含义只是“本地文件通过检查”。这会误导运营状态与告警语义。
P2-4 Portal token 与后台 JWT 共用同一根 secret
证据
admin/routes/web_public.py创建和校验 portal token 时使用settings.jwt_secretdata/customer_portal/token.py是独立 HMAC token 格式admin/auth.py后台 JWT 也使用同一 secret
风险
轮换、隔离、泄露影响面都被耦合,不符合边界最小化原则。
P2-5 payment webhook secret 仍有固定开发默认值,启动阶段也没有 prod fail-closed 校验
证据
admin/config.py默认GAOKAO_PAYMENT_WEBHOOK_SECRET=dev-mock-payment-secretdata/payments/service.py::for_db()也带同样默认值admin/app.py启动只校验 JWT secret 与默认管理员密码,没有校验 payment webhook secret
风险
在 mock / alipay_sim 场景中,如果配置漂移到公网环境,伪造回调成本会明显降低。
P2-6 pytest 把 data/ 直接纳入测试发现根,测试边界偏混杂
证据
pytest.ini:testpaths = admin/tests tests data- CI 也直接跑
pytest admin/tests tests data
风险
业务代码目录与测试入口绑定过紧,不利于区分 unit / integration / e2e / script verification 的语义。
P2-7 部署链只有单容器存活探测,没有业务冒烟、恢复验证、监控告警闭环
证据
docker-compose.yml仅定义一个服务、一个数据卷、一个/healthhealthcheckDockerfile仅安装运行依赖并直接启动admin.app- 文档里有监控设计,但未见对应自动化验证或可运行集成
风险
当前最多只能说明“进程活着”,不能说明“关键业务链在部署后可用”。
4.3 P3 亮点
P3-1 OrdersDAO 把状态机、时间戳、历史记录、交付触发收敛到一条主写路径
证据
data/orders/dao.py::transition_status()单事务处理:状态校验、状态更新、history、时间戳delivered且交付物齐备时会顺带落delivery_notifications
评价
这是当前仓库最稳的边界之一。它明显优于把状态历史散落在各个 route/service 中维护。
P3-2 FastAPI app 装配较整洁,配置校验与 schema 初始化集中在启动期
证据
admin/app.py::create_app()结构清晰_validate_and_log_settings()对 JWT / 默认管理员密码做环境分级处理_setup_database()统一做 schema/bootstrap
评价
应用装配层没有明显失控,是后续继续治理的好基础。
P3-3 管理员密码与分享密码使用 PBKDF2 + 随机盐 + 恒时比较
证据
admin/password.pydata/share/short_link.py
评价
密码存储方案比很多轻量项目更稳,属于正向设计。
P3-4 登录失败统一口径,且已有基础限流
证据
admin/routes/auth.py以username@client_ip做失败计数与retry_after- 普通错误统一返回
AUTH_INVALID_CREDENTIALS
评价
已具备最低限度的暴力破解缓解与账户枚举抑制。
5. 验证与复核结果
5.1 命令复核
在仓库根执行了以下检查:
python3 -m pytest admin/tests tests data -q
python3 -m ruff check . --exclude .venv,.worktrees
python3 -m mypy .
python3 scripts/check_coverage_gate.py coverage.xml
./.venv/bin/python -m pytest admin/tests tests data -q
./.venv/bin/python -m ruff check . --exclude .venv,.worktrees
./.venv/bin/python -m mypy .
./.venv/bin/python scripts/check_coverage_gate.py coverage.xml
5.2 观察到的结果
- 系统 Python 环境缺少
pytest / ruff / mypy,全局命令不可直接复现。 .venv环境下:pytest: 639 passed, 5 failed- 失败主要来自:
tests/test_delivery_dispatcher.pytests/test_retention_cleanup.pytests/test_t5_performance.py
- 失败原因并非随机:
- 若测试通过
subprocess.run(["python3", ...])启动脚本,脚本会落到系统 Python,随后因admin.__init__ -> admin.app -> import uvicorn报ModuleNotFoundError: uvicorn locust可执行文件缺失,导致性能测试无法启动
- 若测试通过
ruff check:通过mypy:未见硬错误输出,但存在 8 条annotation-unchecked提示,集中在测试文件scripts/check_coverage_gate.py coverage.xml:失败,报missing core coverage entries,说明当前 coverage artifact 与 gate 脚本的核心文件映射未对齐。
5.3 这组结果说明什么
- 项目不是“完全不可测”,因为大部分测试可在
.venv中通过。 - 但它也不是稳定可复现的验证闭环:
- 脚本子进程环境与测试 runner 环境脱节
- 性能验证依赖工具未稳定声明/注入
- coverage gate 与覆盖率产物不一致
这与前述 P1/P2 结论一致:系统已有工程基础,但门禁可信度仍不够强。
6. 优先级建议
第一优先级(立即处理)
- 修复支付 webhook 的双写一致性问题
- 补齐删除/匿名化的真实覆盖范围,统一 delete vs anonymize 语义
- 补强真实支付宝回调业务校验
- 修复 webhook server 的全局 DB 连接污染问题
- 统一 coverage / CI / 本地 gate 口径
第二优先级(短期完成)
- 完成退款主状态闭环
- 把分享权限改为 allowlist,而不是 edit/admin 全量透传
- 拆分 portal secret 与 admin JWT secret
- 为 payment webhook secret 增加生产环境启动门禁
- 把渠道同步彻底 cutover 到
OrdersDAO.upsert_by_external_id()
第三优先级(中期治理)
- 把交付状态拆成“已验证可投递”与“真实已发送”
- 补真实 restore drill / Docker 业务冒烟 / 监控告警最小闭环
- 收紧 pytest 入口,明确 unit/integration/e2e 语义边界
7. 最终判断
如果问题是:
这个仓库有没有认真做工程?
答案是:有,而且部分核心边界(尤其 orders DAO / 状态机)做得不错。
如果问题是:
这个系统是否已经达到“关键闭环可信、合规表述稳妥、验证链稳定、运维可托底”的严格标准?
答案是:还没有。
更准确的表述应当是:
这是一个已经具备明显产品化骨架、但仍处于“关键一致性 / 支付安全 / 删除合规 / 验证闭环 / 灾备落地”强化期的系统。当前适合继续收敛与修复,不适合对外宣称为完全成熟闭环。