# 周边扫码验真 + 加入藏品 Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 用户扫描 `https://topfans.online/verify/{assetId}` 二维码,看到验真信息(品牌/公司/链上哈希/验证次数等),确认后一键加入我的藏品 **Architecture:** 双端共用同一组后端 REST 接口(app 内 + 外部 H5 都走 `/api/v1/assets/:asset_id/{verification,mint-to-my-collection}`);Deep link 让外部扫码直接跳 app;加入藏品走简化 mint,跳过 AI 链路,直接 INSERT `asset_registry(asset_type='peripheral')` **Tech Stack:** - Backend: Go 1.21+ / Dubbo-go / Gin / GORM / PostgreSQL - Frontend: uni-app + Vue 3 (组合式 API + ` ``` - [ ] **Step 2: 验证编译** ```bash cd frontend npm run build:app-plus ``` 预期:无错误。 - [ ] **Step 3: 真机手动验收(按 §8.3 清单)** - [ ] **Step 4: Commit(等待用户指示)** --- ## Task 16: 前端 App.vue — 监听 deep link **Files:** - Modify: `frontend/App.vue` **Interfaces:** - Produces: `onLaunch` / `onShow` / `newintent` 监听 deep link,调用 `scanLaunch.js#onDeepLinkTo` - [ ] **Step 1: 阅读现有 App.vue 结构** ```bash cat frontend/App.vue | head -50 ``` - [ ] **Step 2: 在 App.vue#onLaunch / onShow 加入 deep link 处理** 在 `App.vue` 的 ` ``` - [ ] **Step 3: 手动验证(CI 替换前)** 本地用浏览器打开 `frontend/static/verify/verify.html`(可能需要起 static server),确认: - 路径不匹配时显示"二维码格式不正确" - 路径匹配但 fetch 失败时显示"网络错误" - [ ] **Step 4: Commit(等待用户指示)** --- ## Task 20: 部署 — .well-known/ 声明文件 **Files:** - Create: `frontend/static/.well-known/apple-app-site-association` - Create: `frontend/static/.well-known/assetlinks.json` **Interfaces:** - Produces: 2 个 JSON 声明文件,部署到 `topfans.online/.well-known/` 后 OS 才能识别 deep link - [ ] **Step 1: 创建 apple-app-site-association** 在 `frontend/static/.well-known/apple-app-site-association` 写入(**不带 `.json` 后缀**): ```json { "applinks": { "apps": [], "details": [{ "appIDs": ["TEAMID.com.topfans.app"], "components": [ { "/": "/verify/*", "comment": "周边验真扫码" } ] }] } } ``` > ⚠️ 发布前必须把 `TEAMID` 替换为 Apple Developer 后台真实 Team ID;占位发布会导致 UniversalLinks 失效。 - [ ] **Step 2: 创建 assetlinks.json** 在 `frontend/static/.well-known/assetlinks.json` 写入: ```json [{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.topfans.app", "sha256_cert_fingerprints": [""] } }] ``` > ⚠️ 发布前必须把 `` 替换为正式 Release Key 的 SHA256(不是 debug key)。 - [ ] **Step 3: 提交运维上线** 把 2 个文件交给运维: 1. 部署到 `https://topfans.online/.well-known/apple-app-site-association` 2. 部署到 `https://topfans.online/.well-known/assetlinks.json` 3. nginx `Content-Type: application/json`(iOS 严格要求) **上线顺序必须严格串行**(见 §9 部署): 1. .well-known/ 上线 2. nginx rewrite (`/verify/*` → `/verify/verify.html`)上线 3. 新版本 app 包(含 `associatedDomains` + `intentFilters`)上架 - [ ] **Step 4: Commit(等待用户指示)** --- ## Task 21: 部署 — CI 注入 API_BASE **Files:** - Modify: CI 配置文件(`Makefile` 或 `package.json#build`) **Interfaces:** - Produces: 构建流水线在 `frontend/build` / `npm run build` 时执行 `sed` 替换 `verify.html` 的 `__API_BASE__` 占位符 - [ ] **Step 1: 阅读现有 CI / Makefile / package.json#build** ```bash cat frontend/Makefile 2>/dev/null | head -30 cat frontend/package.json | grep -A 5 '"scripts"' | head -20 ``` - [ ] **Step 2: 在 build 脚本中追加 sed 替换** 在 `package.json` 的 `scripts.build` / `scripts.build:app-plus` 中追加(以 `&&` 串联): ```json "build:verify": "sed -i.bak 's|__API_BASE__|'\"$VITE_API_BASE_URL\"'|g' frontend/static/verify/verify.html" ``` (在原 build 命令前插入;若用 Makefile,把 sed 加进 `build` target) - [ ] **Step 3: 验证替换效果** ```bash cd frontend VITE_API_BASE_URL=https://api.topfans.com npm run build:verify grep "__API_BASE__" frontend/static/verify/verify.html # 预期:无匹配(已被替换) grep "https://api.topfans.com" frontend/static/verify/verify.html # 预期:1 处 ``` - [ ] **Step 4: Commit(等待用户指示)** --- ## Task 22: 端到端联调(无 Vitest,按 §8.3 手动清单) **Files:** - Modify: 无(纯手动验收) **Interfaces:** - 验证 spec §8.3 的所有清单项 - [ ] **Step 1: app 内验收(按 spec §8.3 app 内清单)** - [ ] 广场头部扫码按钮可见可点 - [ ] 扫到非项目 URL 弹 "二维码格式不正确" - [ ] 未登录扫码跳 portal,登录后回到验真页 - [ ] 验真页信息展示顺序正确(品牌/公司/链上哈希/验证次数/验证人/首次验证) - [ ] "💡 加入前请对比实物..." 纯文字提示显示 - [ ] "加入我的藏品" 首次点击 → toast 成功 + 跳 asset-detail - [ ] 重复点击 → toast "您已添加过此周边" + 按钮变 "查看我的藏品" - [ ] 验真页 asset 不存在时空态正确 - [ ] **Step 2: H5 验收(按 §8.3 H5 清单)** - [ ] 微信扫码直接打开 H5 - [ ] H5 渲染与 app 内一致(数据同源) - [ ] H5 "加入我的藏品" 触发 deep link,已装 app 跳 app - [ ] H5 未装 app(降级测试)1.5s 后显示下载引导 - [ ] **Step 3: Deep link 验收(按 §8.3 Deep link 清单)** - [ ] iOS UniversalLinks:微信扫 → 跳 app → 进入验真页 - [ ] Android App Links:同上 - [ ] app 在后台被唤起,提取 deep link 参数 → 跳验真页 - [ ] app 已关闭被冷启动,提取 deep link 参数 → 跳验真页 - [ ] **Step 4: 兼容验收** - [ ] iOS 13+ iPhone 真机 - [ ] Android 8+ 真机 - [ ] 微信内置浏览器 / Safari / Chrome - [ ] **Step 5: 报告验收结果** 把验收清单的勾选结果写一份 `docs/superpowers/verification/2026-07-10-qrcode-peripheral-auth-acceptance.md`,标注任何 fail 项。 --- ## Self-Review(plan 完成后的内检) **Spec coverage**(检查每条 spec 章节都有 task 覆盖): | Spec 章节 | 对应 Task | |----------|----------| | §1.1 前端新增 | Task 12, 14, 15, 19 | | §1.2 前端修改 | Task 13, 16, 17, 18 | | §1.3 后端新增 | Task 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 | | §1.4 部署改动 | Task 20, 21 | | §2 URL 与解析 | Task 12 | | §3 UI 设计 | Task 15, 19 | | §4 数据契约 | Task 8 (DTO 字段对应 §4.1/§4.2 JSON) | | §5 Deep Link | Task 16, 17, 20 | | §6 后端实现 | Task 1, 2, 3, 4, 5, 6, 7 | | §7 错误处理 | Task 9 (handleServiceError), Task 6, 7 (BizError) | | §8 测试 | Task 3, 4, 5, 10 (后端单测), Task 22 (手动验收) | | §9 部署 | Task 20, 21 | | §10 MVP 边界 | 各 task 严格遵守(无抽象、无 MintStrategy)| | §11 自检清单 | 全局约束已写入每个 task | **Type consistency**: - `BizError.Code` int,`BizCodeAssetNotFound = 50003` 常量 ✓ - `InsertPeripheralRegistry` 返回 `(newID, createdAtMs, err)` ✓ - `MintResult.MintedAt` = `createdAtMs / 1000` ✓ - `VerificationResult.VerifiedAt` = `info.FirstVerifiedAt / 1000` ✓ **Placeholder scan**: 无 TBD / TODO / "implement later" / "fill in details"。 **No dead references**: 所有 type/function 都在前面的 task 定义。 --- ## Execution Handoff Plan 已保存到 `docs/superpowers/plans/2026-07-10-qrcode-peripheral-authentication.md`,22 个 task,覆盖前后端完整链路。 **两种执行方式:** 1. **Subagent-Driven(推荐)** — 每个 task 派发独立 subagent,task 间做两阶段 review,快速迭代 2. **Inline Execution** — 在当前会话按顺序执行,带 checkpoint 复盘 请告诉我选哪种方式?或者先看看 plan 有没有需要调整的地方?