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,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-29
|
||||
@@ -0,0 +1,99 @@
|
||||
# 设计:RoleHandler 请求验证
|
||||
|
||||
## 上下文
|
||||
|
||||
项目中已有标准的请求验证模式:
|
||||
- 使用 `github.com/go-playground/validator/v10` 库
|
||||
- 在 bootstrap 层创建全局 validator 实例
|
||||
- Handler 构造函数接收 validator
|
||||
- 请求解析后立即调用 `validator.Struct()` 验证
|
||||
|
||||
AuthHandler 已正确实现此模式(参考 `internal/handler/admin/auth.go:34`),RoleHandler 需要遵循相同模式。
|
||||
|
||||
## 目标 / 非目标
|
||||
|
||||
**目标:**
|
||||
- RoleHandler 遵循项目验证标准模式
|
||||
- 所有请求在到达 Service 层前完成验证
|
||||
- 取消被跳过的集成测试
|
||||
|
||||
**非目标:**
|
||||
- 不修改 DTO 的 validate 标签(已正确定义)
|
||||
- 不改变错误响应格式(使用现有 CodeInvalidParam)
|
||||
- 不引入新的验证库或模式
|
||||
|
||||
## 决策
|
||||
|
||||
### 决策 1:遵循 AuthHandler 模式
|
||||
|
||||
**方法:** 完全复制 AuthHandler 的验证模式到 RoleHandler
|
||||
|
||||
**理由:**
|
||||
- 保持代码库一致性
|
||||
- AuthHandler 模式已验证有效
|
||||
- 无需重新设计验证流程
|
||||
|
||||
**实现细节:**
|
||||
```go
|
||||
// 1. RoleHandler 结构体添加 validator 字段
|
||||
type RoleHandler struct {
|
||||
service *roleService.Service
|
||||
validator *validator.Validate // 新增
|
||||
}
|
||||
|
||||
// 2. 构造函数接收 validator
|
||||
func NewRoleHandler(service *roleService.Service, validator *validator.Validate) *RoleHandler {
|
||||
return &RoleHandler{
|
||||
service: service,
|
||||
validator: validator,
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Create 方法中验证
|
||||
func (h *RoleHandler) Create(c *fiber.Ctx) error {
|
||||
var req dto.CreateRoleRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||||
}
|
||||
|
||||
// 新增验证逻辑
|
||||
if err := h.validator.Struct(&req); err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "参数验证失败: "+err.Error())
|
||||
}
|
||||
|
||||
// ... 现有逻辑
|
||||
}
|
||||
```
|
||||
|
||||
### 决策 2:验证所有接受 body 的方法
|
||||
|
||||
**需要验证的方法:**
|
||||
- `Create()` - CreateRoleRequest
|
||||
- `Update()` - UpdateRoleRequest
|
||||
- `AssignPermissions()` - AssignPermissionsRequest
|
||||
- `UpdateStatus()` - UpdateRoleStatusRequest
|
||||
|
||||
**不需要验证的方法:**
|
||||
- `Get()` - 只有路径参数,已有 ParseUint 检查
|
||||
- `List()` - Query 参数,已有 QueryParser
|
||||
- `GetPermissions()` - 只有路径参数
|
||||
- `RemovePermission()` - 只有路径参数
|
||||
- `Delete()` - 只有路径参数
|
||||
|
||||
### 决策 3:错误消息格式
|
||||
|
||||
**使用现有格式:**
|
||||
```go
|
||||
errors.New(errors.CodeInvalidParam, "参数验证失败: "+err.Error())
|
||||
```
|
||||
|
||||
**理由:**
|
||||
- 与 AuthHandler 保持一致
|
||||
- validator 库的错误消息已足够清晰
|
||||
- 前端可以解析错误码和消息
|
||||
|
||||
## 测试策略
|
||||
|
||||
- 取消 `tests/integration/role_test.go:51` 的 TODO 跳过
|
||||
- 运行现有测试验证"缺少必填字段返回错误"场景
|
||||
- 无需添加新测试(现有被跳过的测试已覆盖验证逻辑)
|
||||
@@ -0,0 +1,27 @@
|
||||
# 提案:为 RoleHandler 添加请求验证
|
||||
|
||||
## 为什么
|
||||
|
||||
当前 RoleHandler 缺少请求参数验证,导致无效的请求可以通过 Handler 层传递到 Service 层。这违反了项目的"Handler 层负责参数验证"原则,并且导致集成测试被迫跳过(tests/integration/role_test.go:51,282)。
|
||||
|
||||
其他 Handler(如 AuthHandler)已经正确实现了验证,RoleHandler 需要遵循相同模式。
|
||||
|
||||
## 变更内容
|
||||
|
||||
- RoleHandler 将接收 validator 实例并验证所有请求参数
|
||||
- Create 和 Update 方法将调用 validator.Struct() 验证 DTO
|
||||
- 取消 role_test.go 中被跳过的验证测试
|
||||
|
||||
## 能力
|
||||
|
||||
### 新增能力
|
||||
- `role-request-validation`: RoleHandler 的所有请求(Create、Update、AssignPermissions、UpdateStatus)都将验证必填字段和格式
|
||||
|
||||
### 修改能力
|
||||
无(现有功能无变化,只是增强了输入验证)
|
||||
|
||||
## 影响范围
|
||||
|
||||
- `internal/handler/admin/role.go`: 添加 validator 字段,调用验证方法
|
||||
- `internal/bootstrap/handlers.go`: 传递 validator 给 RoleHandler
|
||||
- `tests/integration/role_test.go`: 取消被跳过的测试
|
||||
@@ -0,0 +1,67 @@
|
||||
# 规格:角色请求验证
|
||||
|
||||
## 新增需求
|
||||
|
||||
### 需求:Create 方法验证必填字段
|
||||
|
||||
RoleHandler.Create 方法必须验证 CreateRoleRequest 的所有必填字段。
|
||||
|
||||
#### 场景:缺少 role_name 返回验证错误
|
||||
|
||||
- **WHEN** 客户端发送 POST /api/admin/roles 请求,body 缺少 role_name 字段
|
||||
- **THEN** 返回 HTTP 400
|
||||
- **AND** 响应包含错误码(CodeInvalidParam)
|
||||
- **AND** 错误消息提示 "参数验证失败"
|
||||
|
||||
#### 场景:缺少 role_type 返回验证错误
|
||||
|
||||
- **WHEN** 客户端发送 POST /api/admin/roles 请求,body 缺少 role_type 字段
|
||||
- **THEN** 返回 HTTP 400
|
||||
- **AND** 响应包含错误码(CodeInvalidParam)
|
||||
|
||||
#### 场景:role_name 过长返回验证错误
|
||||
|
||||
- **WHEN** 客户端发送 POST /api/admin/roles 请求,role_name 超过 50 个字符
|
||||
- **THEN** 返回 HTTP 400
|
||||
- **AND** 响应包含错误码(CodeInvalidParam)
|
||||
|
||||
### 需求:Update 方法验证字段格式
|
||||
|
||||
RoleHandler.Update 方法必须验证 UpdateRoleRequest 的字段格式。
|
||||
|
||||
#### 场景:role_name 过长返回验证错误
|
||||
|
||||
- **WHEN** 客户端发送 PUT /api/admin/roles/:id 请求,role_name 超过 50 个字符
|
||||
- **THEN** 返回 HTTP 400
|
||||
- **AND** 响应包含错误码(CodeInvalidParam)
|
||||
|
||||
#### 场景:status 值非法返回验证错误
|
||||
|
||||
- **WHEN** 客户端发送 PUT /api/admin/roles/:id 请求,status 值不是 0 或 1
|
||||
- **THEN** 返回 HTTP 400
|
||||
- **AND** 响应包含错误码(CodeInvalidParam)
|
||||
|
||||
### 需求:AssignPermissions 方法验证权限ID列表
|
||||
|
||||
RoleHandler.AssignPermissions 方法必须验证权限ID列表不为空。
|
||||
|
||||
#### 场景:perm_ids 为空数组返回验证错误
|
||||
|
||||
- **WHEN** 客户端发送 POST /api/admin/roles/:id/permissions 请求,perm_ids 为空数组 []
|
||||
- **THEN** 返回 HTTP 400
|
||||
- **AND** 响应包含错误码(CodeInvalidParam)
|
||||
|
||||
### 需求:UpdateStatus 方法验证状态值
|
||||
|
||||
RoleHandler.UpdateStatus 方法必须验证状态值在有效范围内。
|
||||
|
||||
#### 场景:status 值非法返回验证错误
|
||||
|
||||
- **WHEN** 客户端发送 PUT /api/admin/roles/:id/status 请求,status 值不是 0 或 1
|
||||
- **THEN** 返回 HTTP 400
|
||||
- **AND** 响应包含错误码(CodeInvalidParam)
|
||||
|
||||
## 测试要求
|
||||
|
||||
- 取消 tests/integration/role_test.go 中的 TODO 跳过(第 51 行)
|
||||
- 验证测试能够通过,证明验证逻辑正常工作
|
||||
@@ -0,0 +1,30 @@
|
||||
# 实现任务
|
||||
|
||||
## 1. 修改 RoleHandler 结构
|
||||
|
||||
- [x] 1.1 在 RoleHandler 结构体中添加 `validator *validator.Validate` 字段
|
||||
- [x] 1.2 修改 NewRoleHandler 构造函数,接收 validator 参数
|
||||
- [x] 1.3 导入 `github.com/go-playground/validator/v10` 包
|
||||
|
||||
## 2. 添加验证逻辑
|
||||
|
||||
- [x] 2.1 Create 方法:BodyParser 后调用 validator.Struct(&req)
|
||||
- [x] 2.2 Update 方法:BodyParser 后调用 validator.Struct(&req)
|
||||
- [x] 2.3 AssignPermissions 方法:BodyParser 后调用 validator.Struct(&req)
|
||||
- [x] 2.4 UpdateStatus 方法:BodyParser 后调用 validator.Struct(&req)
|
||||
|
||||
## 3. 更新 Bootstrap
|
||||
|
||||
- [x] 3.1 修改 internal/bootstrap/handlers.go 中的 initHandlers 函数
|
||||
- [x] 3.2 传递 validate 参数给 NewRoleHandler:`admin.NewRoleHandler(svc.Role, validate)`
|
||||
|
||||
## 4. 取消测试跳过
|
||||
|
||||
- [x] 4.1 删除 tests/integration/role_test.go:51-62 的 TODO 跳过代码
|
||||
- [x] 4.2 取消注释被跳过的测试代码
|
||||
|
||||
## 5. 验证
|
||||
|
||||
- [x] 5.1 运行 `go test -v ./tests/integration/role_test.go` 确保测试通过
|
||||
- [x] 5.2 运行 LSP diagnostics 检查 internal/handler/admin/role.go
|
||||
- [x] 5.3 确认没有编译错误
|
||||
Reference in New Issue
Block a user