Page:
T-203
Pages
00-ai-start-here
01-vision
02-requirements
03-tech-stack
04-architecture
05-coding-rules
06-tasks
07-user-stories
08-interaction-checklist
Design
Home
Integrations-shunyunbao-contract
PPT
T-001
T-002
T-003
T-004
T-101
T-102
T-103
T-104
T-201
T-202
T-203
T-204
T-205
T-206
T-207
T-208
T-209
T-210
T-211
T-212
T-213
T-214
T-215
T-216
T-217
T-218
T-219
T-220
T-221
T-222
T-223
T-224
T-225
T-226
T-227
T-228
T-229
T-230
T-231
T-232
T-233
T-234
T-235
T-236
T-237
T-238
T-239
T-240
T-241
T-242
T-243
T-244
T-245
T-246
T-247
T-248
T-249
T-250
T-251
T-252
T-253
T-254
T-255
T-256
T-257
T-258
T-259
T-260
T-261
T-262
T-263
T-264
T-265
T-266
T-267
T-268
T-269
T-270
T-271
T-272
T-273
T-274
T-275
T-276
T-277
T-278
T-279
T-280
T-281
Task-Template
Tasks
agent-context
api
clean-state-checklist
current-state
routes
Clone
Table of Contents
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
同步来源:
docs/tasks/T-203.md· commitafc651f75a3a
id: T-203 title: 实现任务创建 API 与管理 Web phase: 2 deps:
- T-201
- T-202
status: DONE
created: 2026-07-26
context_ref:
2b265c9work_branch: main write_paths: - backend-api/**
- init.ps1
- init.sh
- docs/00-ai-start-here.md
- docs/02-requirements.md
- docs/03-tech-stack.md
- docs/04-architecture.md
- docs/05-coding-rules.md
- docs/07-user-stories.md
- docs/08-interaction-checklist.md
- docs/api.md
- docs/current-state.md
- docs/design/admin-task-create.html
- docs/design/admin-task-detail.html
- docs/design/android-task-preview.html
- docs/design/android-candidate-confirm.html
- docs/tasks/T-203.md
- progress.md
问题 / 背景
T-201 只有健康检查、SQLite 和 migration 骨架,T-202 只确认了页面信息结构。当前还
不能从管理端安全上传参考图、创建 PENDING 任务、查看真实列表/详情或取消待领取
任务,因此 T-205 的原子领取没有可消费的数据。
审计还发现正式合约存在四个会阻断后续 App 接入的问题:
- 现有 Android
ProbeTask强制标题和 SKU 非空,但任务创建 API/数据表遗漏 SKU。 - 已确认 Web 使用“最高总预算”,部分 Android 原型误写成每件预算。
- API/原型允许 JPEG/PNG/WebP,但 Android 需求提取当前只接受 JPEG。
- 管理会话属于 T-204,T-203 不能伪造登录或永久开放匿名管理接口。
关联需求与交互
- 功能:F-001、F-002,以及 F-007 的最小可见错误。
- 用户故事:US-001、US-002。
- 交互:IX-002、IX-003;登录 IX-001 留给 T-204。
- 页面:
/tasks、/tasks/new、/tasks/{id}。 - API:资产上传、任务创建/列表/详情、待领取任务取消。
已定合约
- 标题和 SKU 必填;描述可空。标题最多 120 个 Unicode 字符且不超过 2048 个 UTF-8 字节,SKU 不超过 512 个 UTF-8 字节,描述不超过 8192 个 UTF-8 字节。
max_budget表示当前任务全部数量的最高商品总预算,币种 CNY,不含无法确认的 运费或优惠;数据库用整数分保存,API 固定输出两位小数字符串。- 参考图上传接受可解码 JPEG/PNG/WebP,原始请求最多 20 MiB、最长边最多 10000 px、总像素最多 25 MP;后端统一缩放到最长边不超过 2048 px、白底合成并 编码为匿名 JPEG。响应的媒体类型、大小和 SHA-256 都指向规范化结果。
- SKU、数量和总预算属于不可变原始事实,任何派生结果都不能覆盖。
- 列表增加
q,匹配任务 ID、来源引用、标题或 SKU;分页固定按created_at DESC, id DESC,cursor 同时包含两个字段。 - T-203 只提前实现事务化
PENDING -> CANCELED;其他状态取消返回冲突,完整取消 请求和状态机属于 T-205。 - T-204 前,管理 Web/API 业务路由只接受 loopback 来源;Web 写操作还必须携带
SameSite Cookie 与表单字段匹配的随机双提交 CSRF token,API 创建/上传必须使用
JSON 或 multipart 与自定义幂等头。
/login不提供假实现,局域网部署仍被明确 阻塞。 - 创建、上传均按调用主体、操作和
Idempotency-Key幂等;同 key 同请求返回原 资源,同 key 不同请求返回409。
方案
- 增加 assets、purchase_tasks、task_events 和 idempotency_records migration, 包含外键、CHECK、唯一约束和 rollback。
- 建立 domain/usecase/repository/sqlite 分层;handler 和模板不得直接执行 SQL。
- 建立受控文件存储与图片规范化器,随机相对路径、同目录临时文件原子改名,失败时 清理;数据库和响应永不暴露绝对路径。
- 实现 JSON/multipart API 和稳定错误映射,保持无默认 CORS、request ID 与 recovery 安全约束。
- 用
html/template、embed、原生 CSS/JS 实现列表、新建和详情;真实数据为空时 显示空状态,不把原型假数据写入数据库。 - Web 表单无 JS 也可完成,使用 PRG
303;JS 只负责图片预览、防重复、离开提醒 和取消确认。
验收要点
- migration 可 up/down/up,约束和外键有效,启动前 migration 门禁明确。
- JPEG/PNG/WebP 被真实解码并规范化为 JPEG;伪 MIME、损坏、超限和像素炸弹拒绝。
- 合法任务创建为唯一
PENDING,原始 title/SKU/quantity/budget/image 不可变。 - 上传和创建幂等;同 key 不同请求冲突,并发重试不产生重复资源。
- 列表筛选、搜索、稳定 cursor 和详情返回真实数据,404 不泄露内部信息。
- 只有
PENDING可立即取消;终态或不支持状态返回稳定冲突。 - Web 覆盖空列表、创建字段错误、图片错误、成功跳转、详情和取消二次确认。
- 非 loopback 业务请求、缺失/错误 CSRF、错误 Content-Type 被拒绝。
- HTML 自动转义,日志/响应不含 Cookie、文件绝对路径、私有样本或请求正文。
- Go test/race/vet/gofmt、迁移 smoke、真实 HTTP/Web smoke 和 Playwright 通过。
边界
- 不实现管理登录、Cookie 会话、用户表/密码哈希或设备鉴权;属于 T-204。
- 不实现 claim、租约、执行状态机、候选、执行证据或 App HTTP TaskSource。
- 不开放非 loopback 管理使用;T-204 完成前不能部署到局域网供其他用户访问。
- 不实现对象存储、ORM、SPA、WebSocket、推送或自动下单。
- 不提交运行时数据库、上传文件、密钥或真实订单/店铺/商品数据。
执行记录
2026-07-26:任务开始
- 基于提交
2b265c9开始,工作区干净。 - codebase-memory MCP 本轮未暴露 graph 工具,按项目规则回退到
rg和定点文件读取。 - 已审计 T-201 现有 config/database/migration/httpapi/cmd 骨架、T-202 原型以及 requirements/API/architecture/IX,先固定上述跨层合约再编码。
2026-07-26:合约和实现
- 修正正式需求和原型中的 SKU、最高总预算、图片格式与验收编号;总预算统一指当前 任务全部数量的商品预算,模型不得覆盖 SKU、数量或预算。
- 新增
00002_tasks_and_assets.sql,建立 assets、purchase_tasks、task_events 和 idempotency_records;字段长度、UTF-8 字节、外键、状态、金额和唯一性均有数据库 约束。 - 建立 domain/usecase/repository/sqlite 分层,上传和创建事务化幂等,列表按
created_at DESC, id DESC稳定分页,待领取取消使用状态与 version 条件更新。 - 文件层真实解码 JPEG/PNG/WebP,限制 20 MiB、10000 px 和 25 MP,白底缩放至最长 边 2048 px 后以质量 90 编码为随机相对键 JPEG;绝对路径不进入数据库外部响应。
- Gin API 实现上传/读取资产、创建/列表/详情/取消任务;业务路由在 T-204 前只接受 loopback,错误使用稳定 code、request ID 和 no-store 响应。
- 管理 Web 使用嵌入模板/CSS/JS,实现真实空列表、搜索筛选、创建、图片预览与复用、 详情参考图和取消确认;使用双提交 CSRF、PRG 303、HTML 自动转义和固定 CSP。
- API 启动前检查全部 migration;存在 pending 版本时拒绝启动并明确提示执行
migrate up,服务进程不自动修改数据库。
2026-07-26:自动验证
GOTOOLCHAIN=local go test -count=1 ./...:99 个测试通过;覆盖领域校验、金额、 图片限制、路径防护、迁移约束、事务幂等、并发、分页、HTTP 生命周期、CSRF 和 模板安全。go test -race -count=1 ./...、go vet ./...、gofmt -l cmd internal migrations和 API/migration Windows 构建全部通过。- 真实 migration CLI 完成
status -> up -> up -> down -> API gate -> up:首次applied=2、重复为 0,回滚 v2 后 API 以退出码 1 拒绝旧库,恢复后 v1/v2 均applied。 httptest使用临时真实 SQLite/asset 目录跑通:上传及幂等重放、创建及重放、SKU 搜索、详情、JPEG 内容读取、取消和重复取消;非 loopback 和缺失幂等键被拒绝。- Playwright 连接真实 Gin/SQLite 进程完成创建任务和详情读取;1440x900、
390x844、360x800 均无横向溢出,可见操作控件最小 44 px,规范化参考图
naturalWidth=64、naturalHeight=48且成功加载,只有同源 HTML/CSS/JS/资产请求, 新页面 console 为 0 error、0 warning;取消对话框默认聚焦“保留任务”。 - 根
init.ps1通过:Androidtest assembleDebug共 76 个 Gradle task 成功, 现有 166 次测试保持通过;随后 Go 测试、vet、格式检查和两个入口构建再次通过。
2026-07-26:隐私与收尾
- 测试只使用代码生成的脱敏小图、标题和 SKU;未读取、复制或提交本地蝦皮订单、 店铺名、真实商品文字或图片。
- Playwright、数据库、资产和 exe smoke 产物只保存在被忽略的
.local/、bin/或var/,未纳入 Git;业务响应和管理页面不显示客户端文件名或服务端存储路径。 - T-203 验收全部满足,状态改为
DONE;T-204 可开始实现正式管理会话和角色门禁。