feat: 实现企业设备授权功能并归档 OpenSpec 变更
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m39s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m39s
- 新增企业设备授权模块(Model、DTO、Service、Handler、Store) - 实现设备授权的创建、查询、更新、删除等完整业务逻辑 - 添加企业卡授权与设备授权的关联关系 - 新增 2 个数据库迁移脚本 - 同步 OpenSpec delta specs 到 main specs - 归档 add-enterprise-device-authorization 变更 - 更新 API 文档和路由配置 - 新增完整的集成测试和单元测试覆盖
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-29
|
||||
|
||||
40
openspec/changes/fix-order-activation-idempotency/design.md
Normal file
40
openspec/changes/fix-order-activation-idempotency/design.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# 订单激活幂等性修复 - 设计
|
||||
|
||||
## 目标
|
||||
|
||||
1. 同一订单被重复支付/重复回调/重复请求时,只会激活一次套餐使用记录。
|
||||
2. 重复请求返回“幂等成功”(不报错,不重复激活)。
|
||||
3. 避免因并发导致的重复插入。
|
||||
|
||||
## 方案
|
||||
|
||||
### 1) 以状态机作为幂等门闸
|
||||
|
||||
将订单支付状态从 `pending` 变更为 `paid` 时使用条件更新:
|
||||
|
||||
- `UPDATE tb_order SET payment_status=paid,... WHERE id=? AND payment_status=pending`
|
||||
- 若 `RowsAffected == 0`:
|
||||
- 视为订单已被处理(可能已支付/已取消/已退款)
|
||||
- 对“已支付”场景直接返回成功(幂等成功)
|
||||
- 对“非待支付且非已支付”场景返回对应业务错误(例如已取消不允许支付)
|
||||
|
||||
这样可以确保并发下只有一个请求能“拿到激活资格”。
|
||||
|
||||
### 2) 激活逻辑只在首次成功支付后执行
|
||||
|
||||
`activatePackage` 只在上述条件更新成功后执行;并确保激活过程内的数据读取使用同一个事务 `tx`(避免出现读取不一致或部分写入)。
|
||||
|
||||
### 3) 防御性约束(可选但推荐)
|
||||
|
||||
为 `tb_package_usage` 增加唯一约束(示例):
|
||||
- 同一订单下,同一 `package_id` 只能有一条 usage
|
||||
- 以 `order_id + package_id` 为主(按当前业务:一个订单对应一个资源,且一次购买不应重复同套餐)
|
||||
|
||||
如果未来允许同订单同套餐多份购买,则需要同时引入 `quantity` 或 usage 的明细拆分策略,再调整唯一约束。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 重复调用钱包支付/支付回调接口,不会重复生成 `tb_package_usage` 记录。
|
||||
- 幂等重复请求返回成功。
|
||||
- 新增测试通过。
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# 订单激活幂等性修复(同订单只激活一次)
|
||||
|
||||
## Why
|
||||
|
||||
业务规则确认:**同一个订单只能激活一次**,不允许重复生成套餐生效记录。
|
||||
|
||||
当前订单支付成功后会生成 `PackageUsage`(套餐使用记录)。在并发请求、回调重放、网络重试等场景下,如果缺少幂等控制,可能重复插入套餐使用记录,导致用户重复获得权益,属于高风险资金/权益漏洞。
|
||||
|
||||
## What Changes
|
||||
|
||||
- **支付状态原子转换**:将“待支付 -> 已支付”的状态变更做成原子操作(带条件更新),只有第一次成功转换才会触发套餐激活。
|
||||
- **激活过程幂等**:`activatePackage` 只在“首次支付成功”场景执行;重复请求返回“幂等成功”(你确认 A=1)。
|
||||
- **可选防御性约束**:为 `tb_package_usage` 增加必要的唯一约束或幂等检查,防止异常路径插入重复记录。
|
||||
- **补充测试**:覆盖并发/重复调用场景,验证不会重复激活。
|
||||
|
||||
## Impact
|
||||
|
||||
涉及模块(预期):
|
||||
- Service:`internal/service/order/service.go`
|
||||
- Store(可选):`internal/store/postgres/order_store.go` / `internal/store/postgres/order_item_store.go`
|
||||
- 迁移(可选):新增唯一索引
|
||||
- 测试:`internal/service/order/service_test.go` 或 `tests/integration/*`
|
||||
|
||||
22
openspec/changes/fix-order-activation-idempotency/tasks.md
Normal file
22
openspec/changes/fix-order-activation-idempotency/tasks.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# 订单激活幂等性修复 - 实现任务
|
||||
|
||||
## 1. 状态原子转换
|
||||
|
||||
- [ ] 1.1 在 `internal/service/order/service.go` 中将支付成功状态更新改为条件更新(仅 `pending -> paid` 成功时继续)
|
||||
- [ ] 1.2 重复请求处理:当订单已支付时返回成功(幂等成功);当订单为已取消/已退款等非待支付状态时返回业务错误
|
||||
|
||||
## 2. 激活幂等与事务一致性
|
||||
|
||||
- [ ] 2.1 调整 `activatePackage`:只在首次支付成功后执行
|
||||
- [ ] 2.2 确保 `activatePackage` 内部读取订单明细/套餐信息使用事务 `tx`(避免使用非事务 DB 导致不一致)
|
||||
|
||||
## 3. 防御性约束(可选)
|
||||
|
||||
- [ ] 3.1 评估并新增 `tb_package_usage` 的唯一索引(例如 `order_id + package_id`),并提供 down.sql
|
||||
- [ ] 3.2 对应调整代码:若插入触发唯一冲突,按幂等成功处理或提前查询避免冲突
|
||||
|
||||
## 4. 测试与验证
|
||||
|
||||
- [ ] 4.1 新增单元/集成测试:重复支付/重复回调不会重复插入 usage
|
||||
- [ ] 4.2 运行 `go test ./...` 确保通过
|
||||
|
||||
Reference in New Issue
Block a user