Files
lovife 50ad577b29 fix(cors): 修复生产登录 403「Invalid CORS request」
- 根因:浏览器对**同源**的 POST/PUT/DELETE 也会带 Origin,而 Spring MVC 只看
  "请求里有没有 Origin"(Spring 7.0.9 的 DefaultCorsProcessor 没有同源短路),
  带了又不在白名单里 → 进 Controller 之前直接 403
- WebConfig 的白名单写死为 localhost/内网;注释声称"生产配置见 application-prod.yml
  的 fill.cors.allowed-origins",但该属性根本不存在、也没人读它 ——
  于是"前后端同源部署"的登录/上传/提交必然登不上(生产 2026-10-20 事故)
- 改为配置驱动:FillProperties.Cors + fill.cors.allowed-origins
  (可用 XT_CORS_ALLOWED_ORIGINS 覆盖);prod 默认
  shenxue.jxit.com / admin.shenxue.jxit.com / *.shenxue.jxit.com;
  dev 补上花生壳穿透域名(H5 走穿透时 POST 同样会被拦)
- 启动日志打印生效白名单,排障先看那一行
- 新增 CorsWhitelistTest(3 条):生产 yml 真能绑定、通配符匹配租户子域、陌生源仍被拒
- docs/09 §2.4:本站地址必须在白名单 + 反代必须传
  Host/X-Real-IP/X-Forwarded-For/X-Forwarded-Proto(缺了登录日志 IP 全是 127.0.0.1);
  交接摘要 §一·四十四 记录事故,并写清"1700+ 条 e2e 全绿为什么还是漏了"

为什么 e2e 没抓到:脚本是 Python requests,不带 Origin 头,永远走不到 CORS 分支;
本地浏览器用的 localhost 正好命中写死的 dev 白名单。唯一能暴露它的是"浏览器 + 正式域名"。

验证:生产白名单下 admin / 主域名 / t1 / t12 → 200,evil / 后缀拼接 / http → 403;
真实 RSA 登录 + Origin: https://admin.shenxue.jxit.com → 200、code=0、拿到 token;
mvn test 15/15;verify-all --quick 6/6;check-test-profile 通过。
接口、库表、契约均无变化。
2026-10-20 09:22:16 +08:00

15 KiB
Raw Permalink Blame History

交付计划与进度

项目:深学在线 起始:2026-09-28 状态:进行中


一、当前已交付

# 交付物 版本 状态
— 主 PRD(含库表设计、接口清单、15 条校验规则、18 张表 DDL) V2.3 ✅
— 功能逻辑卷(纯功能运转逻辑,不含库表/接口/代码) V1.9 ✅
— PostgreSQL 建表脚本 — ✅ 已在 PG 16 实测通过
— 学生端原型(10 屏) V1.3 ✅(原 STEP 03B「申请加入名单」已于 2026-10 需求收敛删除)
— 班主任端原型(9 屏) V1.1 ✅
— 管理端 PC 原型(10 屏) V1.3 ✅ 含表单设计器/材料规则/角色与授权(整理器与申请审批两屏已于 2026-10 删除)

二、待执行计划

排序原则:先解阻塞,再补设计,最后备交付。 客户确认链是最长的外部依赖,必须最先发出去。

阶段一 · 打通确认链

# 任务 产出 为什么这个顺序 状态
P1 客户与认定机构确认函 01-客户与机构确认函.md 外部依赖最长。5 项高优先级阻塞开发(300dpi 能否接受、名单外的人怎么办、社会收集名单从哪来…),越早发出越早回来 ✅
P2 需求追溯矩阵 02-需求追溯矩阵.md 自审:把 PRD 需求 ↔ 原型屏 ↔ 库表 ↔ 接口 逐条对应,找出说了没做/做了没说的缺口。放在接口文档之前,避免接口漏做 ✅
P2.5 管理端补充原型(矩阵审计追加) 追加到 admin-web.html 矩阵发现 3 个 P0/P1 复杂交互页面未出原型:表单设计器、材料规则配置、历史整理器(该屏已于 2026-10 随模块删除)。不画出来开发必理解偏 ✅

阶段二 · 补齐技术设计

# 任务 产出 说明 状态
P3 接口设计(OpenAPI) 03-接口设计.md PRD §8 已有 96 个接口清单,但缺完整请求/响应字段定义。补齐后前端可 mock、后端可并行开工。含补追溯矩阵发现的 21 个缺口 ✅
P4 核心模块设计说明 04-核心模块设计说明.md 6 个模块的伪代码级说明:M1 命名 / M2 压缩 / M3 识别 / M4 门禁 / M5 校验 / M6 导出;含依赖图、开发顺序、Golden 基线 ✅

阶段三 · 交付准备

# 任务 产出 说明 状态
P5 开发任务拆解(WBS) 05-开发任务拆解.md 8 个里程碑拆到可派工粒度(94 个任务 / 380 人日 / 工期 14 周),含关键路径、8 项风险、团队配置、3 个客户演示点 ✅
P6 验收测试清单 06-验收测试清单.md 29 条 Golden 断言(可直接自动化)+ 85 条功能验收 + 20 条异常边界 + 9 项性能 + 12 项安全 + 签署表 ✅
P7 文档导航(README) ../README.md 统一入口:按角色读法、三分钟看懂产品、关键决策速查、快速上手 ✅

三、执行记录

时间 任务 结果
2026-09-28 立计划 7 项,分三阶段
2026-09-28 P1 确认函 完成 01-客户与机构确认函.md:23 项待确认按拍板方分 4 组(认定机构 6 / 客户业务 9 / 商务法务 5 / 内部技术 7);每项给出建议默认值,客户不回复也能推进;附 9 条已闭环决策表防止反复讨论
2026-09-28 P2 追溯矩阵 完成 02-需求追溯矩阵.md。审计发现:① 修正统计口径——实际 115 条 FR(83 P0/29 P1/3 P2)+ 17 条 VAL,此前漏算加粗编号;② 10 个接口缺口(报考范围、整理器、字典、日志、消息中心、订阅额度、审核撤回、任务暂停…);③ 管理端 10 个原型页面缺口,其中表单设计器为 P0;④ 4 个疑似需求问题中 3 个是脚本正则缺陷、1 个为真(已补 FR-616);⑤ 追加 P2.5 补 3 个复杂交互页面原型
2026-09-28 P2.5 补充原型 管理端 admin-web.html 由 7 屏扩至 10 屏:⑧表单设计器(字段库/画布/属性三栏 + 条件规则行,内置字段带锁不可删)⑨材料规则配置(材料清单侧栏 + 命名模板 + 档位选择 + 来源引导语)⑩历史数据整理器(用真实实测数字:475MB→37MB、59 项命名违规、仅 1 项需人工)。四份原型全部通过结构校验
2026-09-28 P6 验收测试清单 完成 06-验收测试清单.md(25KB / 518 行)。把 P4 的 15 项基线转成 29 条可自动化断言 G-01~G-29;另含 3 条端到端主流程(32 步)、20 条异常边界、85 条功能验收、6 条视觉、9 项性能、12 项安全;含里程碑签署表与 7 条 Go/No-Go 条件;点出 3 个易漏盲区(Windows 解压中文名 / 并发绑定临界窗口 / 「无」是合法值)
2026-09-28 客户回执(⚠️ 唯一增量 B1 已于 2026-10 需求回退取消) 客户确认全部 23 项按建议执行,需求冻结。识别出唯一功能增量 B1(申请加入名单),其余 22 项零改动
2026-09-28 D7 降级 重新评估「文件名识别真实准确率」这个待办:因输出命名取自名册、归属靠证件号反查名册、识别有槽位兜底、失败一律放行,该指标不影响任何交付项。降级为「上传页引导文案校准」——班主任在群里问两句即可,取消样本索取。至此全部外部数据依赖清零
2026-09-28 范围收窄 客户确认「先做学校内的填报流程」→ 只做学校收集 + 自主认定(4 类材料全部有实测样本);社会收集 / 社会评价 / 专项职业能力不做(2026-10 进一步明确为取消,不再叫"后置二期"),数据结构与枚举保留不启用。工期 −5 人日(392→387),关键路径不变仍 15 周
2026-09-28 移除联系方式展示 客户指出"学生本来就有班主任联系方式,不需要系统里面体现"。删除 GET /mp/roster/contact 接口 + 门禁失败页「联系老师」按钮。接口总数 122 → 121。⚠️ 当时保留的两条系统内动作里,「申请加入名单」已于 2026-10 撤销,现在只剩「重新填写」+ 一句"请联系老师"
2026-09-28 归属校验修正 客户指出"系统不存在名称错误"——纠正原设计中「把文件名不符自动按名册修正」的缺陷(会把传错的文件静默洗白)。改为 VAL-21 文件归属校验 + 阻断提交;判定优先级重排为 证件号反查名册 > OCR > 姓名(仅辅助);姓名不再作为独立规则。另补全「社会评价」定义与 cert_type 第三取值
2026-09-28 B1 落地 新增 FR-509 系列 10 条 / collect_join_request 表(PG 16 实测通过 + 部分唯一索引业务规则验证)/ 5 个接口 / 错误码 40037~40042 / 学生端 STEP 03B + 管理端 STEP 11 两屏原型 / F-509 验收项 19 条 / WBS 新增 6 个任务
2026-09-28 P7 文档导航 完成 ../README.md(10KB)。按角色给出读法、三分钟看懂产品、13 条关键决策速查、目录结构与快速上手、数据基线、两条踩坑教训
2026-09-28 P5 开发任务拆解 完成 05-开发任务拆解.md(27.6KB / 468 行)。94 个任务 / 380 人日 / 含缓冲 456,工期 14 周。关键结论:工期由关键路径(67 人日串行)决定,不能按人日总数摊人;压缩周期只能砍范围不能加人。含 3 个客户演示点(A 第 5 周 / B 第 10 周 / C 第 14 周)与 §9 可复现核算口径
2026-09-28 P4 核心模块设计 完成 04-核心模块设计说明.md(54KB / 1218 行)。六个模块全部伪代码级:M1 命名(含证件号三源裁决表)、M2 压缩(五档+二分降质+二次有损防护)、M3 识别(四层递进+成本闸)、M4 门禁(并发绑定必须 UPDATE...WHERE bind_user_id IS NULL)、M5 校验、M6 导出(快照先固化+中文文件名编码)。校验中发现并修正三处真问题,见下条教训
2026-09-28 P3 接口设计 完成 03-接口设计.md(102KB / 2626 行)。117 个接口全部字段级定义(PRD 原 96 + 新增 21);新增 §2 枚举全集(含「无」的三条铁律)、§3 通用数据结构(12 个 VO,字段名与 DDL 列一一对应)、§15 错误码全集(50 个,新增 30);自校验通过:模块表合计=声称=实际唯一数=117,无真重复,引用字段名 116 个全部存在于 DDL
2026-10-09 验收走查后的四项修正 ① 去掉 3 条无用菜单(名单管理 / 表单设计器 / 材料规则)—— 功能都在「收集任务」行内入口,菜单里那一条只是指路;后端菜单键同步删除;② 修掉班主任点工作台必弹 403(工作台无条件调了要 org:view / progress:viewAll 的两个接口,班主任都没这两个权限)→ 改为按权限决定发不发请求;③ 新增请求头 X-Tenant-Id(§1.2):平台运营的「组织架构 / 账号管理 / 工作台」原先拿到的是所有租户混在一起的数据,现在必须先在页面上选定学校;④ 修掉开放接口的"推送重试"从未生效(F-112:定时扫描缺 @InterceptorIgnore,异常被 warn 吞掉;E2E 补了"真的重试了"的断言)。详见 交接摘要 §一·三十三
2026-10-09 二期「角色与授权」上线(FR-205) 内置角色只读 + 自定义角色的权限码 / 菜单可配:新增 8 个接口(docs/03 §4.12 / §5.10,契约总数 121 → 129)、V18 迁移(sys_role.user_type + sys_role_menu)、错误码 40045;权限判定从"零 IO"改为"内置按代码 / 自定义按库 + Redis 缓存";新增每日内置角色授权同步(修掉代码与库的静默漂移);PC 新增「角色与授权」页(原型 ⑪)→ ready:false 的菜单归零;账号页的可选角色 / 用户类型 / 角色名全部改读库(删掉前端三份写死的镜像表)。验证:新增 scripts/e2e-m10-role.py 77 条、verify-all --with-e2e 全绿。「数据范围可配」仍是下一批(见 docs/05 M8 的说明)
2026-10-20 修生产登录 403「Invalid CORS request」 生产 POST /api/v1/auth/login 返回 403:浏览器的同源 POST 也带 Origin,而 Spring 只看"有没有 Origin",WebConfig 的 CORS 白名单却写死成 localhost/内网(注释声称读 fill.cors.allowed-origins,该属性其实不存在)。改为配置驱动:FillProperties.Cors + 各 profile 的 fill.cors.allowed-origins(可用 XT_CORS_ALLOWED_ORIGINS 覆盖),生产默认含 admin.shenxue.jxit.com 与 *.shenxue.jxit.com,启动日志打印生效名单。接口 / 库表 / 契约均无变化。docs/09 新增 §2.4:本站地址必须在白名单 + 反代必须传 Host/X-Real-IP/X-Forwarded-For/X-Forwarded-Proto(缺了登录日志 IP 全是 127.0.0.1)。详见 交接摘要 §一·四十四

三、客户回执(2026-09-28)

客户全部 23 项按建议方案确认。 详见 01-客户与机构确认函.md 的客户回执章节。

组 项数 需开发 结论
A 认定机构 6 0 全部与现有设计一致(当初就按实测数据设计)
B 校方业务 9 1(⚠️ B1 已于 2026-10 需求回退取消) 仅 B1(申请加入名单通道) 是功能增量,该通道已于 2026-10 删除
C 商务法务 5 0 C1 小程序资质按建议推进 + H5 保底
D 内部技术 7 0 D4 已随"取消二期"作废、D7 已降级清除;仅 D6(微信三条来源通道体积上限)需真机自测,无外部依赖

一期范围(客户确认后收窄):只做 学校收集 + 自主认定(4 类材料全部有实测样本)。 社会收集 / 社会评价 / 专项职业能力不做(2026-10 取消,不再是"后置"),数据结构与枚举保留不启用。 ⇒ D4(社会评价样本)因此不再是待办;工期 392 → 387 人日,关键路径不变仍 15 周。

本次变更(V1):新增 FR-509 系列(10 条)+ 1 张表(collect_join_request)+ 5 个接口 + 2 屏原型。

指标 变更前 变更后
FR 总数 115 125
接口总数 117 121(2026-10 收敛后为 119)
库表 19 20
VAL 规则 20 21(新增 VAL-21 归属校验)
错误码 50 57
原型屏数 29 31
任务数 94 100
人日 380 392 → 387(一期收窄 −5)
工期 14 周 15 周

四、已知风险(跟踪中)

# 风险 影响 对策
R1 客户迟迟不确认 P1 的 5 项高优先级问题 — ✅ 已解除:客户确认全部 23 项按建议执行,需求已冻结
R2 强特征词表未在"社会评价"批次数据上标定 — ✅ 已消除(2026-10 取消二期)
R3 VLM 选型未定 中 P4 中把 VLM 抽成可替换接口,不绑定供应商
R4 二期启动时缺少社会评价样本 — 已消除(2026-10 取消二期,不再需要该样本)

2026-10 需求收敛(执行记录)

项 内容
起因 客户认为功能面过宽,要求收敛为「总后台开学校 → 学校管理员发任务 → 学生填 → 班主任 + 学校管理员审 → 归档导出 ZIP」
删除 ① 内置角色 6 → 4(删副班主任 DEPUTY_TEACHER、审核员 AUDITOR,存量账号由 V19 迁移处理);② 历史整理器(module/cleanup,5 接口 + cleanup:run + collect_cleanup_job 表 + PC 页 + 原型屏);③ 加入申请(module/join,5 接口 + join:audit + collect_join_request 表 + PC 页 + 学生端 pages/join + 错误码 40037/40038/40039/40040/40042 + 两个站内信模板);④ collect_task_org.deputy_user_ids 整列(审核范围三级回退 → 两级)
取消 二期整体取消:社会收集 / 社会评价 / 专项职业能力 / 数据范围可配 / 角色变更即时失效 / 平台角色页 → 不做;OCR 与材料识别 → 缓做,等供应商选型;材料模板 3 → 1;XJW_BA/OTHER_PROOF 读得到、选不到
数字 接口 129 → 119、错误码 59 → 54、权限码 30 → 28、PC 菜单 12 → 10、小程序页面 10 → 9、原型 32 → 29 屏、E2E 脚本 39 → 37
迁移 V19__remove_deputy_auditor_cleanup_join.sql(先解绑定再软删角色;账号只在"除这两个角色外没有别的角色"时软删)
⚠️ 治理 加入申请(确认函 B1)是客户唯一确认的功能增量,本次属需求回退,建议补变更确认单
详见 docs/交接摘要.md §一·三十六(含 5 条新增防线与 PC 端重搭说明)