chore: 新增 systematic-debugging 技能,更新项目开发规范
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m27s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m27s
新增 systematic-debugging Skill(四阶段根因分析流程),在 AGENTS.md 和 CLAUDE.md 中补充触发条件说明。opencode.json 配置同步更新。 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
260
.claude/skills/systematic-debugging/SKILL.md
Normal file
260
.claude/skills/systematic-debugging/SKILL.md
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
---
|
||||||
|
name: systematic-debugging
|
||||||
|
description: 遇到任何 bug、异常行为、报错时必须使用。在提出任何修复方案之前,强制执行根因分析流程。适用于 API 报错、数据异常、业务逻辑错误、性能问题等所有技术问题。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 系统化调试方法论
|
||||||
|
|
||||||
|
## 铁律
|
||||||
|
|
||||||
|
```
|
||||||
|
没有找到根因,禁止提出任何修复方案。
|
||||||
|
```
|
||||||
|
|
||||||
|
改之前先搞懂为什么坏了。猜测不是调试,验证假设才是。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 什么时候用
|
||||||
|
|
||||||
|
**所有技术问题都用这个流程**:
|
||||||
|
- API 接口报错(4xx / 5xx)
|
||||||
|
- 业务数据异常(金额不对、状态流转错误)
|
||||||
|
- 性能问题(接口慢、数据库慢查询)
|
||||||
|
- 异步任务失败(Asynq 任务报错/卡住)
|
||||||
|
- 构建失败、启动失败
|
||||||
|
|
||||||
|
**尤其是以下场景**:
|
||||||
|
- 时间紧迫(越急越不能瞎猜)
|
||||||
|
- "很简单的问题"(简单问题也有根因)
|
||||||
|
- 已经试了一次修复但没解决
|
||||||
|
- 不完全理解为什么出问题
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四阶段流程
|
||||||
|
|
||||||
|
必须按顺序完成每个阶段,不可跳过。
|
||||||
|
|
||||||
|
### 阶段一:根因调查
|
||||||
|
|
||||||
|
**这是最重要的阶段,占整个调试时间的 60%。没完成本阶段,禁止进入阶段二。**
|
||||||
|
|
||||||
|
#### 1. 仔细阅读错误信息
|
||||||
|
|
||||||
|
- 完整阅读 stack trace,不要跳过
|
||||||
|
- 注意行号、文件路径、错误码
|
||||||
|
- 很多时候答案就在错误信息里
|
||||||
|
- 检查 `logs/app.log` 和 `logs/access.log` 中的上下文
|
||||||
|
|
||||||
|
#### 2. 稳定复现
|
||||||
|
|
||||||
|
- 能稳定触发吗?精确的请求参数是什么?
|
||||||
|
- 用 curl 或 Postman 复现,记录完整的请求和响应
|
||||||
|
- 不能复现 → 收集更多数据(检查日志、Redis 状态、数据库记录),**不要瞎猜**
|
||||||
|
|
||||||
|
#### 3. 检查最近改动
|
||||||
|
|
||||||
|
- `git diff` / `git log --oneline -10` 看最近改了什么
|
||||||
|
- 新加了什么依赖?改了什么配置?改了什么 SQL?
|
||||||
|
- 对比改动前后的行为差异
|
||||||
|
|
||||||
|
#### 4. 逐层诊断(针对本项目架构)
|
||||||
|
|
||||||
|
本项目有明确的分层架构,问题一定出在某一层的边界:
|
||||||
|
|
||||||
|
```
|
||||||
|
请求 → Fiber Middleware → Handler → Service → Store → PostgreSQL/Redis
|
||||||
|
↑ ↑ ↑ ↑ ↑
|
||||||
|
认证/限流 参数解析 业务逻辑 SQL/缓存 数据本身
|
||||||
|
```
|
||||||
|
|
||||||
|
**在每个层边界确认数据是否正确**:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Handler 层 — 请求进来的参数对不对?
|
||||||
|
logger.Info("Handler 收到请求",
|
||||||
|
zap.Any("params", req),
|
||||||
|
zap.String("request_id", requestID),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service 层 — 传给业务逻辑的数据对不对?
|
||||||
|
logger.Info("Service 开始处理",
|
||||||
|
zap.Uint("user_id", userID),
|
||||||
|
zap.Any("input", input),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store 层 — SQL 查询/写入的数据对不对?
|
||||||
|
// 开启 GORM Debug 模式查看实际 SQL
|
||||||
|
db.Debug().Where(...).Find(&result)
|
||||||
|
|
||||||
|
// Redis 层 — 缓存的数据对不对?
|
||||||
|
// 用 redis-cli 直接检查 key 的值
|
||||||
|
// GET auth:token:{token}
|
||||||
|
// GET sim:status:{iccid}
|
||||||
|
```
|
||||||
|
|
||||||
|
**跑一次 → 看日志 → 找到断裂的那一层 → 再深入该层排查。**
|
||||||
|
|
||||||
|
#### 5. 追踪数据流
|
||||||
|
|
||||||
|
如果错误深藏在调用链中:
|
||||||
|
- 坏数据从哪来的?
|
||||||
|
- 谁调用了这个函数,传了什么参数?
|
||||||
|
- 一直往上追,直到找到数据变坏的源头
|
||||||
|
- **修源头,不修症状**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段二:模式分析
|
||||||
|
|
||||||
|
**找到参照物,对比差异。**
|
||||||
|
|
||||||
|
#### 1. 找能用的参照
|
||||||
|
|
||||||
|
项目里有没有类似的、能正常工作的代码?
|
||||||
|
|
||||||
|
| 如果问题在... | 参照物在... |
|
||||||
|
|-------------|-----------|
|
||||||
|
| Handler 参数解析 | 其他 Handler 的相同模式 |
|
||||||
|
| Service 业务逻辑 | 同模块其他方法的实现 |
|
||||||
|
| Store SQL 查询 | 同 Store 文件中类似的查询 |
|
||||||
|
| Redis 操作 | `pkg/constants/redis.go` 中的 Key 定义 |
|
||||||
|
| 异步任务 | `internal/task/` 中其他任务处理器 |
|
||||||
|
| GORM Callback | `pkg/database/` 中的 callback 实现 |
|
||||||
|
|
||||||
|
#### 2. 逐行对比
|
||||||
|
|
||||||
|
完整阅读参考代码,不要跳读。列出每一处差异。
|
||||||
|
|
||||||
|
#### 3. 不要假设"这个不重要"
|
||||||
|
|
||||||
|
小差异经常是 bug 的根因:
|
||||||
|
- 字段标签 `gorm:"column:xxx"` 拼写不对
|
||||||
|
- `errors.New()` 用了错误的错误码
|
||||||
|
- Redis Key 函数参数传反了
|
||||||
|
- Context 里的 UserID 没取到(中间件没配)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段三:假设和验证
|
||||||
|
|
||||||
|
**科学方法:一次只验证一个假设。**
|
||||||
|
|
||||||
|
#### 1. 形成单一假设
|
||||||
|
|
||||||
|
明确写下:
|
||||||
|
|
||||||
|
> "我认为根因是 X,因为 Y。验证方法是 Z。"
|
||||||
|
|
||||||
|
#### 2. 最小化验证
|
||||||
|
|
||||||
|
- 只改一个地方
|
||||||
|
- 一次只验证一个变量
|
||||||
|
- 不要同时修多处
|
||||||
|
|
||||||
|
#### 3. 验证结果
|
||||||
|
|
||||||
|
- 假设成立 → 进入阶段四
|
||||||
|
- 假设不成立 → 回到阶段一,用新信息重新分析
|
||||||
|
- **绝对不能在失败的修复上再叠加修复**
|
||||||
|
|
||||||
|
#### 4. 三次失败 → 停下来
|
||||||
|
|
||||||
|
如果连续 3 次假设都不成立:
|
||||||
|
|
||||||
|
**这不是 bug,是架构问题。**
|
||||||
|
|
||||||
|
- 停止一切修复尝试
|
||||||
|
- 整理已知信息
|
||||||
|
- 向用户说明情况,讨论是否需要重构
|
||||||
|
- 不要再试第 4 次
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段四:实施修复
|
||||||
|
|
||||||
|
**确认根因后,一次性修好。**
|
||||||
|
|
||||||
|
#### 1. 修根因,不修症状
|
||||||
|
|
||||||
|
```
|
||||||
|
❌ 症状修复:在 Handler 里加个 if 把坏数据过滤掉
|
||||||
|
✅ 根因修复:修 Service 层生成坏数据的逻辑
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. 一次只改一个地方
|
||||||
|
|
||||||
|
- 不搞"顺手优化"
|
||||||
|
- 不在修 bug 的同时重构代码
|
||||||
|
- 修完 bug 就停
|
||||||
|
|
||||||
|
#### 3. 验证修复
|
||||||
|
|
||||||
|
- `go build ./...` 编译通过
|
||||||
|
- `lsp_diagnostics` 无新增错误
|
||||||
|
- 用原来复现 bug 的请求再跑一次,确认修好了
|
||||||
|
- 用 PostgreSQL MCP 工具检查数据库中的数据状态
|
||||||
|
|
||||||
|
#### 4. 清理诊断代码
|
||||||
|
|
||||||
|
- 删除阶段一加的临时诊断日志(除非它们本身就该保留)
|
||||||
|
- 确保没有 `db.Debug()` 残留在代码里
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 本项目常见调试场景速查
|
||||||
|
|
||||||
|
| 场景 | 首先检查 |
|
||||||
|
|------|---------|
|
||||||
|
| API 返回 401 | `logs/access.log` 中该请求的 token → Redis 中 `auth:token:{token}` 是否存在 |
|
||||||
|
| API 返回 403 | 用户类型是什么 → GORM Callback 自动过滤的条件对不对 → `middleware.CanManageShop()` 的参数 |
|
||||||
|
| 数据查不到 | GORM 数据权限过滤有没有生效 → `shop_id` / `enterprise_id` 是否正确 → 是否需要 `SkipDataPermission` |
|
||||||
|
| 金额/余额不对 | 乐观锁 version 字段 → `RowsAffected` 是否为 0 → 并发场景下的锁竞争 |
|
||||||
|
| 状态流转错误 | `WHERE status = expected` 条件更新 → 状态机是否有遗漏的路径 |
|
||||||
|
| 异步任务不执行 | Asynq Dashboard → `RedisTaskLockKey` 有没有残留 → Worker 日志 |
|
||||||
|
| 异步任务重复执行 | `RedisTaskLockKey` 的 TTL → 任务幂等性检查 |
|
||||||
|
| 分佣计算错误 | 佣金类型(差价/一次性) → 套餐级别的佣金率 → 设备级防重复分佣 |
|
||||||
|
| 套餐激活异常 | 卡状态 → 实名状态 → 主套餐排队逻辑 → 加油包绑定关系 |
|
||||||
|
| Redis 缓存不一致 | Key 的 TTL → 缓存更新时机 → 是否有手动 `Del` 清除 |
|
||||||
|
| 微信支付回调失败 | 签名验证 → 幂等性处理 → 回调 URL 是否可达 |
|
||||||
|
| GORM 查询慢 | `db.Debug()` 看实际 SQL → 是否 N+1 → 是否缺少索引 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 红线规则
|
||||||
|
|
||||||
|
如果你发现自己在想以下任何一条,**立刻停下来,回到阶段一**:
|
||||||
|
|
||||||
|
| 想法 | 为什么是错的 |
|
||||||
|
|------|------------|
|
||||||
|
| "先快速修一下,回头再查" | 快速修 = 猜测。猜测 = 浪费时间。 |
|
||||||
|
| "试试改这个看看行不行" | 一次只验证一个假设,不是随机改。 |
|
||||||
|
| "大概是 X 的问题,我直接改了" | "大概"不是根因。先验证再改。 |
|
||||||
|
| "这个很简单,不用走流程" | 简单问题走流程只需要 5 分钟。不走流程可能浪费 2 小时。 |
|
||||||
|
| "我不完全理解但这应该行" | 不理解 = 没找到根因。回阶段一。 |
|
||||||
|
| "再试一次"(已经失败 2 次) | 3 次失败 = 架构问题。停下来讨论。 |
|
||||||
|
| "同时改这几个地方应该能修好" | 改多处 = 无法确认哪个是根因。一次只改一处。 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见借口和真相
|
||||||
|
|
||||||
|
| 借口 | 真相 |
|
||||||
|
|------|------|
|
||||||
|
| "问题很简单,不需要走流程" | 简单问题也有根因。走流程对简单问题只花 5 分钟。 |
|
||||||
|
| "太紧急了,没时间分析" | 系统化调试比乱猜快 3-5 倍。越急越要走流程。 |
|
||||||
|
| "先改了验证一下" | 这叫猜测,不叫验证。先确认根因再改。 |
|
||||||
|
| "我看到问题了,直接修" | 看到症状 ≠ 理解根因。症状修复是技术债。 |
|
||||||
|
| "改了好几个地方,反正能用了" | 不知道哪个改动修的,下次还会出问题。 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速参考
|
||||||
|
|
||||||
|
| 阶段 | 核心动作 | 完成标准 |
|
||||||
|
|------|---------|---------|
|
||||||
|
| **一、根因调查** | 读错误日志、复现、检查改动、逐层诊断、追踪数据流 | 能说清楚"因为 X 所以 Y" |
|
||||||
|
| **二、模式分析** | 找参照代码、逐行对比、列出差异 | 知道正确的应该长什么样 |
|
||||||
|
| **三、假设验证** | 写下假设、最小改动、单变量验证 | 假设被证实或推翻 |
|
||||||
|
| **四、实施修复** | 修根因、编译检查、请求验证、清理诊断代码 | bug 消失,无新增问题 |
|
||||||
265
.opencode/skills/systematic-debugging/SKILL.md
Normal file
265
.opencode/skills/systematic-debugging/SKILL.md
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
---
|
||||||
|
name: systematic-debugging
|
||||||
|
description: 遇到任何 bug、异常行为、报错时必须使用。在提出任何修复方案之前,强制执行根因分析流程。适用于 API 报错、数据异常、业务逻辑错误、性能问题等所有技术问题。
|
||||||
|
license: MIT
|
||||||
|
metadata:
|
||||||
|
author: junhong
|
||||||
|
version: "1.0"
|
||||||
|
source: "adapted from obra/superpowers systematic-debugging"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 系统化调试方法论
|
||||||
|
|
||||||
|
## 铁律
|
||||||
|
|
||||||
|
```
|
||||||
|
没有找到根因,禁止提出任何修复方案。
|
||||||
|
```
|
||||||
|
|
||||||
|
改之前先搞懂为什么坏了。猜测不是调试,验证假设才是。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 什么时候用
|
||||||
|
|
||||||
|
**所有技术问题都用这个流程**:
|
||||||
|
- API 接口报错(4xx / 5xx)
|
||||||
|
- 业务数据异常(金额不对、状态流转错误)
|
||||||
|
- 性能问题(接口慢、数据库慢查询)
|
||||||
|
- 异步任务失败(Asynq 任务报错/卡住)
|
||||||
|
- 构建失败、启动失败
|
||||||
|
|
||||||
|
**尤其是以下场景**:
|
||||||
|
- 时间紧迫(越急越不能瞎猜)
|
||||||
|
- "很简单的问题"(简单问题也有根因)
|
||||||
|
- 已经试了一次修复但没解决
|
||||||
|
- 不完全理解为什么出问题
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四阶段流程
|
||||||
|
|
||||||
|
必须按顺序完成每个阶段,不可跳过。
|
||||||
|
|
||||||
|
### 阶段一:根因调查
|
||||||
|
|
||||||
|
**这是最重要的阶段,占整个调试时间的 60%。没完成本阶段,禁止进入阶段二。**
|
||||||
|
|
||||||
|
#### 1. 仔细阅读错误信息
|
||||||
|
|
||||||
|
- 完整阅读 stack trace,不要跳过
|
||||||
|
- 注意行号、文件路径、错误码
|
||||||
|
- 很多时候答案就在错误信息里
|
||||||
|
- 检查 `logs/app.log` 和 `logs/access.log` 中的上下文
|
||||||
|
|
||||||
|
#### 2. 稳定复现
|
||||||
|
|
||||||
|
- 能稳定触发吗?精确的请求参数是什么?
|
||||||
|
- 用 curl 或 Postman 复现,记录完整的请求和响应
|
||||||
|
- 不能复现 → 收集更多数据(检查日志、Redis 状态、数据库记录),**不要瞎猜**
|
||||||
|
|
||||||
|
#### 3. 检查最近改动
|
||||||
|
|
||||||
|
- `git diff` / `git log --oneline -10` 看最近改了什么
|
||||||
|
- 新加了什么依赖?改了什么配置?改了什么 SQL?
|
||||||
|
- 对比改动前后的行为差异
|
||||||
|
|
||||||
|
#### 4. 逐层诊断(针对本项目架构)
|
||||||
|
|
||||||
|
本项目有明确的分层架构,问题一定出在某一层的边界:
|
||||||
|
|
||||||
|
```
|
||||||
|
请求 → Fiber Middleware → Handler → Service → Store → PostgreSQL/Redis
|
||||||
|
↑ ↑ ↑ ↑ ↑
|
||||||
|
认证/限流 参数解析 业务逻辑 SQL/缓存 数据本身
|
||||||
|
```
|
||||||
|
|
||||||
|
**在每个层边界确认数据是否正确**:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Handler 层 — 请求进来的参数对不对?
|
||||||
|
logger.Info("Handler 收到请求",
|
||||||
|
zap.Any("params", req),
|
||||||
|
zap.String("request_id", requestID),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service 层 — 传给业务逻辑的数据对不对?
|
||||||
|
logger.Info("Service 开始处理",
|
||||||
|
zap.Uint("user_id", userID),
|
||||||
|
zap.Any("input", input),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store 层 — SQL 查询/写入的数据对不对?
|
||||||
|
// 开启 GORM Debug 模式查看实际 SQL
|
||||||
|
db.Debug().Where(...).Find(&result)
|
||||||
|
|
||||||
|
// Redis 层 — 缓存的数据对不对?
|
||||||
|
// 用 redis-cli 直接检查 key 的值
|
||||||
|
// GET auth:token:{token}
|
||||||
|
// GET sim:status:{iccid}
|
||||||
|
```
|
||||||
|
|
||||||
|
**跑一次 → 看日志 → 找到断裂的那一层 → 再深入该层排查。**
|
||||||
|
|
||||||
|
#### 5. 追踪数据流
|
||||||
|
|
||||||
|
如果错误深藏在调用链中:
|
||||||
|
- 坏数据从哪来的?
|
||||||
|
- 谁调用了这个函数,传了什么参数?
|
||||||
|
- 一直往上追,直到找到数据变坏的源头
|
||||||
|
- **修源头,不修症状**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段二:模式分析
|
||||||
|
|
||||||
|
**找到参照物,对比差异。**
|
||||||
|
|
||||||
|
#### 1. 找能用的参照
|
||||||
|
|
||||||
|
项目里有没有类似的、能正常工作的代码?
|
||||||
|
|
||||||
|
| 如果问题在... | 参照物在... |
|
||||||
|
|-------------|-----------|
|
||||||
|
| Handler 参数解析 | 其他 Handler 的相同模式 |
|
||||||
|
| Service 业务逻辑 | 同模块其他方法的实现 |
|
||||||
|
| Store SQL 查询 | 同 Store 文件中类似的查询 |
|
||||||
|
| Redis 操作 | `pkg/constants/redis.go` 中的 Key 定义 |
|
||||||
|
| 异步任务 | `internal/task/` 中其他任务处理器 |
|
||||||
|
| GORM Callback | `pkg/database/` 中的 callback 实现 |
|
||||||
|
|
||||||
|
#### 2. 逐行对比
|
||||||
|
|
||||||
|
完整阅读参考代码,不要跳读。列出每一处差异。
|
||||||
|
|
||||||
|
#### 3. 不要假设"这个不重要"
|
||||||
|
|
||||||
|
小差异经常是 bug 的根因:
|
||||||
|
- 字段标签 `gorm:"column:xxx"` 拼写不对
|
||||||
|
- `errors.New()` 用了错误的错误码
|
||||||
|
- Redis Key 函数参数传反了
|
||||||
|
- Context 里的 UserID 没取到(中间件没配)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段三:假设和验证
|
||||||
|
|
||||||
|
**科学方法:一次只验证一个假设。**
|
||||||
|
|
||||||
|
#### 1. 形成单一假设
|
||||||
|
|
||||||
|
明确写下:
|
||||||
|
|
||||||
|
> "我认为根因是 X,因为 Y。验证方法是 Z。"
|
||||||
|
|
||||||
|
#### 2. 最小化验证
|
||||||
|
|
||||||
|
- 只改一个地方
|
||||||
|
- 一次只验证一个变量
|
||||||
|
- 不要同时修多处
|
||||||
|
|
||||||
|
#### 3. 验证结果
|
||||||
|
|
||||||
|
- 假设成立 → 进入阶段四
|
||||||
|
- 假设不成立 → 回到阶段一,用新信息重新分析
|
||||||
|
- **绝对不能在失败的修复上再叠加修复**
|
||||||
|
|
||||||
|
#### 4. 三次失败 → 停下来
|
||||||
|
|
||||||
|
如果连续 3 次假设都不成立:
|
||||||
|
|
||||||
|
**这不是 bug,是架构问题。**
|
||||||
|
|
||||||
|
- 停止一切修复尝试
|
||||||
|
- 整理已知信息
|
||||||
|
- 向用户说明情况,讨论是否需要重构
|
||||||
|
- 不要再试第 4 次
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段四:实施修复
|
||||||
|
|
||||||
|
**确认根因后,一次性修好。**
|
||||||
|
|
||||||
|
#### 1. 修根因,不修症状
|
||||||
|
|
||||||
|
```
|
||||||
|
❌ 症状修复:在 Handler 里加个 if 把坏数据过滤掉
|
||||||
|
✅ 根因修复:修 Service 层生成坏数据的逻辑
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. 一次只改一个地方
|
||||||
|
|
||||||
|
- 不搞"顺手优化"
|
||||||
|
- 不在修 bug 的同时重构代码
|
||||||
|
- 修完 bug 就停
|
||||||
|
|
||||||
|
#### 3. 验证修复
|
||||||
|
|
||||||
|
- `go build ./...` 编译通过
|
||||||
|
- `lsp_diagnostics` 无新增错误
|
||||||
|
- 用原来复现 bug 的请求再跑一次,确认修好了
|
||||||
|
- 用 PostgreSQL MCP 工具检查数据库中的数据状态
|
||||||
|
|
||||||
|
#### 4. 清理诊断代码
|
||||||
|
|
||||||
|
- 删除阶段一加的临时诊断日志(除非它们本身就该保留)
|
||||||
|
- 确保没有 `db.Debug()` 残留在代码里
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 本项目常见调试场景速查
|
||||||
|
|
||||||
|
| 场景 | 首先检查 |
|
||||||
|
|------|---------|
|
||||||
|
| API 返回 401 | `logs/access.log` 中该请求的 token → Redis 中 `auth:token:{token}` 是否存在 |
|
||||||
|
| API 返回 403 | 用户类型是什么 → GORM Callback 自动过滤的条件对不对 → `middleware.CanManageShop()` 的参数 |
|
||||||
|
| 数据查不到 | GORM 数据权限过滤有没有生效 → `shop_id` / `enterprise_id` 是否正确 → 是否需要 `SkipDataPermission` |
|
||||||
|
| 金额/余额不对 | 乐观锁 version 字段 → `RowsAffected` 是否为 0 → 并发场景下的锁竞争 |
|
||||||
|
| 状态流转错误 | `WHERE status = expected` 条件更新 → 状态机是否有遗漏的路径 |
|
||||||
|
| 异步任务不执行 | Asynq Dashboard → `RedisTaskLockKey` 有没有残留 → Worker 日志 |
|
||||||
|
| 异步任务重复执行 | `RedisTaskLockKey` 的 TTL → 任务幂等性检查 |
|
||||||
|
| 分佣计算错误 | 佣金类型(差价/一次性) → 套餐级别的佣金率 → 设备级防重复分佣 |
|
||||||
|
| 套餐激活异常 | 卡状态 → 实名状态 → 主套餐排队逻辑 → 加油包绑定关系 |
|
||||||
|
| Redis 缓存不一致 | Key 的 TTL → 缓存更新时机 → 是否有手动 `Del` 清除 |
|
||||||
|
| 微信支付回调失败 | 签名验证 → 幂等性处理 → 回调 URL 是否可达 |
|
||||||
|
| GORM 查询慢 | `db.Debug()` 看实际 SQL → 是否 N+1 → 是否缺少索引 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 红线规则
|
||||||
|
|
||||||
|
如果你发现自己在想以下任何一条,**立刻停下来,回到阶段一**:
|
||||||
|
|
||||||
|
| 想法 | 为什么是错的 |
|
||||||
|
|------|------------|
|
||||||
|
| "先快速修一下,回头再查" | 快速修 = 猜测。猜测 = 浪费时间。 |
|
||||||
|
| "试试改这个看看行不行" | 一次只验证一个假设,不是随机改。 |
|
||||||
|
| "大概是 X 的问题,我直接改了" | "大概"不是根因。先验证再改。 |
|
||||||
|
| "这个很简单,不用走流程" | 简单问题走流程只需要 5 分钟。不走流程可能浪费 2 小时。 |
|
||||||
|
| "我不完全理解但这应该行" | 不理解 = 没找到根因。回阶段一。 |
|
||||||
|
| "再试一次"(已经失败 2 次) | 3 次失败 = 架构问题。停下来讨论。 |
|
||||||
|
| "同时改这几个地方应该能修好" | 改多处 = 无法确认哪个是根因。一次只改一处。 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见借口和真相
|
||||||
|
|
||||||
|
| 借口 | 真相 |
|
||||||
|
|------|------|
|
||||||
|
| "问题很简单,不需要走流程" | 简单问题也有根因。走流程对简单问题只花 5 分钟。 |
|
||||||
|
| "太紧急了,没时间分析" | 系统化调试比乱猜快 3-5 倍。越急越要走流程。 |
|
||||||
|
| "先改了验证一下" | 这叫猜测,不叫验证。先确认根因再改。 |
|
||||||
|
| "我看到问题了,直接修" | 看到症状 ≠ 理解根因。症状修复是技术债。 |
|
||||||
|
| "改了好几个地方,反正能用了" | 不知道哪个改动修的,下次还会出问题。 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速参考
|
||||||
|
|
||||||
|
| 阶段 | 核心动作 | 完成标准 |
|
||||||
|
|------|---------|---------|
|
||||||
|
| **一、根因调查** | 读错误日志、复现、检查改动、逐层诊断、追踪数据流 | 能说清楚"因为 X 所以 Y" |
|
||||||
|
| **二、模式分析** | 找参照代码、逐行对比、列出差异 | 知道正确的应该长什么样 |
|
||||||
|
| **三、假设验证** | 写下假设、最小改动、单变量验证 | 假设被证实或推翻 |
|
||||||
|
| **四、实施修复** | 修根因、编译检查、请求验证、清理诊断代码 | bug 消失,无新增问题 |
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
| 测试接口/验证数据 | `db-validation` | PostgreSQL MCP 使用方法和验证示例 |
|
| 测试接口/验证数据 | `db-validation` | PostgreSQL MCP 使用方法和验证示例 |
|
||||||
| 数据库迁移 | `db-migration` | 迁移命令、文件规范、执行流程、失败处理 |
|
| 数据库迁移 | `db-migration` | 迁移命令、文件规范、执行流程、失败处理 |
|
||||||
| 维护规范文档 | `doc-management` | 规范文档流程和维护规则 |
|
| 维护规范文档 | `doc-management` | 规范文档流程和维护规则 |
|
||||||
|
| 调试 bug / 排查异常 | `systematic-debugging` | 四阶段根因分析流程、逐层诊断、场景速查表 |
|
||||||
|
|
||||||
### ⚠️ 新增 Handler 时必须同步更新文档生成器
|
### ⚠️ 新增 Handler 时必须同步更新文档生成器
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
| 测试接口/验证数据 | `db-validation` | PostgreSQL MCP 使用方法和验证示例 |
|
| 测试接口/验证数据 | `db-validation` | PostgreSQL MCP 使用方法和验证示例 |
|
||||||
| 数据库迁移 | `db-migration` | 迁移命令、文件规范、执行流程、失败处理 |
|
| 数据库迁移 | `db-migration` | 迁移命令、文件规范、执行流程、失败处理 |
|
||||||
| 维护规范文档 | `doc-management` | 规范文档流程和维护规则 |
|
| 维护规范文档 | `doc-management` | 规范文档流程和维护规则 |
|
||||||
|
| 调试 bug / 排查异常 | `systematic-debugging` | 四阶段根因分析流程、逐层诊断、场景速查表 |
|
||||||
|
|
||||||
### ⚠️ 新增 Handler 时必须同步更新文档生成器
|
### ⚠️ 新增 Handler 时必须同步更新文档生成器
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
},
|
},
|
||||||
"google": {
|
"google": {
|
||||||
"options": {
|
"options": {
|
||||||
"baseURL": "http://45.155.220.179:8317",
|
"baseURL": "http://45.155.220.179:8317/v1beta",
|
||||||
"apiKey": "sk-ZBGcMXCdwtSK7G35s"
|
"apiKey": "sk-ZBGcMXCdwtSK7G35s"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user