一期范围:学校收集 + 自主认定(4 类材料全部有实测样本) - 主 PRD 190KB:125 条 FR / 21 条 VAL / 20 张表 DDL / 121 个接口 - 功能逻辑卷 88KB:不含代码模块 - 接口设计 116KB:58 个错误码 / 12 个 VO - 核心模块设计:M1 命名 / M2 压缩 / M3 识别 / M4 门禁 / M5 校验 / M6 导出 - 开发任务拆解:100 任务 / 387 人日 / 15 周 - 验收测试清单:36 条 Golden 断言 / 111 条功能验收 - PostgreSQL DDL:已在 PG 16.15 实测零错误 - 交互原型 31 屏:学生端 11 / 班主任端 9 / 管理端 11
15 KiB
交接摘要
用途:压缩后的唯一状态源。新会话读这一份即可接续,不必回看历史对话。 更新:2026-09-28
一、项目一句话
职业技能等级认定报名材料收集 SaaS。学生在微信小程序填报、班主任在手机初审、管理员在 PC 终审与导出。核心价值:动态表单 + 规则引擎(命名/压缩/识别)+ 门禁核验 + 一键规范导出。
工作目录 D:\IDEA_Project\xiaotutongxue(空 git 仓库,无 commit,全部改动未提交),交付物在 docs/。
一·二、一期范围(2026-09-28 客户确认收窄)
一期只做「学校收集 + 自主认定」一条流程。 详见 PRD「一期范围声明」。
| 维度 | 字段 | 一期 | 二期后置 |
|---|---|---|---|
| 收集模式 | collect_mode |
1 学校收集 |
2 社会收集 |
| 认定类型 | cert_type |
1 自主认定 |
2 社会评价 / 3 专项职业能力 |
一期材料只有 4 类,全部有实测样本:一寸照片 / 身份证 / 学籍表 / 工作证明
二期才做的 2 类材料零样本:XJW_BA 学信网备案表 / OTHER_PROOF 其它佐证材料
数据结构保留不启用(二期直接开,不需 DB 迁移)——因为这三项本来就是配置驱动的
(needClassAudit 是开关、字段隐藏走 visibleWhen、材料差异是材料项配置),
所以省下的主要是测试成本与一个外部依赖,而不是代码量。
工期:392 → 387 人日(−5);关键路径不变,仍 15 周。
⚠️ 二期启动前必做:索取社会评价样本(D4)→ 标定
XJW_BA/OTHER_PROOF→ 补社会收集审核流与专项职业能力字段隐藏。
一·五、客户回执(2026-09-28 · 需求已冻结)
客户全部 23 项按建议方案确认。 唯一功能增量是 B1:名单加入申请通道。
| 组 | 需开发 | 说明 |
|---|---|---|
| A 认定机构 6 项 | 0 | 与现有设计完全一致(min_long_side=1400、min_quality=70、PNG 保留等都是当初按实测设计的) |
| B 校方业务 9 项 | 1 | B1 已落地:FR-509 系列 + collect_join_request 表 + 5 接口 + 2 屏原型 |
| C 商务法务 5 项 | 0 | C1 小程序资质推进中,H5 保底已列入 M0-13 预研 |
| D 内部技术 7 项 | 0 | D4 已后置为二期(一期不涉及零样本材料);D7 已降级(文件名识别准确率不影响任何交付项,残留只是上传页文案校准,班主任群里问两句即可)。均已清除,无外部依赖 |
规模变化:FR 115 → 125 / 接口 117 → 121 / 库表 19 → 20 / VAL 20 → 21 / 错误码 50 → 57 / Golden 断言 29 → 36 / 功能验收 85 → 111 / 原型 29 → 31 屏 / 任务 94 → 100 / 人日 380 → 392 → 387(一期收窄 −5)/ 工期 14 → 15 周。
B1 的设计要点(三条边界,不要在后继开发中放水)
| # | 边界 | 理由 |
|---|---|---|
| 1 | 只解决"进名单",不绕过门禁 | 申请期间仍不能填报;审批通过后才自动绑定放行 |
| 2 | 证件号与手机号仅存 HMAC + 脱敏值 | 与门禁口径一致 |
| 3 | 驳回必须逐条填原因;批量通过不提供"全选" | 身份认定环节误操作代价极高 |
二、已锁定的铁律(不要重开讨论)
| # | 决策 | 关键理由 |
|---|---|---|
| 1 | 扫描件强制压到 ≤1M,无例外 | 认定机构硬要求 |
| 2 | 默认参数 300dpi / q85 | 实测 28/28 达标,平均 806KB,清晰度零损失 |
| 3 | 材料来源只有 聊天记录 / 相册 / 手机文件,「直接拍照」默认关闭 | 实测 4 类材料无一来自现场拍照 |
| 4 | 必须先导名单,姓名+身份证匹配不通过只提示、不放行(学校与社会收集皆然) | 门禁是产品根基 |
| 5 | 报考范围从名单聚合,不存在独立"计划清单"文件 | 真实名单验证 |
| 6 | 动态表单 = 内置字段(固定列,可统计)+ 扩展字段(extras_json,仅展示导出) | 兼顾统计能力与灵活性 |
| 7 | 数据库 PostgreSQL(纯 PG);软删除字段名为 deleted |
客户已确认 |
| 8 | 班主任端只做右滑通过,驳回必须点按钮 | 误触后果不对称 |
| 9 | 批量通过只带无问题项,红黄一律排除 | 防"手快全选" |
| 10 | 有不合格文件时直接禁用导出按钮,不允许带问题打包 | 铁律 |
| 11 | 识别策略 规则为主 + VLM 兜底(触发率 2%~10%) | 成本可控 |
| 12 | 识别失败一律放行,不得阻断提交 | 可用性优先 |
| 13 | 原型不用 emoji(→ ↔ · 等排版字符保留) |
设计约束 |
三、已完成交付物
| 文件 | 版本/大小 | 状态 |
|---|---|---|
docs/数据信息填报系统PRD.md |
V2.3 / 173KB / 2816 行 | ✅ 含 115 条 FR、17 条 VAL、96 接口、19 表 DDL、实测附录 |
docs/数据信息填报系统PRD-功能逻辑卷.md |
V1.9 / 88KB | ✅ 纯功能逻辑,不含库表/接口/代码 |
docs/db/schema-postgresql.sql |
34KB | ✅ PG 16.15 实测零错误(19 表 / 167 列注释 / 61 索引) |
docs/prototype/student-app.html |
11 屏 / 57KB | ✅ 含 STEP 03B「申请加入名单」 |
docs/prototype/teacher-app.html |
9 屏 / 63KB | ✅ |
docs/prototype/admin-web.html |
11 屏 / 114KB | ✅ 含表单设计器、材料规则配置、历史整理器、申请审批 |
docs/prototype/index.html |
7KB | ✅ 三端入口 |
docs/00-交付计划.md |
— | ✅ 7 项计划与进度记录 |
docs/01-客户与机构确认函.md |
18KB | ✅ P1 23 项已全部确认(客户按建议执行,需求冻结) |
docs/02-需求追溯矩阵.md |
10KB | ✅ P2 审计报告,含 10 个接口缺口 |
docs/03-接口设计.md |
102KB / 2626 行 | ✅ P3 117 个接口字段级定义 + 枚举全集 + 12 个 VO + 50 个错误码;自校验通过 |
docs/06-验收测试清单.md |
29KB | ✅ P6 36 条 Golden 断言 + 111 条功能验收 + 27 条异常边界 |
../README.md |
10KB | ✅ P7 文档导航,按角色读法 + 快速上手 |
docs/04-核心模块设计说明.md |
56KB / 1218 行 | ✅ P4 六个模块伪代码级说明 + 依赖图 + Golden 基线 |
docs/05-开发任务拆解.md |
28KB / 468 行 | ✅ P5 94 个任务 / 380 人日 / 14 周,含关键路径与核算口径 |
四、待办计划
| # | 任务 | 产出 | 状态 |
|---|---|---|---|
| 客户与认定机构确认函 | 01-客户与机构确认函.md |
✅ | |
| 需求追溯矩阵 | 02-需求追溯矩阵.md |
✅ | |
| 管理端补 3 屏原型 | 并入 admin-web.html |
✅ | |
| P3 | 接口设计(OpenAPI) | 03-接口设计.md |
✅ 已完成(117 个接口) |
| P4 | 核心模块设计说明(伪代码级) | 04-核心模块设计说明.md |
✅ 已完成(6 个模块) |
| P5 | 开发任务拆解 WBS(M0–M7) | 05-开发任务拆解.md |
✅ 已完成(94 任务 / 380 人日 / 14 周) |
| P6 | 验收测试清单(Golden Test Set) | 06-验收测试清单.md |
✅ 已完成(29 条 Golden 断言 + 85 条功能验收) |
| P7 | 文档导航 README | ../README.md |
✅ 已完成 |
P3 已补齐的缺口(21 个接口,原审计发现 10 项)
✅ I1 报考范围读取/确认 GET/PUT /api/v1/tasks/{id}/plan-scope
✅ I2 历史数据整理器 POST /api/v1/cleanup/jobs(共 5 个)
✅ I3 字典管理 /api/v1/dicts(4 个)
✅ I4 操作日志 GET /api/v1/logs/operations
✅ I5 登录日志 GET /api/v1/logs/logins
✅ I6 消息中心 /mp/messages、/mp/messages/read、/mp/teacher/messages
✅ I7 订阅额度登记 POST /api/v1/mp/subscribe
✅ I8 审核撤回 POST /api/v1/audit/submissions/{id}/revoke
✅ I9 任务暂停/恢复 POST /api/v1/tasks/{id}/pause、/resume
✅ I10 材料识别结果读取 已并入 GET /api/v1/audit/submissions/{id} 响应
➕ 文件规范化 process 原仅在 PRD §8.9 详述、未登记进清单,已补登
接口总数:96(PRD 原有)+ 21 = 117
五、关键事实速查
真实基准数据集(Golden Test Set)
D:\项目\202609机电填报系统\24中技数控1班\ —— 28 人 × 4 类材料 = 112 文件
| 实测项 | 结果 |
|---|---|
| 原始总量 | 475 MB |
| 命名违规 | 59 / 112(52.7%) |
| 双扩展名 | 56 |
| 体积超标(>1M) | 31 |
| 证件号异常 | 5 例(3 可自动、2 待人工) |
| 疑似串档 | 1(唯一必须人工判断的) |
| 压缩后 | 300dpi/q85 → 平均 806KB、最大 831KB、0 张超标 |
| 材料识别 | 文件名层 112/112;形态层 99.1%;OCR 内容层 32/32 |
官方模板要点
- 21 列(A–U):红=必填 11 项、绿=级联 6 项、黑=选填 4 项
- 「报考职业」「报考工种」在 Excel 里没有下拉,是自由填写 ← 我方产品的核心增量
- 「职业技能等级个人申报表」的规范文件名却是 「工作证明」(机构既有习惯)
- 表头行与工作表名都不固定(实测一份在第 1 行、一份在第 6 行)
三个易错实现陷阱
- 「无」是合法业务值,不是空值
- 专项职业能力:无工种 / 无等级 / 无补考科目(0 科)
- 补考约束:三/四/五级最多 1 科,一/二级最多 2 科,专项 0 科
压缩五档(PRD §6.3)
A4 扫描件 300dpi(2480×3508)/q85 · 一寸照片固定 295×413 · 学籍表为 16:9 截图保持 PNG 不缩放
教师端数字口径(原型必须自洽)
28 人 = 已通过 15 + 待审 4 + 待核对 3 + 有问题 1 + 未提交 5;完成率 82% 是已提交率(23/28)
六、环境与工具
| 项 | 内容 |
|---|---|
| PG 验证容器 | docker exec -it pg-verify psql -U postgres -d filldb;清理 docker rm -f pg-verify |
| 原型校验脚本 | python C:\Users\93292\AppData\Local\Temp\opencode\check2.py <html路径> |
| DDL 同步方式 | 从主 PRD 的 ```sql 代码块自动抽取生成,改文档后重跑抽取脚本 |
| 原型约束 | 单文件自包含、零外部依赖、内联 SVG(<symbol>+<use>,1.7px 描边 currentColor)、无 emoji |
| 原型校验基线 | 四份全通过:标签配对 ✓ / CSS 变量 ✓ / SVG 无冗余 ✓ / emoji 0 ✓ |
七、重要教训
教训一:脚本审计前必须先验证脚本本身
P2 审计时脚本因未匹配加粗编号 | **FR-614** |,误报 3 个"需求条目问题"(实为假警报);若直接采信并"修复",会引入 3 处新错误。同时 FR 总数由误算的 102 修正为 115。
教训二:写新文档必须回查已有编号体系,不能凭记忆
P4 写 M5 校验引擎时,我凭记忆用了一套 VAL 编号,与 PRD 权威清单整体错位:
| P4 原写法 | 我以为的含义 | PRD 实际定义 |
|---|---|---|
| VAL-01 | 姓名与名册一致 | 证件号格式与校验位 |
| VAL-03 | 证件号格式 | 姓名与名册一致 |
| VAL-06 | 双扩展名 | 文件格式白名单 |
| VAL-07 | 多扩展名冲突 | 文件体积上限 |
后果:若不修正,开发按 P4 实现会把规则完全接错,且两份文档互相矛盾。 修正:已全部重映射到 PRD 体系(单次扫描替换避免 01↔03 碰撞),并给 PRD 补了 P4 需要的三条新规则 VAL-18 文件名规范化 / VAL-19 疑似串档 / VAL-20 体积下限保护。 规则:新增文档引用任何已有编号(FR/VAL/错误码/接口)前,先脚本抽取权威清单核对,不凭记忆。
教训三:系统里的数据不会错,错的一定是「归属」
客户指出:"系统应该不存在名称错误的情况。是先录入了有这个姓名和身份证,然后才能填写的。"
这指出一个真实的设计缺陷:
| 位置 | 会不会错 | 说明 |
|---|---|---|
| 填报单里的姓名/证件号 | 永远不会错 | 门禁已核验 + 字段锁定。客户说得对 |
| 文件名里的姓名/证件号 | 可能不同 | 但这不是"名称错误",而是"这份文件可能不属于这个人" |
原设计的错误:把"文件名姓证件号与名册不符"处理为「自动按名册修正」(信息级), 这会把"A 传了 B 的材料"静默洗白成 A 的材料——审核时完全看不出来,事后无从追溯。
学生 A 在微信里误选了同学 B 的材料
↓ 文件名:李四-3610...(B 的号码,校验位通过)
错误做法:判"与名册不符" → 改成 张三-3610... → 信息级,A 看不到
↓ 审核:班主任看到一份名字正确的材料 → 通过
↓ 最终:B 的工作证明被认定成 A 的 ← 灾难
修正(客户已确认):
- 判定优先级重排为
证件号反查名册 > OCR 内容 > 姓名(仅辅助) - 新增 VAL-21 文件归属校验:归属存疑一律阻断提交,且不提供"仍然继续"
- 姓名不再作为独立规则——只在证件号佐证时按名册取值,仅留痕不打扰学生
- 核心判据:文件名证件号能否在名册里反查到"另一个人"(一次查询,走唯一索引,< 1ms)
精髓在于两条的区分:
- 校验位失败 = 不是一个真实号码 → 只是写错了 → 可以自动改
- 校验位通过 = 一个真实存在的自然人 → 改了就是改了身份 → 必须阻断
教训五:联系方式不进系统
客户指出:"学生本来就有班主任联系方式,不需要系统里面体现。"
原设计在门禁失败页放了一个「联系老师」按钮(脱敏手机号 + 一键拨打),并为此专门开了一个接口 GET /mp/roster/contact。
已移除:
| 移除项 | 原因 |
|---|---|
GET /mp/roster/contact 接口 |
不必要(用户已知道怎么找人)+ 有维护成本(换人/换号要同步)+ 多一处隐私暴露面 |
| 门禁失败页「联系老师」按钮 | 同上。改为只保留两条系统内动作:重新填写 / 申请加入名单 |
| 功能逻辑卷中的联系方式展示描述 | 同步 |
保留:纯文案提示(如"如有疑问请联系老师")——不涉及任何联系方式数据。 接口总数:122 → 121。
教训四:「社会评价」与「社会收集」只差一个字
cert_type(认定类型:自主认定 / 社会评价 / 专项职业能力)决定填什么材料;
collect_mode(收集模式:学校收集 / 社会收集)决定谁审核。二者可任意组合,已在 PRD §5.3 与接口 §2.3 分别写明。
另外补全了 cert_type 的第三个取值(专项职业能力)在 DDL 注释与附录中的遗漏。
附带修正
- 体积口径:原型导出中心曾写"475MB → 22.4MB(95%)",与 PRD 及历史整理器屏(37MB/92%)矛盾。实为混淆——444→22MB 是"工作证明"单项,475→37MB 是全班 112 文件合计。已统一为 37MB / 92%。
八、外部依赖(未回)
01-客户与机构确认函.md 已发出待回,其中最高优先级 3 项:
- A1 认定机构是否书面接受 300dpi 扫描件
- B1 名单外的人怎么处理(建议加"申请加入名单→管理员审批"通道)
- B3 是否允许学生修改老师预填字段(建议:姓名/证件号/报考三项锁定,其余可改留痕)
未回复则按文档内建议方案推进。