Files
prop-ai-hr/docs/superpowers/plans/2026-07-31-mobile-citation-source-viewer.md
T

30 KiB
Raw Blame History

手机端问答引用详情与原始媒体定位 Implementation Plan

制定日期:2026-07-31

当前状态(2026-08-02):阶段 0 基线冻结已完成;阶段 1—5 已实现部分能力,本机 H5 已验证文本、图片、视频引用详情及视频 Range 实播,但完整越权矩阵、App-Plus/Android 真机和性能门禁未闭合;阶段 6 未开始

适用范围:mobile-uni 员工端“问 · 数字师傅”、/api/aihr/agent/**、知识检索与受控原始资料接口

Goal: 让员工在手机端点击回答引用后,按当前身份重新鉴权并打开可信来源详情:文本进入全文页并高亮命中位置,图片打开原图,视频进入受控播放器并定位到引用时间或已保存关键帧;来源撤回、过期或失权时失败关闭。

Architecture: 保留 aihr_knowledge_fragment 为检索正文事实源,新增一对一的片段来源定位表保存附件、媒体类型和页码/段落/时间戳等结构化位置。回答只返回不透明 detailRef 和最小展示信息;点击后由服务端重新计算“租户 + 调用应用绑定 + 当前主体授权”,再返回受控文本、图片或视频播放信息。原始 OSS 地址、登录令牌和完整提取正文不进入回答响应。

Tech Stack: Java 17、Spring Boot、Sa-Token、JdbcTemplate、MySQL 8、MinIO/sys_oss、ffmpeg/ffprobe、Tika/现有文档解析器、uni-app Vue 3 + TypeScript、Node test、JUnit 5/Mockito、Android App-Plus。


0. 完成定义与证据纪律

0.1 阶段状态

每个阶段只能使用以下状态:

  • 未开始:尚未写代码或迁移。
  • 实现中:允许局部测试通过,但尚未形成该阶段的完整证据。
  • 技术通过:本地自动化和真实运行链路均通过,但尚未部署生产。
  • 生产通过:所需发布单元已部署,正式账号或真机完成该阶段规定的验证。
  • 阻断:失败项、复现步骤和责任边界已记录;不得用后续阶段结果覆盖。

“源码存在”“单元测试通过”“H5 能加载”“视频能播放”都不能单独视为阶段完成。

0.2 每阶段必须保存的实际结果

每个阶段结束时必须填写本计划中的“实际结果记录”,至少包含:

字段 要求
构建源 完整 Git commit,不使用模糊分支名
环境 本地/测试/生产、后端与 schema 版本、APK 版本
命令或操作 可重复执行的命令或真机点击路径
预期 明确数值、HTTP 状态、页面状态或时间误差
实际 真实通过数、失败数、耗时或错误码,不写“基本正常”
证据 脱敏日志、JUnit/Node 输出、HTTP 头、截图或真机录像路径
遗留项 未覆盖的文件类型、机型、角色、数据或性能边界

执行证据统一写入:

output/citation-source-viewer/<run-id>/

仓库文档只保存脱敏摘要和证据相对路径,不保存手机号、验证码、令牌、短期下载票据、原始 OSS 地址或受保护正文。

0.3 固定验收样本

本地工程样本使用可公开的合成内容,至少包含:

  1. 一份 TXT/Markdown,带唯一标记和已知行号;
  2. 一份三页 PDF,目标引用位于第 2 页;
  3. 一份 DOCX,目标引用位于指定段落;
  4. 一份 PPTX,目标引用位于指定页;
  5. 一张带唯一视觉文字的图片;
  6. 一段不超过两分钟的视频:
    • 已知语句位于固定时间范围;
    • 已知画面位于固定时间点;
    • 含音轨和画面两种可命中依据。

生产验收只选已批准、当前员工有权访问的正式资料;测试问题和答案正文不进入仓库。


1. 范围与非目标

1.1 本计划交付

  • 回答中的 DOCUMENT 引用卡片可点击;
  • 文本全文页展示同一受控附件的解析正文,并定位、高亮命中片段;
  • PDF/PPT/DOCX 在解析能力允许时展示页码、幻灯片号或段落位置;
  • 图片引用打开当前员工仍有权访问的原图;
  • 视频引用打开独立播放器,定位到语句时间范围或关键帧时间;
  • 大视频使用支持 HTTP Range 的受控播放链路;
  • 点击时重新鉴权,撤权、跨租户、来源失效和过期票据均失败关闭;
  • 新资料在解析时产生定位元数据,历史资料有可审计的回填与降级策略;
  • H5、App-Plus、Android 真机分别形成实际验证结果。

1.2 本计划不交付

  • 不把完整原文直接塞进 Agent 回答或会话审计;
  • 不暴露 MinIO/OSS 原始地址或永久公开链接;
  • 不允许客户端提交 attachmentId、租户、岗位或空间代码来扩大权限;
  • 不把 AI 推断的位置当作原文件页码或视频真实时间点;
  • 不承诺所有旧资料自动获得精确页码/帧;无法可靠回填时降级为“打开全文/原文件”;
  • 不在本计划重做 RAG、向量模型或 Agent 意图规划;
  • 不把 DCloud 测试签名 APK 验证写成企业签名或应用商店验收。

2. 实施总览

阶段 交付物 完成门禁 当前状态
0. 基线冻结 当前引用、资源、视频解析和权限链路事实 源码位置与缺口逐项复核 已完成
1. 定位数据契约 schema、结构化解析结果、写入和替换一致性 迁移幂等;六类样本定位记录正确 实现中
2. 受控详情与媒体接口 detailRef、详情解析、全文、图片和 Range 视频 正授权成功;跨租户/撤权/伪造全部拒绝 实现中
3. 手机端引用详情 可点击引用、全文高亮、图片预览、视频定位 390×844 主路径实际点击;H5 与 App 测试通过 实现中
4. 历史资料回填 安全回填、失败降级、进度报告 不改正式来源审批;成功/失败/降级数量可核对 实现中
5. 集成、安全与性能 全链路矩阵、并发/Range/资源释放 零越权;定位误差和性能达到冻结阈值 实现中
6. 发布与真机收口 schema、后端、H5/Android 发布与生产验证 独立授权发布;正式账号和签名 APK 真机证据 未开始

依赖顺序:

阶段 0
  → 阶段 1 数据契约
  → 阶段 2 受控接口
  → 阶段 3 手机端交互
  → 阶段 4 历史回填
  → 阶段 5 全链路门禁
  → 阶段 6 发布与真机

阶段 3 可以在阶段 2 的固定测试响应上并行开发,但不能在阶段 2 的权限和 Range 接口完成前标记技术通过。


3. 阶段 0:当前基线冻结

目标: 冻结真实缺口,防止实施时把“引用已展示”“资源卡能打开”误认为引用跳转已经存在。

已核实事实

核验项 实际结果 结论
工作区 main...origin/main,核验时无未提交文件 可建立独立实施计划
回答引用 snippets 可展开,显示标题、摘要、空间和 fragmentId;引用卡没有点击事件 需要新增点击详情
资源卡 resources 中 FILE 可下载打开、VIDEO 可加载内联播放器 可复用受控读取能力,但未与每条引用绑定
引用契约 Citation 无 attachmentId/mediaType/locator/detailRef 后端需要新增最小详情引用
视频定位 ASR 每 5 分钟片段写入一个 [mm:ss];关键帧间隔至少 30 秒且最多抽取 40 帧,并写入 [画面 mm:ss] 只能得到粗定位文本
关键帧文件 OCR 完成后临时 JPG 被删除 无法直接展示历史关键帧图
片段 schema 只有 idx/doc_id/content/embedding,没有来源定位字段 需新增旁路定位表
原文件权限 /api/knowledge/resources/{attachmentId}/content 每次重新鉴权 继续复用,不改成永久 URL

阶段 0 实际验证结果

  • 状态:通过
  • 日期:2026-07-31
  • 方法:源码只读审计、rg 检索、工作区状态核验
  • 结果:8 项事实全部定位到当前源码或 SQL;没有执行数据库写入、部署或生产操作
  • 未覆盖:当前生产附件的真实 MIME 分布、OSS Range 行为、历史视频定位可回填比例

4. 阶段 1:片段来源定位数据契约

目标: 让每个可点击引用都能确定性关联到受控附件及其真实位置,不依赖前端解析片段文字。

Files

  • Create: backend/script/sql/update/aihr_20260731_knowledge_fragment_locator_mysql8.sql
  • Modify: backend/script/sql/aihr_knowledge_mysql8.sql
  • Create: backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/domain/AihrKnowledgeSourceLocator.java
  • Modify: backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java
  • Modify: backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrVideoService.java
  • Modify: relevant document parser implementations
  • Test: backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/knowledge/AihrKnowledgeSourceLocatorSchemaTest.java
  • Test: backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/knowledge/AihrKnowledgeSourceLocatorIngestionTest.java

Task 1.1:建立旁路定位表

新增 aihr_knowledge_fragment_locator,最小字段:

tenant_id
fragment_id
knowledge_id
doc_id
attachment_id
source_kind
page_number
slide_number
paragraph_start
paragraph_end
sheet_name
row_start
row_end
start_ms
end_ms
frame_ms
locator_version
create_time
update_time

约束:

  • UNIQUE(tenant_id, fragment_id);
  • 查询索引覆盖 (tenant_id, attachment_id, source_kind);
  • source_kind 只允许 TEXT/PDF/DOCX/PPTX/XLSX/IMAGE/VIDEO;
  • 时间、页码和段落不能为负数;
  • 定位表缺失或无定位行时,查询仍可返回普通引用,不影响现有问答;
  • 生产请求不得自动执行 DDL。

Task 1.2:解析结果从纯字符串升级为结构化段

内部解析结果统一为:

record LocatedSegment(
    String text,
    SourceKind sourceKind,
    Integer pageNumber,
    Integer slideNumber,
    Integer paragraphStart,
    Integer paragraphEnd,
    String sheetName,
    Integer rowStart,
    Integer rowEnd,
    Long startMs,
    Long endMs,
    Long frameMs
) {}

最低定位能力:

  • TXT/Markdown:行或段落范围;
  • PDF:页码;
  • DOCX:段落范围;
  • PPTX:幻灯片号;
  • XLSX:工作表与行范围;
  • IMAGE:关联原图,首版不要求 OCR 框坐标;
  • VIDEO ASR:语句或分段开始/结束毫秒;
  • VIDEO 画面:抽帧的真实毫秒位置。

Task 1.3:切片、替换和重试一致性

  • 片段与定位行在同一受控处理流程写入;
  • 同名文档替换时同步清理旧定位行;
  • 异步重试不得产生孤立定位行;
  • 零片段媒体仍保持失败,不创建虚假定位;
  • Qdrant payload 不存原始地址;如需要,可只增加 fragmentId/sourceKind。

阶段 1 验证

运行:

mvn -f backend/pom.xml -pl ruoyi-modules/ruoyi-aihr -am `
  -DskipTests=false -Dsurefire.failIfNoSpecifiedTests=false `
  -Dtest=AihrKnowledgeSourceLocatorSchemaTest,AihrKnowledgeSourceLocatorIngestionTest test

在临时数据库上执行正式迁移两次,并导入六类固定样本。必须实际证明:

  1. 迁移连续执行两次均成功;
  2. 六类样本均有 fragment + locator;
  3. PDF 第 2 页、PPT 指定页、图片附件、视频语句和画面时间均与样本基准一致;
  4. 文档替换后旧 locator 为 0;
  5. 解析失败后 locator 为 0;
  6. 未执行运行时 DDL。

阶段 1 实际结果记录

字段 实际值
状态 实现中
构建源 阶段 1 实现已进入当前分支;2026-08-02 本轮未新增该阶段代码
JUnit 未运行:当前 PowerShell 未找到 java/mvn
迁移幂等 本地 locator 迁移与回填已执行;未完成两次正式迁移的 JUnit 证明
六类样本定位 当前本地 seed 仅有 5 个文本附件、15 个 TEXT locator;PDF/DOCX/PPTX/XLSX/IMAGE/VIDEO 固定样本未完成
替换/失败清理 代码路径已实现,未完成后端自动化复跑
证据目录 output/citation-source-viewer/20260731-local/
遗留项 缺少 Java/Maven 运行时及六类公开合成附件样本

5. 阶段 2:受控引用详情、全文、图片与视频接口

目标: 客户端只持有不透明引用,服务端在点击时重新鉴权并返回最小必要内容。

Files

  • Modify: backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/domain/AihrKnowledgeQueryDto.java
  • Create: backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeCitationDetailService.java
  • Create: backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/controller/AihrKnowledgeCitationController.java
  • Modify: backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeResourceDownloadService.java
  • Test: backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/knowledge/AihrKnowledgeCitationDetailServiceTest.java
  • Test: backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/knowledge/AihrKnowledgeCitationControllerTest.java
  • Test: backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/knowledge/AihrKnowledgeResourceRangeTest.java

Task 2.1:扩展回答引用

兼容新增字段:

{
  "fragmentId": 12345,
  "title": "投诉处理培训",
  "snippet": "……",
  "mediaType": "VIDEO",
  "detailRef": "opaque-short-lived-reference",
  "locatorSummary": {
    "pageNumber": null,
    "startMs": 208000,
    "endMs": 223000,
    "frameMs": null
  }
}

规则:

  • 旧客户端忽略新增字段仍可工作;
  • detailRef 不编码明文租户、附件、用户或 OSS 地址;
  • 正式政策引用仍必须来自有效的 FORMAL_POLICY + APPROVED 来源;
  • DATA_TOOL、个人记录和项目记录分别走现有领域详情,不伪装成企业文档。

Task 2.2:详情解析接口

新增:

GET /api/knowledge/citations/{detailRef}

返回三类详情:

  • TEXT:标题、位置、当前片段、分页全文读取入口、原文件入口;
  • IMAGE:标题、短期原图读取入口;
  • VIDEO:标题、startMs/endMs/frameMs、短期流媒体入口。

点击时必须重新验证:

  1. 当前 APP 登录身份;
  2. 当前租户;
  3. 调用应用与知识空间绑定;
  4. 当前主体授权;
  5. 附件仍为 READY、知识空间仍为 ACTIVE;
  6. 正式来源仍有效且版本、哈希未漂移;
  7. fragmentId/docId/attachmentId 仍属于同一来源。

Task 2.3:全文和媒体读取

  • 全文按页或游标读取,单次响应有硬上限;
  • HTML 展示只生成受控纯文本结构,不渲染原文脚本、宏或外链;
  • 图片继续通过当前授权资源链路读取;
  • 视频流接口支持 Range,合法请求返回 206、Content-Range 和正确 MIME;
  • 票据短期有效、单附件绑定、不可跨资源复用;
  • 撤权后已签发但未使用的票据也必须拒绝或在最短有效期内失效。

阶段 2 验证

必须覆盖:

用例 预期
有权员工打开文本、图片、视频 200;视频 Range 为 206
伪造 detailRef 404/403,不泄露资源是否存在
跨租户引用 拒绝
无空间授权 拒绝
来源回答后被停用或撤权 再次点击拒绝
票据过期或跨附件复用 拒绝
旧客户端请求 原问答响应仍兼容
日志扫描 无 token、票据、OSS 地址、全文

阶段 2 实际结果记录

字段 实际值
状态 实现中
构建源 2026-08-02 本轮修复提交见 Git 历史;该提交不代表生产发布
JUnit AihrKnowledgeResourceRangeTest:2/2 通过,覆盖首次无 Range 请求的 inline/MIME 通路和带 Range 请求转发
正授权 本机已用已发布的合成文本、图片、视频资产通过 APP 登录态检索并打开详情 3/3;未执行生产正式账号验收
越权矩阵 未完成;源码保留租户、应用、主体、来源治理复验,未形成后端运行证据
Range 本机合成 MP4 完整请求 200 video/mp4 且 inline;Range 请求 206 video/mp4,返回合法 Content-Range 和 1024 字节
日志敏感信息扫描 未完成后端运行日志扫描;未在移动端脱敏证据中写入手机号、令牌或 OSS 原址
证据目录 output/citation-source-viewer/20260731-local/
遗留项 生产正式账号、撤权/跨租户/伪造/过期票据反例、日志扫描和完整权限矩阵仍待验证

6. 阶段 3:手机端引用点击与详情页面

目标: 在 390×844 和 Android App-Plus 中完成真实可点击的文本、图片和视频引用路径。

Files

  • Modify: mobile-uni/src/types/api.ts
  • Modify: mobile-uni/src/services/knowledge.ts
  • Modify: mobile-uni/src/pages/user/sop/index.vue
  • Create: mobile-uni/src/pages/user/sop/citation-detail.vue
  • Modify: mobile-uni/src/pages.json
  • Test: mobile-uni/tests/knowledge-citation-detail.test.mjs
  • Test: mobile-uni/tests/agent.test.mjs

Task 3.1:引用卡交互

  • 每条可查看的 DOCUMENT 引用使用可访问按钮;
  • 显示来源类型、页码或视频时间摘要和“查看出处”;
  • 没有 detailRef 的旧引用保持只读,不制造假入口;
  • 点击时不携带租户、角色、空间或原始地址。

Task 3.2:统一详情页

页面状态:

  • loading:正在重新验证来源;
  • text:全文分段加载、目标片段高亮并自动滚动;
  • image:受控图片加载,支持全屏缩放;
  • video:受控播放器加载,在 loadedmetadata/canplay 后 seek;
  • forbidden/expired/not-found:明确说明来源已失效或无权查看;
  • error/retry:网络失败可重试,不把权限错误当网络错误。

Task 3.3:视频定位

  • 语音引用使用 startMs;
  • 画面引用使用 frameMs 并默认暂停展示目标画面;
  • 页面展示 mm:ss,不显示内部片段或附件编号;
  • 切换引用、离开页面或重试时释放 Blob URL 和播放器资源;
  • 若平台无法保证逐帧 seek,业务定位门槛为目标时间 ±500ms;需要证明目标帧时同时展示服务端保存的对应关键帧预览。

Task 3.4:图片与文本

  • 图片使用当前认证上下文读取,不保存永久公开地址;
  • 文本高亮只基于服务端目标片段,不在前端用模糊搜索猜位置;
  • 超长全文使用分页/虚拟加载;
  • 原文件打开继续使用短期下载票据。

阶段 3 验证

自动化:

node --test mobile-uni/tests/knowledge-citation-detail.test.mjs mobile-uni/tests/agent.test.mjs
npm --prefix mobile-uni run typecheck
npm --prefix mobile-uni run build:h5
npm --prefix mobile-uni run build:app

真实页面:

  1. 390×844 打开“问”,提出固定问题;
  2. 展开引用并点击;
  3. 文本详情自动滚动、高亮且无需水平滚动;
  4. 图片可打开、缩放和返回;
  5. 视频进入详情页并定位;
  6. 撤权/过期状态有明确提示;
  7. 返回问答页后会话和展开状态可预测;
  8. 控制台无错误,页面无无限加载。

阶段 3 实际结果记录

字段 实际值
状态 实现中
构建源 2026-08-02 本轮修复提交见 Git 历史;该提交不代表生产发布
Node tests node --test mobile-uni/tests/*.test.mjs:217/217 通过,包含 H5 媒体地址不得落入 /h5/dev-api/ 的回归测试
typecheck npm --prefix mobile-uni run typecheck:通过
H5/App build npm --prefix mobile-uni run build:h5:通过;本轮未重跑 App-Plus 构建
390×844 文本/图片/视频 本机合成已发布资产 3/3:文本详情及命中高亮、图片原图及放大、视频详情均按对应形式呈现
视频实播 合成 MP4 readyState=4、时长约 10.03s、尺寸 320×176,播放时间由 0 推进到约 2.36s
错误状态 详情页无引用参数正确显示不可查看状态;点击“返回问答”回到首页
遗留项 App-Plus/Android 真机、正式资源和正式账号验收仍未完成;本机合成素材不得作为生产样本

本次浏览器复核(2026-07-31,指定在职测试账号切换后):通过内置 Browser 完成退出旧会话、重新获取验证码、登录和进入员工端“问”页面;固定制度问题返回真实回答并展开 3 条引用。当前 3 条引用均为旧知识片段,DOM 中 .citation-action 与“查看出处”入口均为 0,因此没有可安全构造的 detailRef,未伪造详情 URL。已保存脱敏页面证据:output/citation-source-viewer/20260731-local/question-citations-expanded.png。本次验证结论为“引用展示通过,出处详情被定位数据缺失阻断”,不计入文本/图片/视频 3/3 详情门禁。


7. 阶段 4:历史资料定位回填与安全降级

目标: 为现有正式资料补定位能力,但不重写正式来源审批、文档哈希或既有片段事实。

Files

  • Create: scripts/backfill-knowledge-fragment-locators.mjs
  • Create: scripts/verify-knowledge-fragment-locators.mjs
  • Create: backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/service/AihrKnowledgeLocatorBackfillService.java
  • Test: backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/knowledge/AihrKnowledgeLocatorBackfillServiceTest.java
  • Modify: docs/KNOWLEDGE_PLATFORM_RUNBOOK.md

Task 4.1:只读计划

回填必须先输出:

  • 候选附件数;
  • 已有 locator 数;
  • 可按内容哈希确定性匹配数;
  • 需要重新解析数;
  • 无原文件、解析失败或歧义数;
  • 正式来源数量及其审批/哈希状态。

默认只读,不接受浏览器传入目录,不自动删除或替换资料。

Task 4.2:确定性回填

  • 优先按 tenant + knowledge + docId + fragmentId 和规范化文本哈希匹配;
  • 重解析只生成 locator,不改变原始文件 SHA-256、治理审批或知识空间授权;
  • 匹配不唯一时标记 AMBIGUOUS,不得猜测页码或时间;
  • 旧视频只有粗 [mm:ss] 时标记定位精度;
  • 无法精确回填的资料仍可打开全文/原文件,页面显示“暂无精确位置”。

Task 4.3:生产执行边界

  • 本地和测试库先跑;
  • 生产先只读 plan;
  • 正式写入属于数据库变更,必须生成完整 MIGRATE_DB:<hash> 授权串并单独获得授权;
  • 每批限制数量,可中断、可重跑;
  • 回填失败不得删除已有 fragment、embedding、Qdrant point 或正式来源记录。

阶段 4 验证

必须报告真实分母:

attachments_total
locators_before
locators_created
exact
coarse
ambiguous
failed
formal_sources_unchanged
fragments_unchanged
qdrant_points_unchanged

随机抽检至少:

  • 5 份文本/PDF/PPT;
  • 3 张图片;
  • 3 段视频;
  • 所有 AMBIGUOUS/FAILED 小样本或最多 20 项。

阶段 4 实际结果记录

字段 实际值
状态 实现中
构建源 阶段 4 实现已进入当前分支;2026-08-02 本轮未新增该阶段代码
计划分母 attachments_total=5,locators_before=15
exact/coarse/ambiguous/failed exact=15,coarse=0,ambiguous=0,failed=0;locators_created=0
抽检 已核对本地 5 个 seed 附件及 15 条 locator;未覆盖计划要求的 PDF/PPT/图片/视频抽检样本
正式来源未变化 formal_sources_unchanged=0(本地无治理来源记录,未写入正式来源)
fragment/Qdrant 未变化 fragment 与 Qdrant 未变化(只回填 locator)
证据目录 output/citation-source-viewer/20260731-local/
遗留项 需要公开合成六类样本及生产正式来源状态后再完成阶段门禁

8. 阶段 5:全链路、安全、性能与回归门禁

目标: 证明新功能不会扩大权限、破坏问答、拖垮大文件播放或泄漏受保护资料。

自动化矩阵

必须覆盖:

  • TEXT/PDF/DOCX/PPTX/XLSX/IMAGE/VIDEO;
  • 新旧引用响应兼容;
  • 当前员工正授权;
  • 跨员工、跨项目、跨空间、跨租户、停用应用;
  • 来源撤回、版本替换、哈希漂移;
  • 票据过期、重放和跨资源复用;
  • Range 首段、中段、尾段和非法范围;
  • 500MB 契约下不要求客户端先下载整个视频;
  • 连续打开/关闭 20 次无 Blob URL 和播放器泄漏;
  • Agent 普通问答、无依据、冲突和越权原有行为不变。

固定技术阈值

指标 门槛
跨租户/越权泄漏 0
正式政策无引用详情入口 0,旧无定位资料除外且必须明确降级
文本目标片段定位 100% 固定样本
图片原图匹配 100% 固定样本
视频业务定位误差 ≤500ms;精确帧以保存帧图核验
Range 合法范围 206,非法范围正确拒绝
详情元数据 API p95 本地基准 ≤1s
内网视频首帧 固定样本 ≤5s
内网二次 seek 完成 固定样本 ≤3s
原问答回归 既有专项测试全部通过
敏感信息扫描 0 个 token/票据/OSS 原址/手机号

性能结果必须同时记录机器、网络、样本大小和运行次数,不能只写平均值。

阶段 5 实际结果记录

字段 实际值
状态 实现中
构建源 2026-08-02 本轮修复提交见 Git 历史;该提交不代表生产发布
后端测试 AihrKnowledgeResourceRangeTest:2/2 通过
移动端测试 Node 217/217、typecheck、H5 build 通过;本轮未重跑 App-Plus 构建
越权矩阵 未完成真实后端矩阵;仅完成源码级治理约束复核
定位误差 未测量;无真实视频引用数据
Range 本机合成授权视频完整请求 200、Range 请求 206;未覆盖首段/中段/尾段/非法范围完整矩阵
p50/p95 未测量
资源泄漏循环 Node 单元覆盖 Blob URL 释放,未完成 20 次真实页面循环
敏感信息扫描 移动端截图/DOM 证据未包含手机号、验证码、令牌、票据或 OSS 原址;后端日志扫描未完成
证据目录 output/citation-source-viewer/20260731-local/
遗留项 正反权限矩阵、完整 Range 矩阵、定位误差、性能基准、资源循环和生产/真机证据仍待补齐

9. 阶段 6:发布与 Android 真机收口

目标: 将完成门禁的 schema、后端和移动端作为独立发布单元部署,并用正式账号与新签名 APK 验证。

9.1 发布单元

单元 触发条件 授权与验证
schema 新定位表/索引 先备份和只读计划;独立 MIGRATE_DB:<hash> 授权
后端 JAR 详情、鉴权、Range、回填服务 release-backend.sh plan;独立 DEPLOY_BACKEND:<hash> 授权
管理端 仅当新增回填/状态管理页 单独构建、备份和静态发布;不得覆盖 /h5
H5 引用详情页面 备份 /opt/wygj/www/h5 后定向同步
Android mobile-uni 页面和逻辑变化 版本号与 versionCode 递增,重新出包、深检和真机安装

0.1.17 (117) 不包含本计划功能。Android 验收必须使用后续新包,不得以 H5 发布替代 APK。

Windows 上的后端发布计划明确使用 Git Bash:

& "C:\Program Files\Git\bin\bash.exe" scripts/release-backend.sh plan ...

不得改用 WSL bash,不得绕过脚本手工覆盖 JAR。

9.2 生产发布后验证

后端与 schema:

  1. 服务 active;
  2. 公开健康入口 HTTP 200;
  3. schema 预检通过且运行时 DDL 关闭;
  4. 正式账号文本、图片、视频详情正例;
  5. 无权限账号、撤权和过期票据反例;
  6. 视频 Range 206;
  7. 日志无敏感数据。

H5:

  1. 390×844 实际点击三类引用;
  2. 刷新、返回、弱网和失权状态;
  3. 不破坏“今日/练/问/我”导航和既有 Agent 会话。

Android 真机:

  1. 新签名 APK 覆盖安装与冷启动;
  2. 正式员工账号真实发问并打开文本引用;
  3. 打开图片引用并缩放;
  4. 打开视频引用,自动定位语句和画面;
  5. 切后台再返回,定位和权限状态正确;
  6. 切断网络后有明确错误,恢复网络可重试;
  7. 撤权后再次点击失败关闭;
  8. 无 Crash/ANR,测试后恢复设备权限和清理临时文件。

至少在当前 vivo Android 15 真机完成主证据;扩大试点前再补一个不同 Android 大版本或厂商。手机号、验证码、令牌和受保护正文不得出现在截图、录像文件名或报告中。

阶段 6 实际结果记录

字段 实际值
状态 未开始
release commit 未发布;2026-08-02 本机修复提交不等于生产发布
schema 版本/迁移结果 仅本地 Docker 数据库验证;未执行生产迁移
生产 JAR SHA-256 未生成/未部署
H5 构建与远端哈希 本地 H5 构建完成;未生产发布、未计算远端哈希
APK 版本/versionCode App-Plus 构建输入完成;未出包、未安装真机
APK SHA-256/签名摘要 未生成
生产正反权限 未验证
真机型号/Android 未验证
文本/图片/视频 0/3,未进行正式账号真机验收
视频定位误差 未测量
Crash/ANR 未验证
回滚物 未生成
证据目录 output/citation-source-viewer/20260731-local/(仅本地浏览器证据)
遗留项 未授权生产部署;未完成正式账号、Android 真机、签名 APK 和正式资源验收

10. Go/No-Go

只有以下全部成立,才能称“手机端引用详情与媒体定位已完成生产验证”:

  • 阶段 1—5 均有实际结果且状态为 技术通过;
  • schema、后端、H5/Android 实际发布范围与本地构建一致;
  • 正式账号文本、图片、视频 3/3 通过;
  • 跨租户、撤权、过期和伪造反例全部拒绝;
  • 视频 Range 和定位误差达到门槛;
  • 新 Android APK 完成真机验证;
  • 无 Crash/ANR;
  • 回滚物、哈希和证据目录完整;
  • 未把 DCloud 测试签名描述为企业签名或应用商店包。

任一项缺失时,结论只能是:

  • “本地技术通过,待生产发布”,或
  • “生产后端/H5 已通过,待 Android 新包真机”,或
  • “文本/图片可用,视频精确定位仍阻断”。

不得用“引用已经能展开”“原文件可以下载”或“视频可以播放”替代本计划的定位、权限和真机证据。