225 lines
8.1 KiB
Markdown
225 lines
8.1 KiB
Markdown
---
|
||
phase: 01-p0
|
||
plan: 01
|
||
type: execute
|
||
wave: 1
|
||
depends_on: []
|
||
files_modified:
|
||
- internal/task/polling_handler.go
|
||
- internal/model/iot_card.go
|
||
- internal/service/client_order/service.go
|
||
autonomous: true
|
||
requirements:
|
||
- CRITICAL-01
|
||
- CRITICAL-02
|
||
must_haves:
|
||
truths:
|
||
- "parseRealnameStatus 返回 constants.RealNameStatusVerified(=1),不再返回硬编码 2"
|
||
- "isFirstRealname 判断使用常量比较,不再使用 == 2"
|
||
- "Model 注释与常量一致:0=未实名, 1=已实名"
|
||
- "client_order 实名校验使用 constants.RealNameStatusVerified,不再硬编码 1"
|
||
artifacts:
|
||
- path: internal/task/polling_handler.go
|
||
provides: "parseRealnameStatus 返回常量值,isFirstRealname 使用常量"
|
||
contains: "constants.RealNameStatusVerified"
|
||
- path: internal/model/iot_card.go
|
||
provides: "Model 字段注释统一"
|
||
contains: "0-未实名 1-已实名"
|
||
- path: internal/service/client_order/service.go
|
||
provides: "实名校验改为常量比较"
|
||
contains: "constants.RealNameStatusVerified"
|
||
key_links:
|
||
- from: internal/task/polling_handler.go
|
||
to: pkg/constants/iot.go
|
||
via: "constants.RealNameStatusVerified"
|
||
pattern: "constants\\.RealNameStatusVerified"
|
||
- from: internal/service/client_order/service.go
|
||
to: pkg/constants/iot.go
|
||
via: "constants.RealNameStatusVerified"
|
||
pattern: "constants\\.RealNameStatusVerified"
|
||
---
|
||
|
||
<objective>
|
||
统一实名状态常量(CRITICAL-01),并修复 C 端实名校验(CRITICAL-02)。
|
||
|
||
Purpose: 这是整个修复链路的前置条件。轮询写入 2、常量定义 1、校验用 1 三处不一致造成实名链路全面断裂。修复后实名状态全链路统一为 0=未实名、1=已实名。CRITICAL-02 依赖本 Plan 完成才能自动正确。
|
||
|
||
Output:
|
||
- polling_handler.go 写入值改为常量 1
|
||
- iot_card.go 注释与常量统一
|
||
- client_order/service.go 校验使用常量
|
||
</objective>
|
||
|
||
<execution_context>
|
||
@$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md
|
||
@$HOME/.config/opencode/get-shit-done/templates/summary.md
|
||
</execution_context>
|
||
|
||
<context>
|
||
@.planning/PROJECT.md
|
||
@.planning/ROADMAP.md
|
||
@.planning/STATE.md
|
||
@.planning/phases/01-p0/01-CONTEXT.md
|
||
|
||
# 修复规格书(核心参考)
|
||
@.sisyphus/plans/修正业务-完整方案.md
|
||
|
||
<interfaces>
|
||
<!-- 从 pkg/constants/iot.go 提取的常量,executor 直接使用 -->
|
||
|
||
```go
|
||
// pkg/constants/iot.go(已确认存在,第 47-48 行附近)
|
||
const (
|
||
RealNameStatusNotVerified = 0 // 未实名
|
||
RealNameStatusVerified = 1 // 已实名
|
||
)
|
||
```
|
||
|
||
<!-- polling_handler.go 当前错误代码(需改掉) -->
|
||
<!-- 第 696-700 行:parseRealnameStatus 返回 2(错误) -->
|
||
<!-- 第 170 行:isFirstRealname 使用 == 2(错误) -->
|
||
|
||
<!-- client_order/service.go 当前代码(第 115 行附近) -->
|
||
<!-- assetInfo.RealNameStatus != 1(硬编码,需改为常量) -->
|
||
</interfaces>
|
||
</context>
|
||
|
||
<tasks>
|
||
|
||
<task type="auto">
|
||
<name>Task 1: 修复 polling_handler.go 实名状态写入值(CRITICAL-01 核心)</name>
|
||
<files>internal/task/polling_handler.go, internal/model/iot_card.go</files>
|
||
<action>
|
||
**修改 `internal/task/polling_handler.go`:**
|
||
|
||
① `parseRealnameStatus` 函数(第 696-700 行附近):
|
||
```go
|
||
// 修改前
|
||
func (h *PollingHandler) parseRealnameStatus(realStatus bool) int {
|
||
if realStatus {
|
||
return 2 // 已实名
|
||
}
|
||
return 0 // 未实名
|
||
}
|
||
|
||
// 修改后(使用常量,per D-01)
|
||
func (h *PollingHandler) parseRealnameStatus(realStatus bool) int {
|
||
if realStatus {
|
||
return constants.RealNameStatusVerified // = 1,已实名
|
||
}
|
||
return constants.RealNameStatusNotVerified // = 0,未实名
|
||
}
|
||
```
|
||
|
||
② `isFirstRealname` 判断(第 170 行附近):
|
||
```go
|
||
// 修改前
|
||
isFirstRealname := (card.RealNameStatus == 0 || card.RealNameStatus == 1) && newRealnameStatus == 2
|
||
|
||
// 修改后(使用常量比较,per D-01)
|
||
isFirstRealname := card.RealNameStatus != constants.RealNameStatusVerified &&
|
||
newRealnameStatus == constants.RealNameStatusVerified
|
||
```
|
||
|
||
③ 全局搜索 `polling_handler.go` 及 `internal/model/dto/` 下 DTO 注释,将所有 `2=已实名`、`1实名中` 改为 `0=未实名, 1=已实名`(执行:`grep -rn "2=已实名\|1实名中\|RealNameStatus.*2" internal/model/dto/ --include="*.go"`)。
|
||
|
||
**修改 `internal/model/iot_card.go`:**
|
||
|
||
找到第 30 行附近 `RealNameStatus` 字段的 gorm comment:
|
||
```go
|
||
// 修改前
|
||
RealNameStatus int `gorm:"...; comment:实名状态 0-未实名 1-已实名(行业卡可以保持0)"`
|
||
|
||
// 修改后(统一,per D-01)
|
||
RealNameStatus int `gorm:"...; comment:实名状态 0-未实名 1-已实名"`
|
||
```
|
||
|
||
修改完成后执行:`go build ./...`,确认编译通过,提交一个独立 commit(per D-05)。
|
||
</action>
|
||
<verify>
|
||
<automated>go build ./... && rg "return 2" internal/task/polling_handler.go && echo "FAIL: 仍存在 return 2" || echo "PASS: return 2 已消除"</automated>
|
||
</verify>
|
||
<done>
|
||
- polling_handler.go 中 parseRealnameStatus 不再 return 2,改为 return constants.RealNameStatusVerified
|
||
- isFirstRealname 不再用 == 2,改为 == constants.RealNameStatusVerified
|
||
- iot_card.go 注释统一为 0-未实名 1-已实名
|
||
- go build ./... 编译通过
|
||
</done>
|
||
</task>
|
||
|
||
<task type="auto">
|
||
<name>Task 2: 修复 C 端实名校验(CRITICAL-02)</name>
|
||
<files>internal/service/client_order/service.go</files>
|
||
<action>
|
||
**修改 `internal/service/client_order/service.go`(第 115 行附近):**
|
||
|
||
找到实名校验判断:
|
||
```go
|
||
// 修改前(硬编码 1,本质上是 A-1 修完后 DB 里是 1 才会正确,但语义要用常量)
|
||
if packagesNeedRealname(validationResult.Packages) && assetInfo.RealNameStatus != 1 {
|
||
return errors.New(errors.CodeForbidden, "请先完成实名认证")
|
||
}
|
||
|
||
// 修改后(使用常量,per CRITICAL-02 规格)
|
||
if packagesNeedRealname(validationResult.Packages) && assetInfo.RealNameStatus != constants.RealNameStatusVerified {
|
||
return errors.New(errors.CodeForbidden, "请先完成实名认证")
|
||
}
|
||
```
|
||
|
||
同时检查同文件和 `polling_handler.go:982` 是否有其他硬编码 `!= 1` 的实名判断(`rg "RealNameStatus.*!= 1\|!= 1.*RealNameStatus" internal/`),若有,同样改为常量。
|
||
|
||
确认 constants 包已正确 import(若未 import,在 import 块补充 `pkgpath/constants`)。
|
||
|
||
修改完成后执行:`go build ./...`,编译通过后提交独立 commit(per D-05)。
|
||
</action>
|
||
<verify>
|
||
<automated>go build ./... && rg "RealNameStatus != 1" internal/service/client_order/service.go && echo "FAIL: 仍有硬编码" || echo "PASS: 硬编码已消除"</automated>
|
||
</verify>
|
||
<done>
|
||
- client_order/service.go 实名校验改为 constants.RealNameStatusVerified
|
||
- go build ./... 编译通过
|
||
- rg 确认不再有 != 1 的硬编码实名判断
|
||
</done>
|
||
</task>
|
||
|
||
</tasks>
|
||
|
||
<verification>
|
||
整体验收(两个任务完成后):
|
||
|
||
```bash
|
||
# 1. 编译验证
|
||
go build ./...
|
||
|
||
# 2. 确认 parseRealnameStatus 不再写 2
|
||
rg "return 2" internal/task/polling_handler.go
|
||
|
||
# 3. 确认实名判断全部使用常量
|
||
rg "RealNameStatusVerified" internal/task/polling_handler.go internal/service/client_order/service.go
|
||
|
||
# 4. 搜索遗漏的硬编码
|
||
rg "newRealnameStatus == 2\|RealNameStatus == 2\|RealNameStatus != 1" internal/ --include="*.go"
|
||
```
|
||
|
||
人工验收(参见修正业务-完整方案.md 方案 A 验收清单 A-1、A-2):
|
||
- DBHub 执行:`SELECT DISTINCT real_name_status FROM tb_iot_card ORDER BY 1;`
|
||
- 预期:只存在 0 和 1,不存在 2
|
||
</verification>
|
||
|
||
<success_criteria>
|
||
1. `go build ./...` 编译通过,无错误
|
||
2. `parseRealnameStatus(true)` 返回 1(constants.RealNameStatusVerified),不再返回 2
|
||
3. `isFirstRealname` 不再使用 == 2 判断
|
||
4. `client_order/service.go` 实名校验使用常量,不再硬编码 1
|
||
5. Model 注释与常量定义一致
|
||
6. 两个独立 commit 已提交
|
||
</success_criteria>
|
||
|
||
<output>
|
||
完成后创建 `.planning/phases/01-p0/01-01-SUMMARY.md`,记录:
|
||
- 修改了哪些文件(文件路径 + 改动说明)
|
||
- 关键代码片段(修改前后对比)
|
||
- 编译验证结果
|
||
- CRITICAL-01 和 CRITICAL-02 完成状态
|
||
</output>
|