docs: 同步交接摘要 / PRD / 原型,并记录品牌改名「深学在线」

- 交接摘要补 §一·三十五~§一·三十八:角色与授权、需求收敛(4 角色 / 10 菜单 / 取消二期)、
  PC 端重搭后的 UI 修复与卡片式基线、品牌改名与新标识
- PRD 与功能逻辑卷只改标题行与产品代号线;**文件名不动** —— verify-docs.py 按路径读,
  全库还有 20+ 处按文件名引用,改名会连带炸脚本
- 原型 index / admin-web / teacher-app / student-app 的品牌区改「深学在线」,
  admin-web 的 .mark(10 处)换成内嵌的新标 data URI,保持原型"单文件自包含"的约定
- 根 AGENTS.md 与 frontend-pc 的规范同步:接线检查补第 ⑨ 项(SVG 资产是不是合法 XML ——
  SVG 注释里出现连续两个减号就 not well-formed,图标裂开而控制台一句话都不报)、
  「最容易写错的约定」6 -> 7 条(新增品牌标)
- deploy/docker-compose.yml 只改头注释里的项目名(compose 的 name 与七牛对象前缀都没动)
This commit is contained in:
2026-10-10 16:49:04 +08:00
parent 1f3c485ceb
commit 7df078e0ea
22 changed files with 1158 additions and 1093 deletions
+63 -73
View File
@@ -1,7 +1,7 @@
# 数据信息填报系统 PRD
# 深学在线 PRD
> 产品代号:**填报通 / CollectFlow**(暂定)
> 版本:V2.3(2026-09-28 明确滑动交互规则)
> 产品代号:**深学在线**
> 版本:**V2.5**(2026-10 需求收敛:**4 角色 / 10 菜单 / 不设二期**)
> 日期:2026-09-28
> 文档类型:产品需求文档(PRD)+ 数据库设计 + 接口清单
> 适用场景:职业技能等级认定报名材料收集(可扩展至各类"班级/单位材料收集"场景)
@@ -11,6 +11,7 @@
| 版本 | 日期 | 变更内容 | 变更人 |
|---|---|---|---|
| **V2.5** | **2026-10** | **需求收敛:删角色 / 删两模块 / 取消二期**。① 内置角色 **6 → 4**(删「副班主任 `DEPUTY_TEACHER`」与「审核员 `AUDITOR`」,存量账号由 **V19 迁移**处理);② 删「**历史数据整理器**」(FR-1400 系列 + §5.14 + `collect_cleanup_job` 表 + `cleanup:run`)与「**加入申请**」(FR-509 + §7.3.19 + `collect_join_request` 表 + `join:audit` + 错误码 `40037`/`40038`/`40039`/`40040`/`40042`);③ `collect_task_org.deputy_user_ids`(协办人)**整列删除**,审核范围三级回退 → **两级**;④ **不再有任何二期功能设计** —— 社会收集 / 社会评价 / 专项职业能力 / 数据范围可配一律**不做**,OCR 与材料识别改为「**缓做,等供应商选型**」;⑤ 材料类目 6 → 4(`XJW_BA`/`OTHER_PROOF` **读得到、选不到**)、内置材料模板 3 → 1。**数字**:接口 **129 → 119**、错误码 **59 → 54**、权限码 **30 → 28**、PC 菜单 **12 → 10**、小程序页面 **10 → 9**、原型 **32 → 29 屏**。⚠️ **加入申请(确认函 B1)是客户唯一确认的功能增量,本次属需求回退,建议补变更确认单**。 | 开发 |
| **V2.4** | **2026-09-28** | **修正 3 处加密列宽不足(DDL 缺陷,M0 实测暴露)**:`sys_tenant.contact_phone`、`sys_user.phone`、`collect_roster.phone` 原为 `varchar(20)`,是按<b>明文手机号</b>长度建的;但 §10.3 要求手机号 AES-256 加密存储,AES-GCM 密文约 <b>52 字符</b>,插入直接报 `value too long for type character varying(20)`。(`id_card_no` 当初给了 `varchar(128)` 就是考虑到了加密,手机号三列漏了——属设计不一致。)三列统一改为 <b>`varchar(128)`</b> 与 `id_card_no` 对齐。<br>**发现方式**:M0 开通租户实测时数据库报错暴露,非人工审查发现。<br>**审计结论**:其余 `*_mask varchar(32)` 列存的是脱敏值(如 `138****8888`)而非密文,宽度足够,无需改动。 | 开发 |
| V1.0 | 2026-09-24 | 初稿:背景/流程/功能/规则引擎/库表/接口 | 产品 |
| **V1.1** | 2026-09-24 | **复审修订**(用 112 个真实文件重新实测验证):<br>① **勘误**:命名违规率 98.2% → **52.7%**(59/112);双扩展名 55 → **56**;原始总量 436MB → **475MB**(436MB 实为 .rar 包体积);需处理并集 62 → **59**(原为重复计数)<br>② **推翻参数假设**:工作证明是 1272dpi A4 扫描件(非手机拍照)→ §6.3 压缩策略由"按长边"重写为"按材料形态分五档"<br>③ 学籍表是 16:9 截图 → 新增 P4 截图档,禁止缩放与转 JPG<br>④ 新增 §6.1 证件号裁决矩阵,人工量由 5 例降至 3 例<br>⑤ **新增风险 R11**(1.8 亿像素导致 OOM)、**R12**(微信订阅消息次数限制)<br>⑥ **补全 §9.4 班主任移动端页面清单**(初稿遗漏)<br>⑦ 修正 §1.4 指标口径混淆(班主任操作时长 vs 端到端周期)<br>⑧ 补充小程序隐私保护指引、DPA、KMS 等合规项<br>⑨ 补 `collect_task_org` 表、名册 `student_no` 字段、附录 D 错误码、附录 E 定时任务 | 产品 |
@@ -50,20 +51,21 @@
---
## 一期范围声明(2026-09-28 客户确认)
## 一期范围声明(2026-09-28 收窄 → 2026-10 收敛为最终口径)
> **一期只做「学校收集 + 自主认定」这一条流程。**
> 社会收集、社会评价、专项职业能力 **全部后置**;
> 但 **数据结构与枚举保留不启用**——二期直接开,不需要 DB 迁移。
> **只做「学校收集 + 自主认定」这一条流程**,且**不再设计任何二期功能**(2026-10 客户收敛)。
> 社会收集、社会评价、专项职业能力 **一律不做**:`collectMode=2` 与 `certType=2,3` 传入返回 **`40044`**。
> **数据结构与枚举保留不启用**(留着是因为这三项本来配置驱动、不增加维护成本),
> 但**没有"将来直接开"的承诺** —— 要用时按新需求重新评估。
### 范围切分
| 维度 | 字段 | 一期 | 二期后置 | 为什么这么切 |
| 维度 | 字段 | 本期做 | **不做**(已取消,不是"后置") | 为什么这么切 |
|---|---|---|---|---|
| **收集模式** | `collect_mode` | `1` 学校收集 | `2` 社会收集 | 一期只做一条审核流(学生→班主任→管理员),少一条分支、少一套测试 |
| **认定类型** | `cert_type` | `1` 自主认定 | `2` 社会评价<br>`3` 专项职业能力 | 后两者会引入**两类零实测样本的材料**,识别规则目前是推测 |
| **收集模式** | `collect_mode` | `1` 学校收集 | `2` 社会收集(传 2 → `40044`) | 只保留一条审核流(学生→班主任→管理员),少一条分支、少一套测试 |
| **认定类型** | `cert_type` | `1` 自主认定 | `2` 社会评价 / `3` 专项职业能力(传 2/3 → `40044`) | 后两者会引入**两类零实测样本的材料**,识别规则只能是推测 |
### 一期支持的材料(4 类,全部有 112 个真实文件实测)
### 支持的材料(4 类,全部有 112 个真实文件实测)
| 材料编码 | 名称 | 规范文件名示例 | 压缩档位 | 实测 |
|---|---|---|---|:--:|
@@ -72,49 +74,41 @@
| `SCHOOL_ROLL` | 学籍表 | `张三-3601...-学籍表.jpg` | P4 截图 | ✅ |
| `WORK_PROOF` | 工作证明 | `张三-3601...-工作证明.jpg` | P3 扫描件 | ✅ |
### 二期才做的材料(**零实测样本**)
### 不做、也**不再排期**的东西(2026-10 收敛)
| 材料编码 | 名称 | 出现在 | 现状 |
|---|---|---|---|
| `XJW_BA` | 学信网备案表 | 社会评价 | 强特征词是从**官方模板的文字要求**里抄的,**未见一张真实文件** |
| `OTHER_PROOF` | 其它佐证材料 | 社会评价 / 专项 | 含毕业证/社保单/职称/技能证书**四类版式完全不同**的东西,**可能不该做自动识别** |
| 项 | 现状 |
|---|---|
| `XJW_BA` 学信网备案表 / `OTHER_PROOF` 其它佐证材料 | 编码**保留**(历史数据读得到),但**选不到**(不在"新增材料"列表里);强特征词从未标定 |
| 社会收集审核流(跳过班主任初审) | **不做** |
| 专项职业能力的字段隐藏与校验绕过 | **不做** |
| 内置材料模板 `TPL_SOCIAL` / `TPL_ZHUANXIANG` | **已删除**,只剩 `TPL_SCHOOL_ROLL` |
| 原「后置清单」6 项(索取样本 / 标定特征词 / 报名点名单流程 / …) | **全部作废** |
### 后置清单(二期启动前要准备的事)
| # | 事项 | 依赖 |
|:--:|---|---|
| 1 | 索取「社会评价」批次原始材料样本(≥10 份,须含备案表与各类佐证) | 客户提供(D4) |
| 2 | 标定 `XJW_BA` 的强特征词与形态阈值 | ↑ |
| 3 | 决定 `OTHER_PROOF` 是否做自动识别,还是改为纯手动槽位 | ↑ |
| 4 | 实现社会收集审核流(跳过班主任初审,直达管理员) | 无 |
| 5 | 实现专项职业能力的字段隐藏(工种/等级/补考三项)与校验绕过 | 无 |
| 6 | 社会收集的名单来源流程(报名点/机构维护预报名名单) | 客户确认(B2) |
### 对现有设计的影响:几乎没有
### 对现有设计的影响:没有
**因为这三项本来就是配置驱动的**:
| 后置项 | 现有实现方式 | 代码改动量 |
| 项 | 现有实现方式 | 代码改动量 |
|---|---|---|
| 社会收集跳过初审 | `audit_config.needClassAudit` 是一个开关 | 0(只是一个配置值) |
| 专项职业能力的字段隐藏 | 走 `visibleWhen` 条件显示规则 | 0(配置一条规则) |
| 材料清单差异 | 材料项定义(`collect_material_def`) | 0(配置差异) |
> ⇒ **一期收窄省下的主要是「测试与联调成本」和「一个外部依赖(D4)」,而不是代码量。**
> ⇒ **收窄省下的主要是「测试与联调成本」和「一个外部依赖(D4)」,而不是代码量。**
>
> **工期影响**:**−5 人日**(392 → 387)。**关键路径不变,工期仍为 15 周。**
### 一期不做的验证项(从测试范围移除)
### 从测试范围移除的验证项
| 移除项 | 原因 |
|---|---|
| 主流程 B(社会收集,3 步) | 二期 |
| 主流程 B(社会收集,3 步) | 不做 |
| `XJW_BA` / `OTHER_PROOF` 的识别断言 | 零样本,无法定基线 |
| 专项职业能力的字段隐藏与 VAL-14/15 绕过用例 | 二期 |
| 社会收集的跳过初审用例 | 二期 |
| 专项职业能力的字段隐藏与 VAL-14/15 绕过用例 | 不做 |
| 社会收集的跳过初审用例 | 不做 |
> ⚠️ **二期启用时必须要补的回归断言**:`XJW_BA` / `OTHER_PROOF` 的识别准确率、社会收集审核流、专项职业能力字段隐藏。
> 这些都已在本文档与《06-验收测试清单》中保留描述,只是标注为二期。
> ⚠️ 若将来真要启用,**必须补**的回归断言:`XJW_BA` / `OTHER_PROOF` 的识别准确率、社会收集审核流、专项职业能力字段隐藏。
> 描述仍保留在本文档与《06-验收测试清单》里,但**不再标注为"二期"** —— 那会被误读成"已经排期了"。
---
@@ -283,7 +277,7 @@
| **规范名(Standard Name)** | 由命名规则引擎根据模板生成的最终文件名 |
| **初审 / 终审** | 班主任审核 / 管理员审核 |
| **汇总包(Export Package)** | 按目录规范打包后可直接上报的文件集合 |
| **历史数据整理器** | 对已存在的"乱文件夹/压缩包"做批量规范化与体检的独立工具 |
| ~~**历史数据整理器**~~ | **已取消**(2026-10):对历史乱文件夹做批量规范化与体检的独立工具,连模块/表/权限码/页面一并删除 |
---
@@ -501,7 +495,7 @@ DRAFT ──submit──▶ PENDING_CLASS ──班主任通过──▶ PENDING
| FR-307 | **报考范围自动聚合**:名单导入后自动提取"职业 × 工种 × 等级"集合 | **P0** |
| FR-308 | **名单一致性体检**:职业/工种矛盾、等级异常、漏填、拼写不符 → 输出体检报告 | **P0** |
| FR-309 | 报考范围支持管理员**手工修正**,并留痕(谁改的、改前改后) | **P0** |
| FR-310 | **专项职业能力**类型支持:自动隐藏工种、等级、补考相关字段 | ~~P0~~ **二期**<br>⚠️ 一期只做自主认定(见「一期范围声明」) |
| FR-310 | **专项职业能力**类型支持:自动隐藏工种、等级、补考相关字段 | ~~P0~~ **不做**(2026-10 取消二期;只做自主认定,见「一期范围声明」) |
| FR-311 | 追加名单时,若出现**范围外的新报考项**,必须告警并由管理员确认后才接受 | **P0** |
| FR-312 | 可选:接入国标职业字典做**拼写校验与联想建议**(仅辅助,不作强约束) | P2 |
@@ -725,7 +719,7 @@ DRAFT ──submit──▶ PENDING_CLASS ──班主任通过──▶ PENDING
| **FR-502a** | **名单即预填报名表**:名单 21 列的值全部入库(**18 个正式列 + 姓名/身份证号已有列**),学生端按"锁定/预填可改/学生必填"三类规则呈现(见 §5.3.1) | **P0** |
| **FR-502b** | **名单字段三类规则**:姓名+身份证号+报考职业/工种/等级 → **锁定**(名单为空则阻断发布);其余 → 有值则预填可改、无值则学生必填 | **P0** |
| FR-503 | **名单核验(门禁)**:填报人进入前必须填写「姓名 + 身份证号」匹配名单,命中才进入填报页;命中后绑定名单项 | P0 |
| FR-504 | **未命中统一提示**(不区分"号码不在名单"与"姓名不符",防探测),提供 **"重新填写"** 与 **"申请加入名单"(FR-509)** 两条出路;**取消原"自助认领"** | P0 |
| FR-504 | **未命中统一提示**(不区分"号码不在名单"与"姓名不符",防探测),只给 **"重新填写"** 一条系统内出路 + 一句"如确认已报名,请联系老师把你加入名单";**取消原"自助认领"与"申请加入名单"(FR-509)** | P0 |
| FR-504a | **匹配接口限流**:同 openid 每小时 ≤10 次、同 IP 每分钟 ≤20 次,超出锁定并提示 | P0 |
| FR-504b | 名单**不下发前端**,匹配全程在服务端完成;失败尝试不记录明文证件号 | P0 |
| FR-504c | 姓名形近字/同音字纠错:身份证号命中但姓名不符时,给出"你是不是 XXX?"让用户确认 | P1 |
@@ -734,7 +728,7 @@ DRAFT ──submit──▶ PENDING_CLASS ──班主任通过──▶ PENDING
| FR-506 | 名单变更留痕(谁在何时把 A 的证件号从 X 改成 Y) | P0 |
| FR-507 | **发布前校验**:名单人数 > 0 且必须含「姓名」「身份证号」列,否则阻断发布 | P0 |
| FR-508 | 名单追加导入(按证件号去重合并),**追加后新人立即可填报** | P0 |
| **FR-509** | **名单加入申请(客户已确认采纳的建议增量)**:门禁失败页提供「**申请加入名单**」入口 → 生成管理员待办 → **审批通过自动写入名册并放行**。解决了"名单外的人只能找老师手工加人"的运营痛点 | **P0** |
| ~~**FR-509**~~ | ~~名单加入申请:门禁失败页提供「申请加入名单」入口 → 管理员待办 → 审批通过自动写入名册并放行~~ → **已撤销**(2026-10 需求回退):名单外的人由老师在任务里**手工加人**(FR-508 追加导入),系统内**不展示任何联系方式**。⚠️ 它是确认函 B1 的唯一功能增量,建议补变更确认单 | ~~P0~~ |
| FR-509a | **通道边界**:入口**只在门禁失败页**,不在填报页内;**申请期间仍不能填报**——通道只解决"进名单",**不绕过门禁** | P0 |
| FR-509b | 申请表单:姓名、身份证号、手机号(**均必填**)+ 自述班级 / 说明(选填);提交后展示"已提交,等待学校审核",并可查看审批进度 | P0 |
| FR-509c | **限流与防灌**:同 openid 每任务 ≤ **2 次**;**同证件号每任务仅保留 1 条待审或已通过申请**(被驳回后可重新申请);单任务待审申请 > 50 条时告警管理员 | P0 |
@@ -920,20 +914,13 @@ DRAFT ──submit──▶ PENDING_CLASS ──班主任通过──▶ PENDING
| 旗舰版 | 多校区/大型机构 | 不限人数,含定制规则、专属客服、API 对接 |
| 私有化 | 政企/大型认定机构 | 一次性 + 年维护 |
### 5.14 历史数据整理器(FR-1400)★ 差异化获客功能
### 5.14 历史数据整理器(FR-1400)—— **已取消**(2026-10 需求收敛)
**背景**:客户手头已有大量"历史乱数据"(如本项目的 436MB `.rar`)。让他们先看到价值,再谈系统上线。
| 编号 | 需求 | 优先级 |
|---|---|:--:|
| FR-1401 | 上传 ZIP/RAR 或指定目录结构,系统自动解析文件树 | P1 |
| FR-1402 | 自动识别"姓名 / 证件号 / 材料名"三要素并规范化命名 | P1 |
| FR-1403 | 批量压缩到目标体积、格式统一 | P1 |
| FR-1404 | 输出**《材料体检报告》**:命名违规清单、证件号异常清单、体积超标清单、缺失材料清单、重复文件清单 | P1 |
| FR-1405 | 输出规范化后的 ZIP 包 + 可直接上报的目录结构 | P1 |
| FR-1406 | 报告与结果一键分享给班主任(生成链接) | P2 |
> 用本项目 `24中技数控1班` 做基准测试集,预期报告输出:命名违规 **59 项**、证件号异常 5 项、体积超标 31 项、疑似串档 1 项。
> ⚠️ **整节作废**:FR-1401 ~ FR-1406 六条需求、`collect_cleanup_job` 表、`cleanup:run` 权限码、
> PC 端「历史整理器」菜单与页面、原型「整理器」屏、`e2e-m7-cleanup.py` **已全部删除**,**不再排期**。
>
> 原用途(让老师先看到价值再谈上线)记录在此仅供追溯;若将来重启,按新需求重新评估,
> 并注意它当年最有说服力的那条结论仍然成立:**112 个文件里 90 个系统全自动处理,只有 1 个必须人工判断**。
---
@@ -1017,7 +1004,7 @@ DRAFT ──submit──▶ PENDING_CLASS ──班主任通过──▶ PENDING
> 这正是校验位算法带来的直接收益:它把"这到底是谁的材料"从人判断变成机器判断。
> 📌 **已废除**:原矩阵中"不在名册 → 转**待认领**队列"——**"自助认领"机制已在 V1.5 废除**(会绕过门禁)。
> 证件号不在名册时的正确出路是:**引导走「申请加入名单」通道**(FR-509,客户已确认采纳),
> 证件号不在名册时的正确出路是:**先核对姓名/身份证号是否输错**;确认无误则**联系老师把你加进名单**(老师在任务里手工加人,FR-508)。原「申请加入名单」自助通道已于 2026-10 撤销。
> 由管理员逐条审批后入册,而不是让系统自行认领。
**容错与纠正对照表(基于真实数据)**
@@ -1089,7 +1076,7 @@ FUNCTION name_differs_soft(fn, rn): # 仅用于矩阵第 2 条的"留痕"
合法 ⟺ C[S mod 11] == a[17](X 需大写比较)
```
**用途**:填报端实时校验、名册导入体检、历史数据整理器、OCR 结果二次验证。
**用途**:填报端实时校验、名册导入体检、OCR 结果二次验证。(原"历史数据整理器"一项已随模块删除)
### 6.3 压缩规则(按材料形态分档 + 强制 1M)
@@ -1292,8 +1279,8 @@ erDiagram
| 业务 | `collect_notify_record` | 通知记录与订阅额度 | ✅ |
| 业务 | `collect_subscribe_quota` | **微信订阅消息额度余额**(应对 R12 次数限制) | ✅ |
| 业务 | `collect_rule_template` | 规则模板(可复用) | ✅ |
| 业务 | `collect_cleanup_job` | 历史数据整理任务 | ✅ |
| 业务 | `collect_join_request` | **名单加入申请**(⚠️ 客户确认后新增,FR-509) | ✅ |
| ~~业务~~ | ~~`collect_cleanup_job`~~ | **已删除**(2026-10,见 V19 迁移) | — |
| ~~业务~~ | ~~`collect_join_request`~~ | **已删除**(2026-10,见 V19 迁移) | — |
> ✅ = 本文提供完整 DDL;从略 = 标准表(角色/字典/日志),沿用现有框架实现。
>
@@ -1610,7 +1597,7 @@ CREATE TABLE collect_task_org (
CREATE INDEX idx_tenant_head ON collect_task_org (tenant_id, head_user_id);
COMMENT ON TABLE collect_task_org IS '任务覆盖组织与审核人绑定';
COMMENT ON COLUMN collect_task_org.head_user_id IS '该班初审人(班主任),为空则取 sys_org.leader_user_id';
COMMENT ON COLUMN collect_task_org.deputy_user_ids IS '副班主任/协办人,逗号分隔';
-- ⚠️ 2026-10 需求收敛:`deputy_user_ids`(协办人)**整列已删除**(V19 迁移)。审核范围由三级回退收窄为两级(`head_user_id` → `sys_org.leader_user_id`)。
COMMENT ON COLUMN collect_task_org.expected_count IS '应填人数(期望值,管理员填写,可空);仅在与名册实际人数不一致时告警。NULL 表示未设置,与 0(预期 0 人)含义不同';
COMMENT ON COLUMN collect_task_org.status IS '0已移除 1生效';
```
@@ -1891,7 +1878,7 @@ COMMENT ON COLUMN collect_file.detect_conflict IS '是否与槽位冲突(1=冲
COMMENT ON COLUMN collect_file.need_manual_place IS '是否需要人工归属(散图分拣用)';
COMMENT ON COLUMN collect_file.vlm_called IS '是否触发了VLM兜底(用于成本核算)';
COMMENT ON COLUMN collect_file.validate_status IS '0未校验 1通过 2警告 3错误';
COMMENT ON COLUMN collect_file.source IS '1本人上传 2班主任代传 3管理员代传 4整理器导入';
COMMENT ON COLUMN collect_file.source IS '1本人上传 2班主任代传 3管理员代传 4整理器导入(⚠️ 整理器模块已于 2026-10 取消,4 仅历史数据)';
```
#### 7.3.12 校验问题
@@ -2087,6 +2074,7 @@ COMMENT ON COLUMN collect_rule_template.materials IS '材料清单模板';
#### 7.3.18 历史数据整理任务
```sql
-- ⚠️ 2026-10 需求收敛:**本表已删除**(见 V19 迁移)。以下 DDL 仅作历史记录,不要再照着建。
CREATE TABLE collect_cleanup_job (
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
tenant_id bigint NOT NULL,
@@ -2113,9 +2101,10 @@ COMMENT ON COLUMN collect_cleanup_job.status IS '0排队 1解析中 2处理中 3
COMMENT ON COLUMN collect_cleanup_job.report_json IS '体检报告:命名违规/证件号异常/体积超标/缺失/重复';
```
#### 7.3.19 名单加入申请(⚠️ 客户确认后新增)
#### 7.3.19 名单加入申请(**已撤销** · 2026-10 需求收敛)
> 对应 FR-509 系列。解决"名单外的人只能找老师手工加人"的运营痛点。
> ⚠️ **本表已删除**(见 V19 迁移),FR-509 通道整体取消。以下 DDL 仅作历史记录。
> 现在的口径:门禁失败只提示核对 + "请联系老师把你加入名单",由老师手工加人;系统内不展示联系方式。
```sql
CREATE TABLE collect_join_request (
@@ -2497,7 +2486,7 @@ export/{tenantId}/{taskId}/{exportId}/{批次号}-{专业}-{班级}.zip
|---|---|---|
| 首页(任务列表) | `pages/index` | 卡片式展示任务;显示进度环"已完成 3/5 项";倒计时提醒 |
| **门禁核验** | `pages/gate/verify` | ⚠️ **新增(入口第一屏)**:填写「姓名 + 身份证号」;身份证输入用数字键盘、自动分段、末位 X 大写、支持粘贴;本地先校验格式与校验位;提交后匹配名单 |
| **门禁失败** | `pages/gate/fail` | 统一提示"没有找到你的信息";**两个系统内动作:重新填写 / 申请加入名单**(FR-509)。**不展示任何联系方式** |
| **门禁失败** | `pages/gate/fail` | 统一提示"没有找到你的信息";**只有「重新填写」一个系统内动作**,另加一句"如确认已报名,请联系老师把你加入名单"。**不展示任何联系方式**(原「申请加入名单」通道已于 2026-10 撤销) |
| 任务详情 | `pages/task/detail` | 材料清单、状态、示例图、操作指引 |
| 信息填写 | `pages/form/index` | 分步表单;已匹配名册自动回填;身份证 OCR 一键识别 |
| 材料上传 | `pages/upload/index` | **来源选择:微信聊天记录 / 手机相册 / 手机文件**(无"拍照");每个材料项附"去哪里找"引导;上传即显示"压缩中 92%…";实时校验结果 |
@@ -2533,9 +2522,9 @@ export/{tenantId}/{taskId}/{exportId}/{批次号}-{专业}-{班级}.zip
│ 没有找到你的信息 │
│ 请核对姓名和身份证号是否与老师 │
│ 提供的名单一致。 │
│ 如果确实已报名,可申请加入名单。  │
│ 如已报名,请联系老师加你进名单。  │
│ │
│[ 重新填写 ] [ 申请加入名单 ]  │
│[ 重新填写 ] │
└──────────────────────────────────┘
```
@@ -2612,7 +2601,7 @@ export/{tenantId}/{taskId}/{exportId}/{批次号}-{专业}-{班级}.zip
| 导出中心 | 创建导出、进度、历史、下载 |
| 通知中心 | 模板管理、发送记录、催报设置 |
| 系统设置 | 组织、用户、角色、字典、日志、套餐用量 |
| 整理器(差异化) | 上传压缩包 → 体检报告 → 一键规范化 → 下载结果 |
| ~~整理器(差异化)~~ | **已取消**(2026-10) |
**命名规则编辑器**(重点)
@@ -2739,13 +2728,13 @@ export/{tenantId}/{taskId}/{exportId}/{批次号}-{专业}-{班级}.zip
| **M3 规则引擎(核心)** | 命名规范化、**五档压缩(libvips)**、格式转换、校验位裁决、OCR、**超大图 OOM 防护** | 3.5 周(A/B 验证已因实测达标而取消,较 V1.2 减 0.5 周) | 可上传即规范化 |
| **M4 审核与导出** | 审核工作台、批量审核、汇总导出、分卷打包 | 2 周 | 全流程闭环(PC 端) |
| **M5 移动端** | 小程序填报端 + **班主任端**、通知与催报(含订阅消息授权策略) | 2.5 周 | 手机端可用 |
| **M6 整理器** | 历史数据批量规范化 + 体检报告 | 1.5 周 | 获客工具 |
| ~~**M6 整理器**~~ | **已取消**(2026-10):历史数据批量规范化 + 体检报告 | — | — |
| **M7 联调与试运行** | 压测(**必须用 28 张 1.6 亿像素真实扫描件**)、真实数据回归、试点 1–2 个班 | 2 周 | 试运行报告 |
| **合计** | 部分任务可并行 | **12.5–14.5 周** | V1.0 上线 |
**MVP 建议范围(若需 6 周内出可用版本)**
保留:M1 + M2(简化版:表单字段固定为模板)+ M3 + M4 + M5
砍掉:整理器(M6)、证件照规格化、自动催报、部分统计看板
砍掉:**整理器(M6,已于 2026-10 正式取消)**、证件照规格化、自动催报、部分统计看板
> ⚠️ **不建议再压缩 M3**:超大图 OOM 防护与压缩参数验证是项目成败的关键路径,压缩这部分的工期会直接把风险推到试运行阶段(即"在真实客户面前爆炸")。
@@ -2806,7 +2795,7 @@ export/{tenantId}/{taskId}/{exportId}/{批次号}-{专业}-{班级}.zip
| R3 | 微信小程序审核受阻(涉及教育/UGC 类目、需资质) | 高 | ① 提前确认类目与资质(可能需 ICP + 办学许可或合作方资质);② 备选 H5 方案(扫码即填)保底 |
| R4 | 个人信息合规(身份证号属敏感个人信息) | 高 | 见 10.3;签约时明确数据处理者角色与责任划分(SaaS 服务商 = 受托处理者) |
| R5 | 存储与带宽成本超预期(原始文件 3.8TB/学期) | 中 | 强制原始文件 30 天清理 + 客户端预压缩 + 导出走签名 URL |
| R6 | 老师抵触新系统("又要多学一个东西") | 高 | ① "历史数据整理器"作为钩子,先让老师看到价值;② 名册 Excel 直接导入,无需重复录入;③ 一屏批量审核,比现在更快 |
| R6 | 老师抵触新系统("又要多学一个东西") | 高 | ① 名册 Excel 直接导入,无需重复录入;② 一屏批量审核,比现在更快;③ 门禁核验把"谁还没交"变成一眼可见(原"历史数据整理器"钩子已随该模块取消,见 §5.14) |
| R7 | 学生不会操作 / 使用老旧手机 | 中 | 三步极简流程 + 班主任代传兜底 + 大字号模式 |
| R8 | 重复提交 / 版本混乱 | 低 | 版本化文件管理 + 导出去重取最新 |
| R9 | 与现有系统(如需对接认定机构平台)不兼容 | 中 | 预留开放 API(8.10);导出包格式遵循机构要求 |
@@ -2834,7 +2823,7 @@ export/{tenantId}/{taskId}/{exportId}/{批次号}-{专业}-{班级}.zip
| Q8 | 是否需要向学生收取费用(如报名服务费),涉及支付资质 | 中 | 商务 |
| Q9 | 一期是否需要与"认定机构业务系统"对接 | 中 | 客户 |
| Q10 | 私有化部署版本是否同步开发(当前决策为 SaaS 优先、私有化后置) | 低 | 产品 |
| **Q11** | **名单外的人怎么处理?** 当前按需求实现为"不给填、只提示",老师需去后台加人。建议增加"**申请加入名单 → 管理员审批后自动放行**"通道(既不破门禁、又免手工加人)。**请决策** | **高** | 客户 |
| ~~**Q11**~~ | ~~名单外的人怎么处理?建议增加"申请加入名单 → 管理员审批后自动放行"通道~~ → **已决策并已回退**(2026-10):**不做自助通道**,由老师在任务里手工加人;系统内不展示联系方式 | — | 已关闭 |
| **Q12** | **社会收集的名单从哪来?** 社会收集同样"先导名单",但若名单来源不稳定(预报名名单 / 报名点收集 / 机构提供),落地难度较大。需确认名单来源与责任方 | **高** | 客户 |
| Q13 | 门禁是否再加一层**手机号验证码**(防止有人拿到他人姓名+身份证号即可代填) | 中 | 客户 |
| Q14 | 门禁限流阈值(同 openid 每小时 10 次)是否合适,需按实际人数标定 | 中 | 研发 |
@@ -2854,9 +2843,9 @@ export/{tenantId}/{taskId}/{exportId}/{批次号}-{专业}-{班级}.zip
| `PHOTO1` | 一寸照片 |
| `IDCARD` | 身份证 |
| `SCHOOL_ROLL` | 学籍表 |
| `XJW_BA` | 学信网备案表 |
| `XJW_BA` | 学信网备案表(**读得到、选不到**:不在"新增材料"列表里) |
| `WORK_PROOF` | 工作证明 / 个人申报表 |
| `OTHER_PROOF` | 其它佐证材料 |
| `OTHER_PROOF` | 其它佐证材料(**读得到、选不到**:不在"新增材料"列表里) |
**收集模式 `collect_mode`**:`1` 学校收集 / `2` 社会收集
**认定类型 `cert_type`**:`1` 自主认定 / `2` 社会评价 / `3` 专项职业能力
@@ -2911,7 +2900,7 @@ export/{tenantId}/{taskId}/{exportId}/{批次号}-{专业}-{班级}.zip
| `40004` | 身份证号校验位不通过 | 高亮错误位,提示核对原件 |
| `40005` | 证件号与名册不一致 | 展示名册值,要求确认 |
| `40006` | 疑似串档(校验位均通过但与他人不符) | 转人工,不自动修正 |
| `40007` | 门禁未匹配(姓名或身份证号与名单不符) | **统一提示**"没有找到你的信息",提供**重新填写 / 申请加入名单**(不透露是哪一项错) |
| `40007` | 门禁未匹配(姓名或身份证号与名单不符) | **统一提示**"没有找到你的信息",只提供**重新填写**(原「申请加入名单」已于 2026-10 撤销;不透露是哪一项错) |
| `40071` | 门禁尝试过于频繁(触发限流) | 提示"操作过于频繁,请稍后再试" |
| `40072` | 名单项已被他人绑定 | 提示"该信息已被登记,如有疑问请联系老师" |
| `40008` | 任务已截止 / 已归档 | 禁止提交,提示联系管理员 |
@@ -2938,6 +2927,7 @@ export/{tenantId}/{taskId}/{exportId}/{批次号}-{专业}-{班级}.zip
| 用量统计 | 每日 01:00 | 租户存储量/OCR/短信用量快照,供计费与超额告警 |
| 压缩失败重试 | 每 10 分钟 | 扫描"压缩受限/处理失败"文件,重试 ≤3 次 |
| 租户到期提醒 | 每日 08:00 | 到期前 30/7/1 天提醒 |
| 内置角色授权同步 | 每日 03:20 | 把 `sys_role_permission` / `sys_role_menu` 里**内置角色**的行对齐到代码定义(「角色与授权」已按**一期功能**计,见 `docs/03` §5.10 口径 2) |
## 附录 F:复审方法论说明
@@ -2979,7 +2969,7 @@ ERROR: relation "collect_task" does not exist ← 上面第 1 个错误的
|---|---|---|
| `uk_tenant_code` | sys_tenant、collect_task | → `uk_task_tenant_code` |
| `idx_name` | sys_occupation_ref、collect_roster | → `idx_occref_name` / `idx_roster_name` |
| `idx_tenant` | collect_material_def、collect_rule_template、collect_cleanup_job | → `idx_matdef_tenant` / `idx_ruletpl_tenant` / `idx_cleanup_tenant` |
| `idx_tenant` | collect_material_def、collect_rule_template(`collect_cleanup_job` 已于 2026-10 删除) | → `idx_matdef_tenant` / `idx_ruletpl_tenant` |
| `idx_submission` | collect_file、collect_validation_issue、collect_audit_record | → `idx_file_submission` / `idx_issue_submission` / `idx_audit_submission` |
> ⚠️ **根因**:**MySQL 的索引名只需表内唯一,PG 要求 schema 内全局唯一。**