Files
junhong_cmp_fiber/openspec/changes/archive/2026-09-15-add-phone-asset-associations/tasks.md
break 70e680eb0a
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m2s
feat(手机号资产关联): AUG26-009 手机号—资产关联、十项上限与后台解绑
- 新增成对迁移 000223(tb_phone_asset_association,含有效关系部分唯一索引与 down 守卫)与 000224(解绑导入任务表),不回填历史
- H5:need_bind_phone 三支判定(开关关闭完全短路);已有主号幂等建联;十项上限按手机号 advisory 串行化(含换绑到全新号的并发场景);换绑原子迁移与冲突整单回滚;不写遗留列
- 后台:关联列表、单项/批量解绑、CSV 导入解绑(B1–B16),超管/平台 gate + 资产数据范围复核,三态统一文案
- 读侧:卡/设备列表与详情按页一次 IN 聚合;两类导出补「关联手机号」列并保留历史表头反解兼容
- 脱敏:关联审计走独立动作/资源只写脱敏手机号;访问日志手机号类字段脱敏
- 同步主 Spec openspec/specs/phone-asset-association 并归档 AUG26-009,补齐 requirement-evidence 与入口矩阵,context-health 通过
2026-09-15 11:54:56 +08:00

26 lines
6.8 KiB
Markdown
Raw Blame History

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.
## 1. 关联事实与 H5 建联
- [x] 1.1 新增成对迁移 `migrations/000223_*`(编号按实施时目录最大编号复核,当前最大为 `000222`)、模型与常量:关联表含 `asset_type``asset_id``phone``status`、建立时间、建立来源(固定 `h5_sms_verification`)与失效信息;配有效关系部分唯一索引 `(phone, asset_type, asset_id)`、按 `phone` 计数索引、按 `(asset_type, asset_id)` 集合查询索引;`down` 带有效性守卫,不回填历史。
- [x] 1.2 新增关联 store 的四个方法:`ExistsValid`(登录判定)、`CountValidByPhone`(十项上限)、`ListValidByAssets`(列表/导出一次批量聚合)、`CreateIfAbsent`(幂等建联)。
- [x] 1.3 改造 `issueLoginToken` 为三支判定:无主号 → `true`;有主号但未与当前访问资产存在有效关系 → `true`;已关联 → `false`;全局开关关闭 → 恒 `false` 且不查询、不创建、不删除关系。关联查询使用 JWT 的 `asset_type/asset_id`,不使用 `phone` claim。保持登录响应形状不变。
- [x] 1.4 扩展 `BindPhone`:已有主号且提交号码等于主号、验证码有效时幂等建联且不改账号手机号;号码不等于主号仍拒绝;无当前访问资产身份时只完成账号手机号绑定;建联前在事务内锁定手机号行计数,达十项返回上限文案且不写关联。
- [x] 1.5 改造 `ChangePhone`:事务内先算「新号现有有效关系数 + 旧号待迁移数」,超十项整次失败;通过时把旧号全部有效关系原子迁移至新号;与「新号已存在的同资产有效关系」冲突时整次失败回滚;不写遗留列 `tb_personal_customer.phone`;审计只写脱敏手机号。加锁顺序统一为按手机号行 `id ASC`
## 2. 读侧与后台解除
- [x] 2.1 资产列表与详情补关联手机号投影:按当页资产集合一次 `IN` 批量查询后装配,禁止逐资产查询;卡与设备两条 Query 路径都要覆盖。
- [x] 2.2 IoT 卡与设备两个导出场景补「关联手机号」列:设备导出新列并入尾部并让 `deviceExportTailHeaderCount` 递增,`buildDeviceExportRow` 同步;`cardGroupCountFromHeaders` 保留旧表头反解兼容分支,保证历史任务可用 `ResolvedHeaders` 重导出。
- [x] 2.3 实现单项解绑 `DELETE /phone-asset-associations/:id`路径主键即指定一条关系必须二次确认并填写原因1500 字符);锁关系后复核资产数据范围,标记失效并逐条审计(脱敏)。
- [x] 2.4 实现勾选批量解绑 `POST /phone-asset-associations/batch-unbind`:资产集合去重、二次确认、原因必填;每项资产独立解除全部有效关系,返回成功数、失败数与逐项结果;部分成功不回滚成功项。
- [x] 2.5 实现 CSV 解绑导入场景,按 B1B16 全清单(不含 B17B1 任务类型常量B2 队列常量、`QueueForTaskType` 分支与队列权重B3 新任务表成对迁移(含 `down` 守卫B4 任务模型(含逐行结果明细 jsonbB5 任务 store`UpdateStatus`/`UpdateProgress`/`UpdateResult`B6 `internal/bootstrap` 各装配文件注入B7 worker 处理器逐行独立事务、BOM 去除、UTF-8 校验失败按 GBK 回退、固定表头列序、行号自数据首行起计、任务级失败不产生行明细、不设行数硬上限B8 `pkg/queue/handler.go` 处理器注册B9 `cmd/worker/main.go` 启动补偿B10 `internal/infrastructure/releasegate/checker.go:243` 未完成异步任务表清单追加新表B11 应用 service建任务、入队失败必落库B12 Handler 与 DTO入口限超级管理员与平台用户B13 路由注册B14 占位装配B15 上传用途常量、存储映射、用途枚举与上传接口文档表四处同步B16 审计动作码与资源注册。列:资产标识(必填,复用既有资产标识解析)+ 备注(可选),解绑原因由任务级必填字段与二次确认提供;**任务明细持久化解绑当时的完整手机号快照**B13、B14 与 2.6 合并执行)。
- [x] 2.6 注册本 Change 全部新增接口的路由(沿用超管/平台路由组级 gate 先例)、`cmd/api/docs.go``cmd/gendocs/main.go` 占位装配及 OpenAPI 文档ENG-ROUTE-001并补充三态统一失败文案常量供新用例使用既有内联字面量按 As-Is 保留。
## 3. 验证与交付
- [x] 3.1 按 ENG-TEST-001 在维护者指定测试面验证正向行为:开关开启首次访问未关联资产返回 `need_bind_phone=true` 且完成验证后建立关系;已关联资产不再要求验证;开关关闭后登录不要求验证且不新建、不删除关系;第 11 项资产验证被拒绝且原十项不变;重复验证同一资产不产生第二条关系;换绑超限整次失败且新旧关系均不变;换绑迁移与新号既有同资产关系冲突时整次回滚。
- [x] 3.2 验证反向断言:换货完成后关联记录数不变且新资产不继承旧资产关联;换货新资产首次登录返回 `need_bind_phone=true`;资产导入后关联记录数不变;后台资产编辑后关联记录数不变。
- 说明:判定为完成(维护者裁定)。证据:全仓 `tb_phone_asset_association` 写入点仅本 Change 的 5 处H5 建联、换绑迁移、后台单项解除、后台批量解除、CSV 导入解除),`exchange` / `customer_binding` / 资产导入 / 后台资产编辑模块对本表零引用且零改动;等价谓词「有主号但未与当前访问资产存在有效关系 → `need_bind_phone=true`」已实测。完整换货 / 资产导入端到端(需共享队列与对象存储)未执行,作为残留范围记录。
- [x] 3.3 验证读侧与脱敏:资产列表按页一次聚合(以查询次数为准,禁止 N+1卡与设备两类导出均含关联手机号列且历史任务表头仍可反解列组批量任务结果在关系失效后仍返回完整手机号快照审计、日志与错误中只出现脱敏手机号越权、资产不存在、已无有效关系三态返回同一文案。
- [x] 3.4 验证权限与批量语义:代理、企业、个人客户访问后台解绑入口返回 403数据范围外资产不可见也不可解除单项解绑未指定关系被拒绝缺二次确认或原因被拒绝批量与导入按资产解除全部有效关系逐资产独立结果失败行保留原状且不影响其他行无行数硬上限。
- [x] 3.5 验证迁移与交付命令:隔离库 `up/down/up`(有数据时 `down` 被守卫拒绝);`gofmt -w <changed-go-files>``go build ./cmd/api ./cmd/worker``go run cmd/gendocs/main.go``openspec validate add-phone-asset-associations --strict``openspec doctor --json`;自动化测试按项目决策为 N/A。fixture 只增删本 Change 自己的记录,禁止重置整库。