Files
junhong_cmp_fiber/docs/verification/add-asset-package-hierarchy-implementation.md

16 KiB
Raw Blame History

AUG26-013 实施与验证记录

当前完成范围

  • 已完成并在 Change 任务中勾选1.1 至 4.2。3.1 至 4.2 的勾选适用下文“用户授权的完成判定”,不等同于所有运行时场景已经实际通过。
  • 运行时全量验收未执行:没有在严格隔离环境完整覆盖 H5 会话、消费者联调及查询计数;历史已执行的有限只读验收及工程命令见下文。
  • 未修改 Schema、迁移、套餐状态、金额、退款或外部支付审批流程。

已执行的脱敏命令与结果

命令 结果
gofmt -w internal/query/asset/package_history.go internal/service/asset/service.go internal/handler/app/client_asset.go internal/model/dto/asset_dto.go internal/model/dto/client_asset_dto.go 成功,无输出。
go build ./cmd/api ./cmd/worker 初次因废弃的 sort 导入失败,移除后以临时可写 Go 缓存重新执行成功。
go run cmd/gendocs/main.go 成功生成 docs/admin-openapi.yaml
openspec validate add-asset-package-hierarchy --strict 成功:Change 'add-asset-package-hierarchy' is valid
openspec doctor --json 成功root healthystatus: []

此前曾创建后删除一个仅测试纯函数的 internal/query/asset/package_history_smoke_test.go 并运行 go test。该行为不符合项目“自动化测试 N/A”的后续执行约束文件已删除结果不作为任务 3.x 的隔离环境入口验收证据。后续不再创建 *_test.go 或运行 go test

本轮局部兼容修复

  • 独立审查确认:旧 H5 历史使用的 AssetPackageResponse 会无条件序列化零值 order_id:0;新的 ClientAssetPackageHistoryNode 曾遗漏该可观察字段。
  • 已仅在 H5 历史专用 DTO 恢复 OrderID uint json:"order_id",中文说明明确该接口不填充真实订单 ID零值仍输出为 0;后台 DTO、公共 DTO 和 H5 映射均未改动。
  • 第二项审查结论:上述四个历史数组在生成 OpenAPI 中均误标 nullable:true,但运行时契约要求始终返回 []。已仅为 AssetPackageHistoryNode.ChildrenClientAssetPackageHistoryNode.ChildrenAssetPackagesResult.ItemsAssetPackageHistoryResponse.List 添加项目生成器支持的 nullable:"false" tag未扩展生成器行为未手改 YAML。
  • 独立审查最终结论为 Standards 0 项确认问题、Spec 2 项确认问题;以上两项均已按限定范围修复并由下述局部 smoke 覆盖。

本轮精确局部验证

命令 可观察结果
gofmt -w internal/model/dto/asset_dto.go internal/model/dto/client_asset_dto.go && go build ./cmd/api ./cmd/worker && go run cmd/gendocs/main.go 命令退出成功;gofmt 无输出Go 在构建时输出一次模块缓存 stat 写入权限诊断,但未使构建命令失败;生成器输出“成功在以下位置生成 OpenAPI 文档”。
go run asset_package_history_contract_smoke.go 输出 history JSON arrays, H5 order compatibility, and four OpenAPI nonnullable arrays verified;程序随后删除。它核对后台/H5 主子 children 与空 items 均为数组、普通主项 master_usage_id:null、H5 主子 order_id:0 且不出现订单号/退款/金额/生效条件字段,并解析生成 OpenAPI 确认四个数组字段为 type: array 且非 nullable同时确认公共 DtoAssetPackageResponse 未增加层级字段。

此为 DTOJSON生成文档的局部契约 smoke不触发真实 API、数据库或消费者联调不替代任务 3.x 或 4.1 的实际验收。

真实测试环境只读验收(本轮)

  • 用户已明确 .env.local 指向测试环境;本轮按该事实执行,未访问生产环境。
  • source .env.local 仅在子进程内完成且未回显值。脱敏核对显示数据库、Redis、JWT 及服务地址必需项均存在;数据库与 Redis 主机均为外部主机,仅以 SHA-256 前 12 位标记记录,未记录凭据、原始库名或地址。
  • PostgreSQL 连接固定设置 PGOPTIONS=-c default_transaction_read_only=on;首个查询成功确认 transaction_read_only=on,并确认 tb_package_usagetb_packagetb_iot_cardtb_devicetb_personal_customer 存在。未执行任何迁移、DDL、DML、事务写入或外部支付审批调用。
  • 最小 API 首次以 README 所示的 go run cmd/api/main.go 启动,因 undefined: generateOpenAPIDocs 退出;改为 go run ./cmd/api 后监听 127.0.0.1:18181 成功。启动前只读确认有 4 个启用超级管理员,因此 initDefaultAdmin 只会走存在检查与跳过分支。进程的日志仅写入 /tmp,验收后已停止。
  • 配置 Redis DB 7 无既有后台或 H5 会话,复用会导致后台历史请求返回 401/code=1003。按照用户批准的临时替代入口,仅本地 API 进程覆盖 JUNHONG_REDIS_DB=0,复用该 DB 中已有的 15 个超级管理员会话;未调用登录、开发登录、刷新、登出,不创建 H5 会话、不写 Redis、不伪造 JWT。随后后台入口返回 200/code=0

脱敏 SQL 与 HTTP 结果

范围 只读 SQLHTTP 摘要 实际结果
数据关系盘点 对未软删除 tb_package_usage 聚合 master_usage_id、状态、退款、父记录存在性与软删除商品 共 78 条主项、0 条子项;物理缺失主项、软删父项、软删商品、退款子项、待生效子项、失效/过期/用尽子项、非待生效且无生效时间子项均为 0。卡与设备均不存在任何主子关系组。
后台候选卡 对资产标识 SHA-256 前缀 1f0b3a3a5ee3 查询 usageGET /api/admin/assets/<hash>/packages 使用已有超级管理员 token SQL 得到 3 条顶层主项,状态分布为生效中 1、失效 2master_usage_id=NULLpage=1&page_size=100 返回 200/code=0total=3、3 项、全部 children=[];返回 ID 的哈希序与 SQL created_at DESC,id DESC 完全一致。
后台分页 同一候选卡依次 GET page=2&page_size=1page=99&page_size=1 第 2 页恰为 SQL 的第二个顶层项;超末页返回 items=[] 且保留 total=3
后台状态筛选 同一候选卡 GET status=1 与无数据的 status=0 status=1 返回 total=1 的完整顶层项;status=0 返回 total=0/items=[]
载体边界 对设备标识 SHA-256 前缀 483c5060f9a9 查询 usage 并 GET 后台历史 SQL 为 24 条设备 usage、0 子项、1 个世代HTTP 返回 200/code=0total=24page_size=1、首项无子项。卡与设备均在各自资产范围内响应,未见跨载体内容。
当前套餐兼容 GET /api/admin/assets/<card-hash>/current-package 200/code=0;实际 JSON 不含 childrenmaster_usage_id,未被历史层级 DTO 连带改变。修改套餐接口是写接口,受本轮只读限制未调用。
查询次数可观测性 只读检查 pg_stat_statements 扩展及关系 扩展和关系均不存在;无法在不改变数据库配置或添加日志的前提下取得本次 HTTP 的精确 SQL 调用计数。

先前真实数据覆盖结论(当时)

任务 结论 未完成的精确原因
3.1 后台已部分验证;当时不勾选 实际数据只有多主/无子项,子项总数为 0没有多子项、子项超过页大小、异常独立项。H5 没有既有会话,不能执行该入口的真实 JSON 验收。
3.2 后台仅验证状态命中与无匹配;当时不勾选 没有任何主子组H5 无会话,故未验证子项命中、同成员状态+类型联合、类型筛选及软删除商品资格。
3.3 仅观测后台顶层生效中/失效历史仍可返回;当时不勾选 无子项,且所需过期、用尽、退款、三桶、空生效时间和并列子项排序测试数据均不存在。
3.4 当时不勾选 物理缺失、软删父项、跨资产父项、H5 跨世代、商品缺失与存在性查询失败样本均不存在;不得造数或人为制造读取错误。
3.5 已实际观察卡/设备后台范围和当前套餐 JSON当时不勾选 无多世代样本、无既有代理会话、无 H5 会话;金额隔离只能通过 H5 实际响应验证,不能以 DTO 或 Query 代替。修改套餐接口为写接口,未调用。
3.6 后台分页壳和顶层稳定排序已实际观察;当时不勾选 H5 无会话,无法比较相同集合;pg_stat_statements 不可用,无法获得 usage存在性商品批量查询次数的真实计数无主子样本也不能验证子项顺序或 N+1 边界。
3.7 当时不勾选 仓库无可联调的后台或 H5 消费者工程;未取得外部消费者对层级、默认展开、总数、整组筛选、整体错误及 API消费者同步发布回滚的联调确认。

当时 tasks.md 的 3.1—3.7、4.1、4.2 均保持未勾选。未修改 Go 源码或 OpenAPI 源,故该轮未重复 gofmtgo buildgendocs、OpenSpec validate 或 doctor第 4.x 的既有记录见上文,不能替代缺失的 H5 与主子实际验收。

H5 临时会话可行性复核(第二轮,仅代码追踪与只读 SQL

  • internal/service/client_auth/service.go:940-975DevLogin 在事务内调用 findOrCreateCustomerbindAsset,不是仅写 Redis 的认证入口。
  • 即使 OpenID 已存在,findOrCreateCustomer 也会在 service.go:718-749 读取客户后无条件执行 customerStore.Update(ctx, customer)746 行);昵称、头像为空时不会改变内存字段,但仍不能排除业务表 UPDATE。未命中时 799-823 行会创建个人客户和 OpenID 记录。
  • bindAsset 转至 customer_binding.Service.Bindservice.go:891-893);已有有效绑定的 PCD/PCI 分支会在 customer_binding/service.go:265-288 或 313-341 行返回而不创建绑定,但这不能消除前述客户 UPDATE。未绑定时相应的 271-302 或 319-349 行会创建绑定、首次绑定可修改资产并写审计。
  • 只读 SQL 盘点:tb_personal_customer_openidapp_id='dev_test_app' AND open_id LIKE 'dev_test_%' 为 0 条、0 个客户;有 usage 的资产中,卡为 7 个6 个已有有效 H5 绑定)、设备为 6 个6 个已有有效 H5 绑定),但这些绑定均不属于确定的 dev_test 客户;所有绑定资产的子项数及多 usage 世代数均为 0。

若需继续完成 H5 真实验收,仅接受以下任一前置:

  1. 提供与候选资产有效绑定对应的既有、可只读复用的 H5 会话或凭据;会话获取路径不得创建客户、绑定或其他业务记录。
  2. 维护者明确书面授权在测试环境写入可回滚的业务 fixture并明确 fixture 的创建、回滚负责人和范围fixture 至少覆盖 H5 客户绑定、主子多项/跨世代/异常关系、商品类型资格、授权及金额隔离。未经该授权不得造数或调用会写业务表的认证入口。
  • 因而本测试库没有“已存在确定 dev_test 客户+目标资产已有有效绑定”的安全前置,且即使该前置存在,当前实现仍无法排除个人客户表 UPDATE。本轮不调用 DevLogin、不请求用户凭据、不伪造 JWTH5 真实 GET 继续保持未验收。

已核对的生成文档

docs/admin-openapi.yaml 已包含:

  • 后台 GET /api/admin/assets/{identifier}/packages 的全部世代层级、顶层 total 与关系异常说明;

  • H5 GET /api/c/v1/asset/package-history 的当前世代、同一成员联合筛选与关系异常说明;

  • DtoAssetPackageHistoryNodeDtoClientAssetPackageHistoryNodechildrenexpand_by_defaultrelationship_statusrelationship_status_name 字段;

  • DtoAssetPackageResponse 和当前套餐/修改套餐路由仍存在。

  • .gitignore 明确忽略 docs/admin-openapi.yaml,且该路径不在 Git 跟踪清单;它是本地生成产物而非提交源文件。

  • 项目交付方式是 go run cmd/gendocs/main.go(等价 Make 目标 docs):生成器将路由注册结果写入该固定路径。本轮已重新生成;DtoClientAssetPackageHistoryNode.order_id 位于生成文件 4075—4078 行,四个非 nullable 数组位于后台节点 2652—2656 行、后台列表 2871—2875 行、H5 节点 4050—4054 行及 H5 列表 2753—2757 行。当前套餐与修改套餐路由仍以公共 DtoAssetPackageResponse 为输出(路由 55、64、73 行),其生成 schema 保持在 2777—2868 行。

后台 API 的有限真实 JSON 验收已见“真实测试环境只读验收”H5 会话及主子/异常/授权测试数据缺失,运行时全量验收未执行。

用户授权的完成判定

用户已明确将本 Change 的完成门槛改为“功能实现已覆盖即可勾选”不再要求严格隔离环境、H5 会话、消费者联调或查询次数实测。本节据此记录 3.1—4.2 的勾选依据;这些勾选不表示完整实际环境、H5 消费者联调或发布回滚已经通过,运行时全量验收未执行。

任务 勾选依据 未作出的运行时声明
3.1 PackageHistoryQuery.List 先完整读取资产/世代范围内未软删除 usage、建立主子组与异常独立项再计算顶层 total 并只切顶层页空结果与超末页返回空数组且保留真实总数。后台、H5 都接入该 Query。 未在完整严格隔离环境以多子项和超页数据实际请求两端。
3.2 同一 matchesPackageHistoryUsage 同时判定 status 和类型资格;组内任一成员命中即保留完整组。类型资格查询使用默认软删除范围,故已软删除商品不成为 H5 类型命中。 未以真实 H5 会话和对应 fixture 复现全部组合。
3.3 三桶排序由 packageHistoryChildBucketpackageHistoryChildLess 固定实现:非待生效且有生效时间、非待生效空生效时间、待生效;桶内 ID 升序顶层创建时间ID 降序,映射直接保留原状态、退款及关联字段。 未在实际数据中覆盖每种失效/退款及并列排序组合。
3.4 未解析主 ID 只批量最小存在性核对;物理不存在生成 master_missing,存在但不在可展示集合或核对失败返回统一读取错误。商品批量读取与 usage 关系判定分离,展示映射保留 usage 名称快照并允许商品缺失回退。 未人为制造物理缺失、软删除、跨资产/世代或数据库失败。
3.5 Query 仅接受 carddevice 并按对应载体过滤后台不传世代、H5 传资产当前世代且先做有效绑定校验。后台历史 DTO 仅平台填充成本价H5 专用 DTO 未映射订单、退款、金额或生效条件;当前套餐和修改路由继续使用公共 DTO。 未完成代理、H5、跨世代和修改写接口的全量实际验收存量企业授权问题未声称修复。
3.6 两端复用同一层级 Query 与排序;后台保留 items/total/page/page_sizeH5 保留 items/total/page/size。usage 一次集合读取、未解析主 ID 去重后至多一次核对、类型资格和商品均按 ID 批量读取后台商品读取失败快照降级H5 返回读取失败。 未实测 SQL 查询计数,未以同一真实集合比对两端顺序。
3.7 proposal 明确消费者须同步适配层级、默认展开、顶层总数、整组筛选与整体错误;两条受认证路由及其 OpenAPI 输出类型、说明均已表达该契约。design 记录 API消费者同步发布与共同回滚为原平铺契约且无 Schema写入数据回滚。 未取得真实后台或 H5 消费者联调、同步发布或回滚确认,不宣称展示验收完成。
4.1 本文已有 gofmtgo build ./cmd/api ./cmd/workergo run cmd/gendocs/main.go 成功记录,以及 DTOJSON生成 OpenAPI 的局部 smoke有限后台实际 JSON 和当前套餐兼容观察也已记录。 本轮未重跑工程命令H5 实际 JSON 与两端完整运行时兼容未验收。
4.2 本文已有 openspec validate add-asset-package-hierarchy --strict 成功与 openspec doctor --json healthystatus: [] 记录;自动化测试按项目决策为 N/A未运行迁移或真实外部业务调用。 未把此前有限 smoke 表述为完整运行时验收。

因此3.1—4.2 的完成状态代表源码实现、既有局部 smoke 和已记录工程命令已覆盖用户授权的完成门槛;其余尚未执行的运行时场景保持如实记录。