彭峰 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
..
README.md 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
auth-reproduction.json 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
dependency-summary.json 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
local-page-probes.json 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
probe-local-pages.cjs 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
reproduce-auth.cjs 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
student-home-unavailable.png 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
sync-readonly.json 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
teacher-home-unavailable.png 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine
verification-summary.json 6d4e042e77 docs(qa): audit three-end launch readiness with local evidence il y a 1 semaine

README.md

小树三端上线前审查(2026-10-13)

结论与范围

当前版本不建议直接作为已验收版本发布。 主体教学功能已经形成闭环,但账号安全、移动端登录、密码规则、工资结算入口与现有同步方案之间仍有明确问题。先处理 A01—A06,再进行发布验收。

依用户要求,本次只审查当前代码、本地运行与本机已有运行记录;未部署、未操作生产会员/工资/预约。学生端和老师端共用移动应用,按两个身份分别检查。代码基线为 9224f7a 加工作区原有两项未提交修改:learning-page.component.ts 和 home-learning-modules.integration.spec.ts;报告不是仅对 Git HEAD 的审查。

证据分为:本地复现、源码确认、本机历史报告、发布前待验证。浏览器使用隔离模拟账号与拦截接口;模拟页面通过不等于真实线上接口通过。审查覆盖关键业务和横切能力,未声称逐一人工点击全部历史迁移路由。

优先处理的问题

A01 · P1 · 旧系统密码可以覆盖新系统已修改密码

  • 证据:scripts/deploy-admin-functions.mjs 的 user_login_passwd(约 2990 行)在新密码登录失败后调用 migrateLegacyLogin(2881 行)。后者只要旧系统验证成功,就执行 target.setPassword(password),并清除 passwordResetRequired,没有“仅首次迁移”条件。
  • 本地复现:隔离内存中的账号已有新密码,旧密码验证成功后,新密码被替换,强制改密标记被清除;没有操作真实账号。见 auth-reproduction.json。
  • 影响:新系统改密不能可靠切断旧密码;学生、教师与复用该入口的后台账号均需核查。前提是旧系统仍接受该账号旧密码,不代表任何人无需密码即可登录。
  • 修复:只允许尚未完成密码迁移的账号进入旧验证;在一次性迁移、主动改密或管理员重置后永久关闭旧密码回退。显式维护迁移状态,并撤销应失效会话。
  • 验收:首次迁移成功;迁移后新密码成功、旧密码失败;网络故障不能触发改密;停用、跨帐套与重置密码场景均拒绝不合规回退。

A02 · P1 · 移动端旧请求失败会清除新会话

  • 证据:projects/xiaoshu-mobile/src/app/core/api.service.ts 的 callCloud 只把“是否需登录”的布尔值交给错误处理;handleError 收到 401 后调用 expireSession,未核对失败请求所属 token。
  • 本地复现:A 会话发起请求 → 换成 B 会话 → A 的迟到 401 返回 → B 会话被清空,跳到 wxauth?expired=1。
  • 影响:学生、老师操作中可能突然退出并清理本地学习草稿。后台已有 token 比较和会话复核,本问题主要在共用移动端服务。
  • 修复:传递实际请求 token;仅处理与当前会话匹配的失效响应;区分网络故障与真实失效;复用后台已实现的复核策略。
  • 验收:迟到 401 不影响新登录;当前会话确实失效才退出;503、断网不退出;并发失效只跳转一次。

A03 · P1 · 后台接受的密码,移动端可能无法登录

  • 证据:后台创建/导入/重置密码支持 8—72 位;移动端 login-page.component.ts 的 submitClassic 限制 6—18 位。会员导入模板也明示 8—72 位。
  • 本地复现:20 位密码在移动端被客户端直接拒绝,请求数为 0。
  • 修复:统一三端与服务端密码规则,登录端不要用注册旧规则拒绝现有合法密码;调整提示与导入模板。
  • 验收:后台创建的 8、18、19、72 位合法密码均能在移动端按统一规则登录,超界输入有一致提示。

A04 · P1 · 临时密码强制修改流程没有在移动端闭环

  • 证据:后台重置写入 passwordResetRequired=true,移动端没有消费此标记;pages/member/passwd 被 feature-policy.ts 的表单策略阻止。
  • 本地页面:进入“修改登录密码”显示“暂未开放,请联系管理员处理”。
  • 影响:管理员交付的临时密码无法由学生/老师自主修改,也没有强制改密约束。与 A01 组合后风险更高。
  • 修复:服务端返回并执行强制改密状态;实现当前密码验证、修改、撤销旧会话与重新登录;允许访问必要的改密/退出/帮助页面。
  • 验收:临时账号先改密再使用;旧密码和旧会话失效;失败保留输入并可重试。

A05 · P1 · 工资批次仍被旧同步桥验收条件阻挡

  • 证据:scripts/cloud/payroll-integrity.js 的 payrollSettlementSyncStatus 仍以同步桥配置、manifest、检查点及两分钟延迟为条件;payrollMutation 对 create/refresh/review 强制检查 settlementReady。directPayrollSyncStatus 的直接接口凭据固定 settlementReady:false;scripts/cloud/legacy-direct-control.js:87 的完成报告同样固定为 false。
  • 本机最新完整同步报告:旧接口已完成、9 个数据集业务编号对账通过、失败 0,但 settlementReady:false。见 sync-readonly.json。这是已发生的历史报告,不是本次生产实时查询。
  • 影响:每天 23 点同步成功并不等于工资可以生成、刷新或审核;页面仍可能提示未配置持续同步。现有提示还写着“手动同步”“每日自动同步尚未验收”,与已安装任务容易混淆。
  • 修复:接入直接接口的工资截止范围核验:按结算月份核对预约、完课和复习凭据;分类处理已保留的新系统修改与未解决差异,保存对账版本和确认结果;基于这些证据开放结算。不能把 false 改成 true,也不能将所有 1,330 条保留差异一概当作错误或一概忽略。
  • 验收:真实缺失/未解决工资冲突仍拦截;已核验范围可生成;核验后源数据变更会使确认失效;复习奖励、跨月补结和已发放金额不重复。

A06 · P1 · 依赖存在已知安全公告,上线前需要分级处理

  • 官方 npm registry 的本次完整扫描:85 个受影响依赖条目,其中 critical 6、high 49、moderate 22、low 8。这是依赖树条目数,含构建/测试工具和传递依赖,不是 85 个已经证实可利用的产品漏洞。 默认 npmmirror 不支持 audit,本次已改用官方 registry;未执行 audit fix --force。
  • 直接依赖涉及 Angular 18、xlsx、html2pdf.js、jspdf 等;详见 dependency-summary.json 的安装版本及公告链接。
  • 后台会员、词库 Excel 导入确实调用 xlsx.read,应优先处理 SheetJS 解析链;PDF 导出库也进入实际功能。Angular 的 i18n、SSR 等公告各有触发条件,不能仅凭版本认定当前 SPA 都可利用。
  • 修复:先梳理浏览器可达依赖,升级/替换已知风险导入导出库,再安排 Angular 支持版本迁移;单独处理开发工具。每组升级做对应功能回归,不自动强升整树。
  • 验收:产物依赖风险有处理结果或有依据的不可达说明;Excel 导入、PDF 多页导出、路由、表单与移动端全部回归。
  • 一级来源:Angular 官方公告、html2pdf 官方公告、SheetJS 公告。扫描结果只代表审查时点。

使用体验、稳定性与维护问题

编号 级别 问题与证据 建议与验收
B01 P2 学生首页 home-page.component.html:97–101 将缺失统计/余额回退为 0,统计失败只给教师设置错误状态;模拟 503 时学生仍看到一排 0。部分余额来自登录快照,未标出更新时间。 未取得值显示“—/暂不可用”,已有值标为缓存并可刷新;真实 0 才显示 0。模拟失败、充值后刷新、跨端变化分别验收。
B02 P2 学生/老师课表失败时同时显示“暂无排课”和错误提示;后台排课错误状态也仍显示 0 与空泳道。见 local-page-probes.json。 首次失败、真实为空、保留缓存三种状态分开;未成功查询前不下“没有课”的结论。
B03 P2 隐私注销入口 pages/member/acc_destory 被功能策略阻断;本地显示暂未开放。登录协议走站内文章,用户中心另有旧域名文档来源。 提供可完成的申请/管理员处理入口,明确处理状态;核对并统一协议内容及版本。本项是功能与内容一致性问题,不代替法律审查。
B04 P2 CloudFunctionsService 的后台 admin/operations/app 请求没有统一超时;移动端也只有特定 action 设置 20 秒超时。 给读写分别设有限等待与取消/核对路径;写入超时显示“结果待核对”,重试必须沿用幂等键,避免误导重复操作。用悬挂响应测试释放 loading。
B05 P2 operations-vocabulary.component.ts:138–141 在解析 Excel 前没有文件大小/行数限制,直接主线程读取全表;会员导入已有 5 MB/200 行限制,可作参考。 解析前限制大小,限制解压/行数并考虑 Worker;大文件应快速拒绝且页面仍可操作。
B06 P2 webview-page.component.ts 接受任意 http/https 参数并绕过资源 URL 安全检查,iframe 允许脚本、同源、弹窗及下载。没有主机允许名单。未复现跨域脚本读取,也不能据此声称存在完整 XSS。 收敛到 HTTPS 允许域名,按来源最小化 sandbox 权限;明确外部站点提示;测试非法协议、恶意主机、嵌套编码与新窗口。
B07 P2 移动端 SessionService 没有后台已有的跨标签 storage 监听;退出仅清理本地会话,未见此路径调用服务端撤销会话。 明确多端退出策略;同浏览器标签及时更新身份,退出后旧 token 按产品约定失效;不能只隐藏界面。当前为源码判断,未做生产 token 重放。
B08 P2 全量前端测试有 7 个失败项,旧流程/日期/缓存命名的测试未同步维护。 修复测试契约并稳定日期时钟;建立完整构建与测试门禁。不要删掉断言或修改业务去迎合旧测试。详见下一节。
B09 P2 夜间任务具备失败重试和私有报告,但执行器未见主动通知实现;只有日志不足以让人及时知道凭据过期或持续失败。 给最终失败、连续未完成、冲突显著增长设去重告警;成功保留安静。验证人为失败可被发现、恢复后告警消除。
B10 P3 前端未找到全局异常采集与关联请求编号链路;现有多处错误只弹短暂 toast。 增加脱敏错误记录、版本号、请求编号和可重试提示,避免上报密码/token/学员完整信息。仓库未发现不等于部署平台没有监控。
B11 P3 移动登录文本输入主要用 placeholder,缺少持久 label;部分后台图标按钮/自制 drawer 缺少可访问名称与焦点管理。 登录表单补 label,主要触控目标约 44px;对话框聚焦、Escape、关闭后回焦;键盘与读屏抽验。这里是源码抽查,未做全站无障碍认证。

已执行的验证与通过部分

检查 本次结果 证明范围
npm run build 移动端、后台均成功 当前工作区可生成生产包;已有样式预算/CommonJS 警告未阻断构建
移动端全量测试 197 项,192 成功、5 失败 未全绿
后台全量测试 256 项,254 成功、2 失败 未全绿;移动端失败使组合命令中断,所以另行运行后台
node --test --test-concurrency=2 scripts/tests/*.test.mjs 163 成功、0 失败 本地 SQL/网关/业务策略测试,不是生产数据库测试
云 action 清单核对 requested 116、implemented 99、blocked 21、missing 0 没有未分类 action;三组非互斥,不能相加成覆盖率,也不代表 21 个关闭功能已实现
报告与预约详情浏览器 375/812 宽度及横屏编辑;保存一次、无页面异常、无横向溢出 模拟接口;取消、报告跳转编辑、保存路径通过
三端故障状态抽查 375/1366 宽度;首页、课表、用户中心、后台工作台/排课/工资;无页面异常/文档横向溢出 模拟 503,与健康真实数据 UI 分开记录
未登录路由 移动预约跳登录、后台工资跳登录 前端 guard;服务端权限另由源码/SQL测试支撑
身份与越权 本地测试覆盖普通会员无后台权限、运营不能提权、跨帐套拒绝、停用撤销、版本冲突 生产角色/ACL 是否与代码一致仍需发布者确认
业务事务 结课幂等、写入失败回滚、课时预留、重复退款、并发抢最后课时、报告文字修改、奖励防重复均有通过用例 PGlite/隔离测试,不能替代生产恢复演练

7 个失败项的归因

  1. 移动端 3 个学习分组/跳过拼写用例使用旧缓存键 ...901.;当前代码按 ...901.unbound. 或 bindingId 隔离。只在临时测试副本更新前缀后,3 项全通过,没有修改业务逻辑。
  2. 移动端 2 个预约课程/单元用例仍模拟旧 content_list,没有提供新的 app_lesson_courses 契约,其中还断言“不应有课程选择框”,与用户要求显示学员全部已开通课程相反。源码证明测试过期;这两项尚未重写完整测试并复跑,不把它们认定为线上课程加载故障,也不声称已修好。
  3. 后台 2 个陪练月份用例硬编码 2026-09/9月;当前默认月份为 10 月。临时副本改为 10 月后该文件 4 项全通过。最终应使用稳定时钟/依赖注入而不是继续改硬编码月份。组件模块级 CURRENT_MONTH 还应在长期开页跨月场景重新计算。

临时副本均已删除,原有未提交代码保持原样。全量基线仍为 7 个失败,不能用诊断副本成功代替门禁通过。

分端覆盖与剩余验收

范围 审查内容 结论 / 尚缺证据
学生 登录、个人资料入口、课程/排课、学习分组、抗遗忘、结课报告、评价、密码/注销 核心本地测试可用;A01—A04、B01/B03/B07 待修。手机真实音频、断网回前台与跨设备会话待验收。
老师 学员绑定、预约当天开课、全部已开通词库选择、多词库学习、结课反馈与修改、复习奖励 本地权限/课时/报告事务用例通过;A02/A04 影响会话。长课中断、锁屏恢复和真实媒体待验收。
后台 会员导入/开课、余额划拨、排课/取消、老师可用时间、工资、报表导出、词库、管理员角色 本地业务事务保护较完整;A01/A03/A05/A06 是重点。大表导入、真实打印文件与生产角色映射需后续验证。
同步与数据 旧接口执行器、依赖顺序、原子主附表、差异保留、断点、业务编号对账、删除标记与阅读身份冲突 直接接口本地测试通过;已有完成报告。保留差异不是失败,但需按工资/课时影响分类处理。未重新同步真实数据。
性能 生产初始包、懒加载、PDF/Excel按需导入、故障渲染 移动初始约 410.17 kB/估算传输112.89 kB;后台367.21/102.76 kB。仅体积,未得出端到端速度结论。需真数据/网络条件下测可交互 p75。
安全与隐私 密码迁移、会话、权限、导入库、外链、隐私入口、日志与凭据 已确认 A01—A04;其余区分源码风险与实际利用。未输出执行凭据,审查文件仅模拟账号和汇总。
发布与维护 构建、测试、依赖、打包、同步任务、回滚和备份证据 后台有 release prepare/verify;未找到对应移动发布打包和仓库CI流程。数据库备份/恢复、TLS/CORS/安全头属于发布环境待核验,不认定线上缺失。

本机 23 点同步现状(只读)

  • LaunchAgent cn.xiaoshu.legacy-direct-sync-nightly 已加载;北京时间 23:00,RunAtLoad 开启,失败后 KeepAlive 重试、ThrottleInterval 300 秒。
  • 运行器及两个依赖文件与当前仓库内容一致;凭据文件权限 0600;最近记录 exit 0、runs 2。白天 state=not running 是正常的,不表示任务未安装。
  • 2026-10-12 完整报告:新增业务记录 53、更新 181、保留冲突 1,330、失败 0,9 类编号对账完成;次日 00:22 的 already_completed 是防重复,不是新一轮同步。
  • 本次读取的另一个 ready 是就绪检查,不是已同步。不能把它当当天同步成功。
  • Mac 作为运行主机已获用户确认。仍需开机并登录该用户;关机、用户退出等条件下不能保证 23 点执行。安装记录/一次完成不等于以后每晚定时触发已验证,下一次自然触发应核对 businessDate 和 finish 回执。
  • sync-worker:nightly 已走直接接口;package.json 中 sync-worker:once/start 仍指旧桥 worker,容易误用,应明确标记历史用途或收敛命令。

修复顺序与发布交接

  1. 先修账号链路:A01—A04 同一组处理,覆盖旧密码关闭、新密码统一、首次改密、迟到响应与跨标签登录。用隔离账号测试,保留迁移兼容但禁止覆盖已更新密码。
  2. 闭合工资核验:A05,使用现有直接接口成功凭据与月份截止核验,不回到同步桥,不绕过差异与财务事务。
  3. 处理依赖与可靠性:A06、B01—B09;先真实可达导入库、错误零值、超时、告警,再扩展到统一体验。
  4. 稳定验收门禁:更新过期测试并使全量通过;固定时间、明确 fixture 契约;在隔离数据上完成学生—老师—后台全链路。
  5. 用户自行发布前核对:前端 commit/hash、后端版本、SQL迁移版本一致;配置学生/老师端及后台域名、HTTPS、API CORS、SPA回退、缓存策略;备份并实际恢复一次;准备前端回滚包与后端兼容回滚方案。
  6. 发布后验收由发布者执行:用隔离学生/老师/管理员验证登录→开课→排课→开始→多词库学习→结课→报告修改→学生评价→工资核对;再验 23 点自然触发、断网、iOS Safari/微信/Android、音频播放、PDF下载。不得用真实客户记录制造验收扣费或发薪。

可用的发布验收清单

  • A01—A06 已关闭或有明确范围的风险处置结论。
  • 两端生产构建、前端全量、服务端本地测试全通过。
  • 真实环境的角色/帐套、禁用用户、错误身份、重复提交、并发版本冲突已验证。
  • 工资核验与旧接口同步凭据连通,保留差异已按影响处理。
  • 发布产物与源码版本可追溯,移动端与后台不会误用旧 dist 目录。
  • 备份、恢复、回滚、安全头、上传限制、登录限流和告警由发布者确认。
  • 真机核心教学流程与下一次 23 点自然触发通过。

证据与复现

  • verification-summary.json:构建、测试、清单、报告UI摘要。
  • auth-reproduction.json:三项登录问题及注销入口的隔离复现。
  • dependency-summary.json:官方 registry 扫描摘要,含直接依赖公告。
  • local-page-probes.json:各身份/视口的模拟故障页面文本与溢出/错误检查。
  • sync-readonly.json:任务配置、脚本一致性与已有对账报告的脱敏汇总。
  • 两张 *-home-unavailable.png:本地故障态截图(模拟账号)。
  • reproduce-auth.cjs、probe-local-pages.cjs:从仓库根目录运行,需 Chrome 和 Playwright;可通过 PLAYWRIGHT_MODULE 指向本机模块位置。它们只针对本地4200/4300,不应改成生产地址运行。

本次交付为审查报告和本地证据;未修改上述业务缺陷,未部署。原有测试未全通过,因此不把报告描述为“上线验收通过”。