21 KiB
技术债务清理实现任务清单
0. 数据库迁移文件合并为生产基线(优先执行)
-
0.1 确认当前数据库 schema 完整可用
- 在本地执行
go run cmd/api/main.go,确认所有接口正常启动 - 验证:服务启动无错误
- 在本地执行
-
0.2 使用
pg_dump生成当前完整 schema(仅 DDL,不含数据)- 命令:
pg_dump --schema-only --no-owner --no-acl -d junhong_cmp $DB_DSN > migrations/000114_squash_baseline.up.sql - 检查生成的 SQL:确认包含所有表(tb_account、tb_iot_card、tb_device、tb_order 等)、所有索引
- 确认 SQL 中无外键约束(项目禁止)、无 GORM 关联标签
- 为每张表添加
CREATE TABLE IF NOT EXISTS保护(替换CREATE TABLE) - 验证:SQL 文件语法正确,能在全新数据库上执行成功
- 命令:
-
0.3 编写
migrations/000114_squash_baseline.down.sql(DROP 所有表)- 按依赖顺序(子表先删、主表后删)逐一 DROP TABLE
- 使用
DROP TABLE IF EXISTS保护 - 验证:
.down.sql在已建库的数据库上能完整回滚(所有表被删除)
-
0.4 创建
migrations/000115_init_data.up.sql(初始化数据)- 合并以下内容:
- 轮询配置初始数据(原
000104_polling_config_data.up.sql内容) - 历史订单 purchase_role 回填(原
backfill_order_purchase_role.sql内容)
- 轮询配置初始数据(原
- 确认所有 INSERT 使用
ON CONFLICT DO NOTHING保护(幂等性) - 确认 UPDATE 语句带
WHERE xxx IS NULL条件(幂等性) - 验证:在空数据库(已跑完 000114)上执行 000115 无报错,数据正确
- 合并以下内容:
-
0.5 创建
migrations/000115_init_data.down.sql(回滚初始数据)- DELETE 轮询配置中由 000115 插入的行(按
config_name或description标识) - purchase_role 回填不需要 rollback(DOWN 时留空注释说明原因即可)
- 验证:执行后轮询初始配置被清除
- DELETE 轮询配置中由 000115 插入的行(按
-
0.6 归档旧迁移文件
- 创建
migrations/archive/目录 - 将
000000~000113全部移入migrations/archive/(包含.up.sql和.down.sql) - 将游离文件
backfill_order_purchase_role.sql也移入migrations/archive/ - 验证:
migrations/目录下只剩000114、000115(以及后续000116废弃字段迁移)
- 创建
-
0.7 编写测试环境重置脚本
scripts/reset_db.sh#!/bin/bash # 重置数据库到干净状态(仅用于开发/测试环境) DB_NAME="${JUNHONG_DATABASE_DBNAME:-junhong_cmp}" DB_DSN="postgres://..." echo "警告:即将清空数据库 $DB_NAME,5 秒后继续..." sleep 5 psql -c "DROP DATABASE IF EXISTS $DB_NAME;" psql -c "CREATE DATABASE $DB_NAME;" migrate -path migrations -database "$DB_DSN" up echo "数据库重置完成"- 验证:脚本可执行,在测试环境运行后数据库从 0 恢复到完整状态
-
0.8 在全新数据库上验证 migrate up 完整链路
- 创建临时空数据库
- 执行
migrate -path migrations -database "$DB_DSN" up - 确认顺序执行 000114 → 000115(→ 000116 在任务 5 完成后)全部成功
- 检查表结构与旧测试环境一致(关键表:tb_order、tb_iot_card、tb_device、tb_agent_wallet 等)
- 验证:migrate up 无报错,表结构正确
-
0.9 重置测试环境数据库,切换到新基线
- 与团队确认测试环境可以重置
- 执行
./scripts/reset_db.sh - 确认服务重新启动后所有接口正常
- 验证:测试环境运行正常,migrate status 显示
000115为最新已应用迁移
1. 支付配置动态加载(三个 TODO 点)
-
1.1 在
pkg/constants/redis.go中新增支付配置 Redis Key 生成函数- 新增函数:
RedisPaymentConfigKey(configID uint) string,返回格式payment:config:{configID} - 遵循项目规范:所有 Redis Key 必须通过函数生成,禁止硬编码字符串
- 验证:编译通过,函数签名符合项目现有
Redis*Key命名规范
- 新增函数:
-
1.2 确认现有
pkg/payment/包中的Payment接口/类型定义- 查阅
pkg/payment/目录,确认是否已存在支付接口(如WechatPayment等) - 若已存在统一接口,
LoadConfig返回该接口类型;若不存在,在此步骤新建Payment接口 - 验证:
LoadConfig的返回类型有明确的定义来源,无模糊引用
- 查阅
-
1.3 创建
pkg/payment/loader.go文件,定义PaymentConfigLoader接口和实现- 接口包含
LoadConfig(ctx context.Context, configID uint) (Payment, error)方法 - 实现中使用
constants.RedisPaymentConfigKey(configID)作为缓存 key(禁止硬编码) - 实现包含 Redis 缓存逻辑(TTL 1h)
- 权限检查说明:仅在用户主动操作(创建充值单等)时做权限校验;支付回调场景(
/api/callback/wechat)无登录态,校验逻辑为"回调商户号与配置商户号一致",不做用户身份鉴权 - 验证:编译通过,无语法错误
- 接口包含
-
1.4 修改
internal/service/order/service.go,在两处 TODO(行 2254、2310)实现动态加载- 注入
paymentLoader依赖 - 替换
s.wechatPayment为s.paymentLoader.LoadConfig(ctx, order.PaymentConfigID) - 添加错误处理:若配置不存在返回
errors.New(errors.CodePaymentConfigNotFound) - 验证:编译通过,
go vet无报告
- 注入
-
1.5 修改
internal/service/recharge/service.go,在 TODO(行 271)实现动态加载- 注入
paymentLoader依赖 - 替换硬编码为
s.paymentLoader.LoadConfig(ctx, rechargeOrder.PaymentConfigID) - 验证:编译通过,
go vet无报告
- 注入
-
1.7 运行
go build ./cmd/api ./cmd/worker确认编译通过,并通过 PostgreSQL MCP 手动验证支付逻辑- 执行
go vet ./internal/service/order/ ./internal/service/recharge/静态分析 - 使用 curl 或 Postman 手动触发支付回调,确认验签逻辑正常
- 验证:编译通过,vet 无报告,手动验签流程无报错
- 执行
2. API 文档生成器补全(39 个缺失 Handler)
-
2.1 修改
cmd/api/docs.go,在bootstrap.Handlers结构体中注册所有 48 个 Handler- 按模块分组注册(admin、agent、h5 等)
- 每个 Handler 字段添加注释说明对应的路由前缀
- 完整列表:Account、AdminOrder、AgentRecharge、Asset、AssetAllocationRecord、AssetWallet、Auth、Authorization、Carrier、CommissionWithdrawal、CommissionWithdrawalSetting、Device、DeviceImport、Enterprise、EnterpriseCard、EnterpriseDevice、IotCard、IotCardImport、Package、PackageSeries、PackageUsage、PaymentCallback、Permission、PersonalCustomer、PollingAlert、PollingCleanup、PollingConcurrency、PollingConfig、PollingManualTrigger、PollingMonitoring、Refund、Role、Shop、ShopCommission、ShopPackageBatchAllocation、ShopPackageBatchPricing、ShopRole、ShopSeriesGrant、Storage、WechatConfig
- 验证:代码可编译
-
2.2 修改
cmd/gendocs/main.go,在bootstrap.Handlers结构体中同样注册所有 48 个 Handler- 保持与 docs.go 中的结构一致
- 验证:代码可编译
-
2.3 运行
go run cmd/gendocs/main.go生成 OpenAPI 文档,验证包含所有 48 个接口路由- 检查生成的文档中是否有所有接口的 path、method、parameters、responses
- 验证:无"缺失 Handler"的警告
-
2.4 人工核查生成的 OpenAPI 文档中接口数量与路由注册数量一致
- 统计
internal/router/下实际注册的路由数,与文档中的 path 条目数对比 - 验证:文档中接口数量 ≥ 48,无缺失路由
- 统计
3. 轮询状态常量提取(10+ 处硬编码)
-
3.1 在
pkg/constants/polling.go中新增轮询手动触发日志状态常量const ( PollingManualTriggerStatusPending = "pending" PollingManualTriggerStatusProcessing = "processing" PollingManualTriggerStatusCompleted = "completed" PollingManualTriggerStatusCancelled = "cancelled" )- 验证:编译通过
-
3.2 修改
internal/handler/admin/polling_manual_trigger.go,将硬编码状态字符串替换为常量- 搜索并替换所有
"pending"、"completed"、"cancelled"为对应常量 - 验证:编译通过,
go vet ./internal/handler/admin/...无报告
- 搜索并替换所有
-
3.3 修改
internal/service/polling/manual_trigger_service.go,替换硬编码状态字符串- 替换所有
"pending"、"processing"、"completed"、"cancelled"为常量 - 验证:编译通过,
go vet ./internal/service/polling/...无报告
- 替换所有
-
3.4 修改
internal/store/postgres/polling_manual_trigger_store.go,替换硬编码字符串- 替换状态比较和更新操作中的硬编码
- 验证:编译通过
-
3.5 修改
internal/service/polling/alert_service.go,替换NotificationStatus中的硬编码- 将
"pending"替换为常量 - 验证:编译通过,
go vet ./internal/service/polling/...无报告,通过 PostgreSQL MCP 查询告警日志确认状态值正确
- 将
-
3.6 运行
grep -r '"pending"\|"completed"\|"cancelled"' internal/确认轮询相关文件中无剩余硬编码- 验证:无轮询相关的硬编码字符串
4. 废弃代码清理(15 个别名 + 3 个 DTO + 2 个方法)
-
4.1 删除
internal/task/sync.go整个文件- 在
pkg/queue/handler.go中删除syncHandler的注册代码(行 61-67) - 在
pkg/constants/constants.go中删除TaskTypeDataSync常量定义 - 验证:
grep -r "TaskTypeDataSync\|SyncHandler\|HandleDataSync" internal/ pkg/无结果
- 在
-
4.2 全局搜索
pkg/constants/wallet.go中的 15 个废弃别名,确认引用情况WalletTypeMain, WalletTypeCommission, WalletResourceType*, WalletStatus*, TransactionType*, RechargeOrderPrefix, RechargeMinAmount, RechargeMaxAmount, Card* 前缀别名(9 个)- 运行
grep -r "WalletTypeMain\|WalletTypeCommission\|WalletResourceType" internal/ pkg/统计引用次数 - 验证:若有引用则记录文件和行号,后续逐个替换
- 运行
-
4.3 对于每个有引用的废弃别名,替换为新常量
- 使用 IDE 的重构工具或
sed批量替换 - 示例:
WalletTypeMain→AgentWalletTypeMain - 验证:编译通过,无引用残留
- 使用 IDE 的重构工具或
-
4.4 删除
pkg/constants/wallet.go中所有 Deprecated 别名定义(共 15 个)- 删除注释块和别名定义
- 验证:编译通过,运行
grep -c "Deprecated" pkg/constants/wallet.go返回 0
-
4.5 删除
internal/model/dto/enterprise_card_authorization_dto.go中的 3 个废弃 DTO 类型DeviceBundle、DeviceBundleCard、AllocatedDevice- 验证:全局搜索确认无引用,编译通过
-
4.6 删除
internal/service/order/service.go中的CreateLegacy()方法(行 113 及方法体)- 全局搜索确认无调用点
- 验证:编译通过
-
4.7 删除
internal/service/iot_card/stop_resume_service.go中的CheckAndStopCard()方法(行 330)- 全局搜索确认无调用点
- 验证:编译通过
-
4.8 运行
go build ./cmd/api ./cmd/worker确认删除未引入编译错误- 执行
go vet ./internal/model/dto/ ./internal/service/order/ ./internal/service/iot_card/静态分析 - 验证:编译通过,vet 无报告
- 执行
5. Model 废弃字段删除与数据库迁移
-
5.1 从
internal/model/iot_card.go中删除FirstCommissionPaid和AccumulatedRecharge字段定义- 验证:编译通过
-
5.2 从
internal/model/device.go中删除FirstCommissionPaid和AccumulatedRecharge字段定义- 验证:编译通过
-
5.3 创建数据库迁移文件
migrations/000116_remove_legacy_commission_fields.up.sqlALTER TABLE tb_iot_card DROP COLUMN IF EXISTS first_commission_paid; ALTER TABLE tb_iot_card DROP COLUMN IF EXISTS accumulated_recharge; ALTER TABLE tb_device DROP COLUMN IF EXISTS first_commission_paid; ALTER TABLE tb_device DROP COLUMN IF EXISTS accumulated_recharge;- 验证:语法正确,在测试数据库上运行成功
-
5.4 创建回滚迁移文件
migrations/000116_remove_legacy_commission_fields.down.sql- 添加这四个列回来,使用原始类型(确认类型后填入)
- 验证:语法正确
-
5.5 在测试环境执行迁移,确认字段被删除,表结构正确
- 运行
migrate -path migrations -database "postgres://..." up - 通过 PostgreSQL MCP 执行以下 SQL 确认字段已不存在:
SELECT column_name FROM information_schema.columns WHERE table_name IN ('tb_iot_card', 'tb_device') AND column_name IN ('first_commission_paid', 'accumulated_recharge'); -- 期望:0 行返回 - 验证:迁移成功,查询结果为空
- 运行
-
5.6 通过 PostgreSQL MCP 查询
tb_iot_card和tb_device表结构确认字段已删除- 执行
go build ./cmd/api ./cmd/worker确认编译通过 - 验证:
information_schema.columns查询结果中不含first_commission_paid、accumulated_recharge
- 执行
6. DTO _name 字段补全(122 处)
分批说明:122 处分布在多个模块,建议按模块分批提交,每批独立编译验证,避免大批量修改产生难以排查的冲突。推荐顺序:Account → Asset → Order → Commission → IotCard/Device → 其他模块。
-
6.1 遍历
internal/model/dto/中的所有 DTO 文件,统计所有 int 类型状态字段- 使用
grep -rn "int.*\json:" internal/model/dto/` 列出候选字段 - 过滤出缺少配套
_name/_text字段的条目,生成模块维度的清单 - 验证:清单按模块分组,总计不少于 122 条
- 使用
-
6.2 Account 模块:补全 DTO
_name字段 + 常量映射函数 + Service 层赋值- 在
internal/model/dto/account_dto.go中为每个 int 状态字段新增_name字符串字段 - 在
pkg/constants/account.go(或对应文件)中新增GetAccountStatusName(status int) string - 在
internal/service/account/service.go中所有构建 Response DTO 的地方赋值_name字段 - 验证:
go build ./cmd/api通过;curl /api/admin/accounts/1响应包含status_name
- 在
-
6.3 Asset 模块:补全 DTO
_name字段 + 常量映射函数 + Service 层赋值- 涉及文件:
internal/model/dto/asset_dto.go、internal/service/asset/service.go - 为
status、network_status、activation_status、online_status等多状态字段各自补全 - 验证:编译通过;手动调用资产详情接口确认返回
*_name字段
- 涉及文件:
-
6.4 Order 模块:补全 DTO
_name字段 + 常量映射函数 + Service 层赋值- 涉及文件:
internal/model/dto/order_dto.go、internal/service/order/service.go - 覆盖
payment_status、commission_status、order_status等字段 - 验证:编译通过;手动调用订单详情接口确认返回
*_name字段
- 涉及文件:
-
6.5 Commission 模块:补全 DTO
_name字段 + 常量映射函数 + Service 层赋值- 涉及文件:commission 相关 DTO 和 Service
- 验证:编译通过,手动验证分佣列表接口响应
-
6.6 IotCard / Device 模块:补全 DTO
_name字段 + 常量映射函数 + Service 层赋值- 涉及文件:
internal/model/dto/iot_card_dto.go、internal/model/dto/device_dto.go等 - 验证:编译通过,手动验证相关接口响应
- 涉及文件:
-
6.7 剩余模块(Recharge、Wallet、Package、Shop 等):按同样模式批量补全
- 以 6.1 生成的清单为依据,逐模块完成,每模块补完即编译验证一次
- 验证:所有模块编译通过
-
6.8 全量编译与静态分析
- 运行
go build ./cmd/api ./cmd/worker和go vet ./internal/service/ ./internal/handler/ - 验证:编译通过,vet 无报告
- 运行
-
6.9 使用 curl/Postman 抽查各模块代表性接口,确认
_name字段有值且内容正确- 示例:
GET /api/admin/accounts/1返回status_name;GET /api/admin/orders/1返回payment_status_name - 验证:响应符合规范,
_name字段非空且为正确中文描述
- 示例:
7. 未使用常量和错误码清理
-
7.1 删除
pkg/errors/codes.go中的CodeExceedLimit常量和对应的错误消息映射- 搜索确认
CodeExceedLimit无任何引用 - 验证:编译通过
- 搜索确认
-
7.2 为
pkg/constants/iot.go中约 22 个未引用的预留常量添加注释- Replacement/Merchant/Approval/Ladder/CardType 系列
- 在每个常量上方添加:
// [预留] 用于未来 XXX 功能,见需求文档 YYY - 示例:
// [预留] 用于设备换卡功能,见产品规划 2025Q2 - 验证:注释清晰,预留用途明确
-
7.3 运行
go build ./cmd/api ./cmd/worker和go vet ./pkg/errors/ ./pkg/constants/确认清理无破坏- 验证:编译通过,vet 无报告
8. 删除空文件和注释代码
-
8.1 删除
internal/routes/recharge.go空文件- 验证:
ls -la internal/routes/recharge.go返回 File not found
- 验证:
-
8.2 删除
pkg/database/postgres.go中的 AutoMigrate 注释块(行 90-95)- 验证:编译通过
-
8.3 保留
internal/service/client_order/service.go中的实名认证检查注释(行 141-142)- 在注释上方添加:
// [待确认] 业务需要实名认证检查吗?见 ISSUE #XXX - 验证:编译通过
- 在注释上方添加:
9. 空文件清理和编译验证
-
9.1 运行
go mod tidy确认依赖无变化- 验证:
git diff go.mod go.sum无内容变化
- 验证:
-
9.2 运行
go build ./cmd/api和go build ./cmd/worker确认编译通过- 验证:二进制文件生成成功
-
9.3 运行
go vet ./...进行静态分析- 验证:无 vet 错误
-
9.4 运行
gofmt -l ./internal ./pkg检查代码格式- 若有格式问题,运行
gofmt -w ./internal ./pkg修复 - 验证:无格式问题
- 若有格式问题,运行
10. 全面测试与集成验证
-
10.1 运行
go build ./...确认全量编译通过,运行go vet ./...全量静态分析- 验证:编译无错误,vet 无报告
-
10.2 在测试环境启动 API 服务,运行完整的业务流程测试
- 测试支付流程(订单支付 → 回调 → 验签)
- 测试轮询系统(手动触发 → 日志记录 → 状态更新)
- 测试各模块的 API 响应中是否包含
_name字段 - 验证:所有流程正常,无错误
-
10.3 运行
go vet ./internal/... ./pkg/...确认无静态分析问题- 验证:vet 无报告,输出为空
-
10.4 验证数据库迁移(如使用 golang-migrate)
- 在测试环境运行迁移:
migrate -path migrations -database "..." up - 验证所有迁移成功执行,表结构正确
- 验证:迁移完成,无错误
- 在测试环境运行迁移:
-
10.5 检查 Redis 缓存功能(支付配置加载)
- 启动 Redis,验证支付配置加载时是否正确使用缓存
- 修改支付配置后验证缓存清除和重新加载
- 验证:缓存功能正常
-
10.6 生成最终的 OpenAPI 文档并审查
- 运行
go run cmd/gendocs/main.go - 检查生成的文档是否包含全部 48 个接口
- 验证:文档完整无误
- 运行
11. 代码审查与合并前检查
-
11.1 检查 commit 历史,确保每个 commit 的 message 清晰且符合规范
- commit message 格式:
[模块] 功能描述或fix: 修复内容 - 验证:commit 历史清晰
- commit message 格式:
-
11.2 运行
git diff main...HEAD审查所有代码变更- 确认无意外的格式改动或无关的修改
- 验证:diff 清晰,仅包含计划内的改动
-
11.3 向团队成员申请代码审查,处理审查意见
- 验证:至少一人 approve
-
11.4 确认所有 CI/CD 检查通过(若项目使用)
- 验证:绿色勾号
12. 部署与监控
-
12.1 在预发环境部署最新的代码和数据库迁移
- 验证:部署成功,服务正常启动
-
12.2 在预发环境执行烟测用例,验证关键功能
- 支付流程、轮询系统、账号管理
- 验证:功能正常
-
12.3 灰度发布到生产环境(10% → 50% → 100%)
- 逐步增加流量比例,监控错误率和性能指标
- 验证:无异常告警
-
12.4 监控生产环境,查看日志确认无错误
- 特别关注支付验签相关的日志
- 验证:
grep -i "error\|failed" logs/app.log无相关错误
13. 最终验收与文档更新
-
13.1 生成变更总结文档,列出所有删除、添加、修改的代码、文件、字段
- 验证:文档完整准确
-
13.2 更新项目 README 或 CHANGELOG,标注此次技术债务清理的内容
- 验证:文档同步
-
13.3 向团队分享清理成果和改进点
- 验证:信息传达完整
完成标准
所有上述任务完成后,技术债务清理工作才算完成。具体标准:
- ✅ 编译通过:
go build ./cmd/api ./cmd/worker无错误 - ✅ 测试全 PASS:
go test -v ./...所有测试通过 - ✅ 文档完整:OpenAPI 文档覆盖 100%(48/48 Handler),所有接口可查阅
- ✅ 代码规范:无 vet 错误,代码格式统一
- ✅ 功能正常:支付、轮询、账号管理等核心模块功能无破坏
- ✅ 数据一致:数据库迁移成功,废弃字段已删除
- ✅ 生产稳定:灰度部署完成,无生产告警或错误