Files
cmbuyer/docs/tasks/T-204.md
T

7.6 KiB
Raw Blame History

id, title, phase, deps, status, created, vikunja_task_id, context_ref, work_branch, needs_device, needs_human_review, write_paths
id title phase deps status created vikunja_task_id context_ref work_branch needs_device needs_human_review write_paths
T-204 路由化任务详情与内部截图资产 2
T-203
TODO 2026-08-04 31 20aaba0 task/t-204-details-evidence false false
docs/tasks/T-204.md
admin/migrations/00003_evidence_assets.sql
admin/internal/migrations/migrations_test.go
admin/internal/evidence/**
admin/internal/storage/evidence/**
admin/internal/taskdetail/**
admin/internal/config/**
admin/internal/server/**
admin/internal/transport/webui/**
admin/cmd/server/**
admin/README.md
docs/api.md
docs/routes.md
docs/04-architecture.md

问题 / 背景

T-203 已完成传统任务表格与批量“开始采购”授权。采购管理员还缺少可复制、可返回的任务详情,以及只供内部审计的规格面板/确认页原始截图。T-204 提供详情与截图资产底座;不实现 T-205 的 attempt/event 写入,不实现 T-306 的客户端上传调用。

关联需求与交互

  • 功能:F-007、F-011。
  • 用户故事:US-002、US-004、US-007。
  • 交互:IX-003、IX-004;双击非控件区域或 Enter 打开同一 /tasks/{id},直达显示完整页,列表增强为抽屉。
  • 架构/API:GET /tasks/{id}、POST /api/v1/tasks/{id}/evidence、GET /evidence/{asset_id}。

方案

  1. 新增任务详情只读查询,返回任务要求、状态、版本、授权摘要和当前已有的 attempt/submission/evidence 摘要;缺少后续事实时显示明确空态,不伪造数据。
  2. GET /tasks/{id} 以同一数据模型渲染完整页或同源 HTML fragment。列表行双击非交互区域、键盘 Enter 打开抽屉并把 URL 推到同一路径;Esc、关闭或浏览器返回恢复筛选、滚动与触发行焦点。外部商品链接、复选框和批量按钮不得触发行详情。
  3. 详情是审计视图,不提供试选后确认、再次提交、付款自动化或围栏后重试。状态文案始终区分“订单已创建,系统尚未付款”。
  4. 新建 evidence_assets 迁移和存储边界:只接收明确的单个 PNG screenshot;attempt_id 必填且必须属于 URL 中的 task。元数据仅允许 upload_key、attempt_id、kind、privacy_tier=INTERNAL_RAW、sha256、captured_at;记录 MIME、字节数、宽高、存储键和上传主体。
  5. 上传先经注入的 DeviceAuthenticator;T-301 前生产默认拒绝,测试可用 fake principal 验证契约,不创建临时 token 或共享密钥。T-301 完成后再接真实 Bearer 身份。
  6. multipart 设严格总大小、字段/单文件限制;拒绝未知字段、重复字段、XML/manifest/目录/本机路径、非 PNG、魔数/DecodeConfig/尺寸/hash 不一致以及未批准的截图 kind。服务端文件名只由资产 id/存储键生成,不使用上传名。
  7. 文件同目录临时写、流式 SHA-256、校验、fsync、原子 rename 后才写 DB;故障只允许产生不可达孤儿,不允许 DB 指向缺失或半文件。upload_key 同任务同载荷幂等,载荷变化冲突,并发只生成一条可读资产。
  8. GET /evidence/{asset_id} 仅有效管理员会话可读,返回 image/png、Cache-Control: no-store、X-Content-Type-Options: nosniff;未登录不泄露资产是否存在,不经静态目录暴露。
  9. UI 采用现有采购服务高密度表格风格:可见关闭按钮、焦点圈、44px 交互目标、截图 width/height 预留和 lazy loading、响应式布局、reduced-motion;不得只有双击一种入口。
  10. T-204 明确定值单文件最大 10 MiB、解码后最大 16,777,216 像素;证据目录由显式配置提供。保留期限仍由后续部署任务定值,不在本任务自动删除资产。

验收要点

  • 详情完整页与抽屉使用同一路由/数据;刷新/复制 URL、浏览器返回、Esc、焦点和滚动/筛选恢复均有测试。
  • 不存在、畸形 id、未登录、fragment 伪造请求均 fail closed,不泄露内部错误。
  • 上传覆盖认证矩阵、multipart 负例、PNG 魔数/解码/大小/尺寸/hash、未知/重复字段、任务/attempt 归属、路径穿越、幂等冲突/并发及原子故障注入。
  • 截图读取覆盖管理员会话、未登录、缺失资产和 no-store/nosniff;完整 XML、支付页和凭据不会进入接口或 Git。
  • 运行 Go 全量/竞态/vet/build、Node 测试与语法检查、完整 init、上下文校验和 diff-check。

执行记录

待认领。

执行记录

(暂无)

边界

  • 本任务只实现管理员任务详情、内部 PNG 证据资产底座和受保护读取;不实现 T-205 的 attempt/event 写接口、闸门计算、失败分类、提交围栏或结果调和,不实现 T-306 的客户端截图与上传调用。
  • T-301 完成前不得发明临时设备 token、共享密钥或把管理员会话当设备身份。上传 handler 必须先调用窄 DeviceAuthenticator;生产默认实现一律拒绝,只有测试可以注入 fake principal。
  • 上传只接受一个调用方显式选择的 PNG;不得枚举目录,不接收 XML、manifest、本机路径、原文件名、 任意备注、Cookie、token、支付凭据或未批准的截图 kind。MVP 本任务只开放 SKU_PANEL_GATE_1,后续 kind 必须在对应任务中收紧扩展。
  • attempt_id 必填且必须以复合外键证明属于 URL 中的 task。privacy_tier 只能是 INTERNAL_RAW;截图可含页面已显示的地址/手机号,但服务端不得 OCR、提取、索引、搜索或写日志。
  • 单文件最多 10 MiB,单边最多 8192 px,解码后最多 16,777,216 像素;必须同时校验 multipart 类型、 PNG 魔数、解码结果、字节数、尺寸与调用方声明的 64 位小写 SHA-256,任一不符零发布。
  • 文件必须在显式配置的证据根目录内以服务端生成的内容地址落盘,不进入公开静态目录。先同目录临时写、 流式 hash、fsync、原子 rename,再写数据库;故障最多留下不可达孤儿,不得留下指向半文件或缺失 文件的可见数据库记录,也不得为清理孤儿而删除并发复用文件。
  • 同一设备主体与 upload_key 的相同规范请求只返回原资产;内容、任务、attempt 或元数据变化一律 409。不得把 SHA-256 当业务记录唯一键,因为不同合法证据可以复用相同物理内容。
  • GET /evidence/{asset_id} 只允许有效管理员会话,必须返回 Cache-Control: no-store 和 X-Content-Type-Options: nosniff;匿名请求先拒绝,不泄露资产是否存在,不提供公开 URL、目录浏览、 批量导出、删除或预签名链接。
  • /tasks/{id} 的抽屉与完整页必须共享同一数据和详情模板。双击不是唯一入口;Enter、可见关闭按钮、 Esc、浏览器前进/后退、焦点与列表滚动/筛选恢复均可用,外部商品链接、复选框、输入框和按钮不得误触 行详情。截图必须预留尺寸、响应式缩放、延迟加载,alt 不转录地址或手机号。
  • 详情是只读审计视图,不制造不存在的 attempt/event/闸门/提交事实,不出现“机器选对了吗”、围栏后 重试、再次提交或自动付款动作。截图不作为价格闸门通过或人工审批的唯一依据。
  • 本任务不实现、不调用通用真机点击、submit_order_once()、支付、免密支付、先用后付或任何扣款能力; 既有三道价格闸门、服务端提交围栏、唯一点击一次且不重试的规则不得放宽。