diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 21f727f..5bc14a0 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -10,8 +10,8 @@ ### CRITICAL — P0 紧急 Bug 修复(方案 A) -- [ ] **CRITICAL-01**: 实名状态常量统一 — `parseRealnameStatus` 写入值 2 改为常量 1,Model 注释统一,全链路使用 `constants.RealNameStatusVerified` -- [ ] **CRITICAL-02**: C 端实名校验修复 — `client_order/service.go` 实名判断改用 `constants.RealNameStatusVerified`(依赖 CRITICAL-01) +- [x] **CRITICAL-01**: 实名状态常量统一 — `parseRealnameStatus` 写入值 2 改为常量 1,Model 注释统一,全链路使用 `constants.RealNameStatusVerified` +- [x] **CRITICAL-02**: C 端实名校验修复 — `client_order/service.go` 实名判断改用 `constants.RealNameStatusVerified`(依赖 CRITICAL-01) - [ ] **CRITICAL-03**: 实名激活任务断链修复 — `PollingHandler` 注入 `asynq.Client`,删除 RPush 降级方案,改用 `asynq.Client.EnqueueContext()` - [ ] **CRITICAL-04**: 充值回调后自动购包触发 — `recharge/service.go` 在 HandlePaymentCallback 成功后入队 `TaskTypeAutoPurchaseAfterRecharge`;注册 `AutoPurchaseHandler` - [ ] **CRITICAL-05**: 自动购包佣金链补全 — `AutoPurchaseHandler.ProcessTask()` 事务提交成功后入队 `TaskTypeCommission` @@ -120,8 +120,8 @@ | REQ-ID | Phase | Status | |--------|-------|--------| -| CRITICAL-01 | Phase 1 | Pending | -| CRITICAL-02 | Phase 1 | Pending | +| CRITICAL-01 | Phase 1 | Complete | +| CRITICAL-02 | Phase 1 | Complete | | CRITICAL-03 | Phase 1 | Pending | | CRITICAL-04 | Phase 1 | Pending | | CRITICAL-05 | Phase 1 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 18c4b88..1f5cbde 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -34,7 +34,7 @@ **Plans**: 5 plans Plans: -- [ ] 01-01-PLAN.md — CRITICAL-01/02:实名状态常量统一 + C 端实名校验修复(Wave 1) +- [x] 01-01-PLAN.md — CRITICAL-01/02:实名状态常量统一 + C 端实名校验修复(Wave 1) - [ ] 01-02-PLAN.md — CRITICAL-03:实名激活任务断链(PollingHandler 注入 asynqClient)(Wave 2) - [ ] 01-03-PLAN.md — CRITICAL-04/05:充值回调触发自动购包 + 佣金链补全(Wave 2,parallel) - [ ] 01-04-PLAN.md — CRITICAL-06:代购订单 sellerCostPrice 6 处语义审查修正(Wave 1,parallel) @@ -118,7 +118,7 @@ Plans: | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| -| 1. P0 紧急修复 | 1/5 | In Progress| | +| 1. P0 紧急修复 | 2/5 | In Progress| | | 2. 权限/财务/实名/轮询修复 | 0/1 | Not started | - | | 3. 设备体系完善 | 0/1 | Not started | - | | 4. 退款 + 支付 + 运营修复 | 0/1 | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 886fc4a..36cf296 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,12 +3,12 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: unknown -last_updated: "2026-03-27T14:51:42.219Z" +last_updated: "2026-03-27T14:56:27.264Z" progress: total_phases: 6 completed_phases: 0 total_plans: 5 - completed_plans: 1 + completed_plans: 2 --- # Project State — 君鸿卡管系统 @@ -22,7 +22,7 @@ progress: ## Current Position Phase: 01 (p0) — EXECUTING -Plan: 2 of 5 +Plan: 3 of 5 | Field | Value | |-------|-------| | **Current Phase** | 1 — P0 紧急修复 | @@ -72,6 +72,7 @@ Progress: [ 1 ]──[ 2 ]──[ 3 ]──[ 4 ]──[ 5 ]──[ 6 ] --- | Phase 01-p0 P05 | 8 | 2 tasks | 3 files | +| Phase 01-p0 P01 | 15 | 2 tasks | 7 files | ## Accumulated Context diff --git a/.planning/phases/01-p0/01-01-SUMMARY.md b/.planning/phases/01-p0/01-01-SUMMARY.md new file mode 100644 index 0000000..2a08512 --- /dev/null +++ b/.planning/phases/01-p0/01-01-SUMMARY.md @@ -0,0 +1,233 @@ +--- +phase: 01-p0 +plan: 01 +subsystem: realname-status +tags: [bug-fix, constants, critical, realname] +dependency_graph: + requires: [] + provides: [CRITICAL-01, CRITICAL-02] + affects: [polling_handler, client_order, scheduler, iot_card_service, asset_dto] +tech_stack: + added: [] + patterns: [constants-over-magic-numbers] +key_files: + created: [] + modified: + - internal/task/polling_handler.go + - internal/model/iot_card.go + - internal/model/dto/asset_dto.go + - internal/polling/scheduler.go + - internal/service/iot_card/service.go + - internal/service/client_order/service.go + - internal/handler/app/client_realname.go +decisions: + - 统一使用 constants.RealNameStatusVerified(=1) 替代所有硬编码 1、2 的实名状态判断 + - scheduler.go 中 0/1/2 三态判断简化为已实名/未实名两态(符合常量设计) +metrics: + duration_minutes: 15 + completed_date: "2026-03-27" + tasks_completed: 2 + files_modified: 7 +--- + +# Phase 01 Plan 01: 统一实名状态常量 Summary + +**一句话总结:** 将全链路 7 处硬编码实名状态值(包括错误的 `return 2`)统一改为 `constants.RealNameStatusVerified(=1)` / `constants.RealNameStatusNotVerified(=0)`,修复 CRITICAL-01 和 CRITICAL-02。 + +--- + +## Objective Achieved + +统一实名状态常量(CRITICAL-01),并修复 C 端实名校验(CRITICAL-02)。 + +实名链路三处不一致(轮询写入 2、常量定义 1、C 端校验 1)造成实名状态链路全面断裂,修复后全链路统一为 `0=未实名、1=已实名`。 + +--- + +## Tasks Completed + +| Task | Name | Commit | Files | +|------|------|--------|-------| +| 1 | 修复 polling_handler.go 实名状态写入值(CRITICAL-01) | `1fd0072` | polling_handler.go, iot_card.go, asset_dto.go, scheduler.go, iot_card/service.go | +| 2 | 修复 C 端实名校验(CRITICAL-02) | `da50a35` | client_order/service.go, client_realname.go | + +--- + +## Key Changes + +### Task 1 — CRITICAL-01 核心修复 + +**① `internal/task/polling_handler.go` — `parseRealnameStatus`** + +```go +// 修改前(错误:写入 2 到数据库) +func (h *PollingHandler) parseRealnameStatus(realStatus bool) int { + if realStatus { + return 2 // 已实名 + } + return 0 // 未实名 +} + +// 修改后(正确:写入常量值 1) +func (h *PollingHandler) parseRealnameStatus(realStatus bool) int { + if realStatus { + return constants.RealNameStatusVerified // = 1,已实名 + } + return constants.RealNameStatusNotVerified // = 0,未实名 +} +``` + +**② `internal/task/polling_handler.go` — `isFirstRealname`** + +```go +// 修改前(错误:硬编码 == 2 判断) +isFirstRealname := (card.RealNameStatus == 0 || card.RealNameStatus == 1) && newRealnameStatus == 2 + +// 修改后(正确:使用常量比较,逻辑等价但语义清晰) +isFirstRealname := card.RealNameStatus != constants.RealNameStatusVerified && + newRealnameStatus == constants.RealNameStatusVerified +``` + +**③ `internal/model/iot_card.go` — Model gorm comment** + +```go +// 修改前 +RealNameStatus int `gorm:"...comment:实名状态 0-未实名 1-已实名(行业卡可以保持0)" json:"real_name_status"` + +// 修改后(统一注释,去除误导性括号说明) +RealNameStatus int `gorm:"...comment:实名状态 0-未实名 1-已实名" json:"real_name_status"` +``` + +**④ `internal/model/dto/asset_dto.go` — DTO description** + +```go +// 修改前(错误:包含 1实名中 2已实名 的旧三态描述) +RealNameStatus int `json:"real_name_status" description:"实名状态:0未实名 1实名中 2已实名"` + +// 修改后(正确:两态) +RealNameStatus int `json:"real_name_status" description:"实名状态:0未实名 1已实名"` +``` + +**⑤ `internal/polling/scheduler.go` — `getCardCondition`** + +```go +// 修改前(错误:使用硬编码 0/1/2 三态判断) +if card.RealNameStatus == 0 || card.RealNameStatus == 1 { + return "not_real_name" +} +if card.RealNameStatus == 2 { + // ... +} + +// 修改后(正确:两态常量判断) +if card.RealNameStatus != constants.RealNameStatusVerified { + return "not_real_name" +} +if card.RealNameStatus == constants.RealNameStatusVerified { + // ... +} +``` + +**⑥ `internal/service/iot_card/service.go` — `parseGatewayRealnameStatus`** + +```go +// 修改前(错误:返回硬编码 2) +// true=已实名(2),false=未实名(0) +func parseGatewayRealnameStatus(realStatus bool) int { + if realStatus { return 2 } + return 0 +} + +// 修改后(正确:返回常量) +// true=已实名(1),false=未实名(0) +func parseGatewayRealnameStatus(realStatus bool) int { + if realStatus { return constants.RealNameStatusVerified } + return constants.RealNameStatusNotVerified +} +``` + +--- + +### Task 2 — CRITICAL-02 修复 + +**① `internal/service/client_order/service.go`** + +```go +// 修改前(硬编码 1,语义不清晰) +if packagesNeedRealname(validationResult.Packages) && assetInfo.RealNameStatus != 1 { + +// 修改后(常量比较,语义明确) +if packagesNeedRealname(validationResult.Packages) && assetInfo.RealNameStatus != constants.RealNameStatusVerified { +``` + +**② `internal/handler/app/client_realname.go`** + +```go +// 修改前(硬编码 1) +if targetCard.RealNameStatus == 1 { + +// 修改后(常量) +if targetCard.RealNameStatus == constants.RealNameStatusVerified { +``` + +--- + +## Verification Results + +``` +✅ go build ./... — 编译通过,无错误 +✅ return 2 已消除 — polling_handler.go 中不再有 return 2 +✅ 常量使用确认 — polling_handler.go 和 client_order/service.go 均使用 constants.RealNameStatusVerified +✅ 无遗漏硬编码 — rg 未发现 newRealnameStatus==2 / RealNameStatus==2 / RealNameStatus!=1 +``` + +--- + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 2 - 缺失修复] 修复 asset_dto.go DTO description** +- **Found during:** Task 1 全局搜索 +- **Issue:** `asset_dto.go` 的 `RealNameStatus` description 仍含旧三态描述 `1实名中 2已实名` +- **Fix:** 更新为 `0未实名 1已实名` +- **Files modified:** `internal/model/dto/asset_dto.go` +- **Commit:** `1fd0072` + +**2. [Rule 2 - 缺失修复] 修复 scheduler.go 硬编码三态判断** +- **Found during:** Task 1 全局搜索 +- **Issue:** `scheduler.go:getCardCondition` 使用 `RealNameStatus == 0 || == 1 || == 2` 硬编码 +- **Fix:** 改为 `!= constants.RealNameStatusVerified` / `== constants.RealNameStatusVerified` +- **Files modified:** `internal/polling/scheduler.go` +- **Commit:** `1fd0072` + +**3. [Rule 2 - 缺失修复] 修复 iot_card/service.go 另一处 return 2** +- **Found during:** Task 1 全局搜索 +- **Issue:** `parseGatewayRealnameStatus` 函数也返回硬编码 `2`,与 polling_handler.go 同等问题 +- **Fix:** 改为常量返回 +- **Files modified:** `internal/service/iot_card/service.go` +- **Commit:** `1fd0072` + +**4. [Rule 2 - 缺失修复] 修复 client_realname.go Handler 层硬编码** +- **Found during:** Task 2 全局搜索 +- **Issue:** `client_realname.go:128` Handler 层 `== 1` 硬编码实名判断 +- **Fix:** 改为 `constants.RealNameStatusVerified` +- **Files modified:** `internal/handler/app/client_realname.go` +- **Commit:** `da50a35` + +--- + +## Requirements Completed + +- ✅ **CRITICAL-01**: 实名状态常量统一(DB 写入值 2 vs 常量 1,所有链路断裂)— 已修复 +- ✅ **CRITICAL-02**: C 端实名校验修复(依赖 CRITICAL-01)— 已修复 + +--- + +## Self-Check: PASSED + +- ✅ `internal/task/polling_handler.go` — 已修改并提交 +- ✅ `internal/model/iot_card.go` — 已修改并提交 +- ✅ `internal/service/client_order/service.go` — 已修改并提交 +- ✅ commit `1fd0072` — 存在(Task 1) +- ✅ commit `da50a35` — 存在(Task 2)