Browse Source

feat: 静态代码审计,修复逻辑bug和安全漏洞

BaiLuoYan 4 weeks ago
parent
commit
228ee889a9
71 changed files with 201 additions and 88 deletions
  1. 67 46
      README.md
  2. 1 1
      internal/handler/auth/changePasswordHandler.go
  3. 1 1
      internal/handler/auth/logoutHandler.go
  4. 1 1
      internal/handler/auth/userInfoHandler.go
  5. 1 1
      internal/handler/dept/createDeptHandler.go
  6. 1 1
      internal/handler/dept/deleteDeptHandler.go
  7. 1 1
      internal/handler/dept/deptTreeHandler.go
  8. 1 1
      internal/handler/dept/updateDeptHandler.go
  9. 1 1
      internal/handler/member/addMemberHandler.go
  10. 1 1
      internal/handler/member/memberListHandler.go
  11. 1 1
      internal/handler/member/removeMemberHandler.go
  12. 1 1
      internal/handler/member/updateMemberHandler.go
  13. 1 1
      internal/handler/perm/permListHandler.go
  14. 1 1
      internal/handler/product/createProductHandler.go
  15. 1 1
      internal/handler/product/productDetailHandler.go
  16. 1 1
      internal/handler/product/productListHandler.go
  17. 1 1
      internal/handler/product/updateProductHandler.go
  18. 1 1
      internal/handler/pub/adminLoginHandler.go
  19. 1 1
      internal/handler/pub/loginHandler.go
  20. 1 1
      internal/handler/pub/refreshTokenHandler.go
  21. 1 1
      internal/handler/pub/syncPermsHandler.go
  22. 1 1
      internal/handler/role/bindRolePermsHandler.go
  23. 1 1
      internal/handler/role/createRoleHandler.go
  24. 1 1
      internal/handler/role/deleteRoleHandler.go
  25. 1 1
      internal/handler/role/roleDetailHandler.go
  26. 1 1
      internal/handler/role/roleListHandler.go
  27. 1 1
      internal/handler/role/updateRoleHandler.go
  28. 1 1
      internal/handler/user/bindRolesHandler.go
  29. 1 1
      internal/handler/user/createUserHandler.go
  30. 1 1
      internal/handler/user/setUserPermsHandler.go
  31. 1 1
      internal/handler/user/updateUserHandler.go
  32. 1 1
      internal/handler/user/updateUserStatusHandler.go
  33. 1 1
      internal/handler/user/userDetailHandler.go
  34. 1 1
      internal/handler/user/userListHandler.go
  35. 1 0
      internal/logic/auth/changePasswordLogic.go
  36. 1 0
      internal/logic/auth/logoutLogic.go
  37. 1 0
      internal/logic/auth/userInfoLogic.go
  38. 1 0
      internal/logic/dept/createDeptLogic.go
  39. 1 0
      internal/logic/dept/deleteDeptLogic.go
  40. 1 0
      internal/logic/dept/deptTreeLogic.go
  41. 1 0
      internal/logic/dept/updateDeptLogic.go
  42. 1 0
      internal/logic/member/addMemberLogic.go
  43. 1 0
      internal/logic/member/memberListLogic.go
  44. 1 0
      internal/logic/member/removeMemberLogic.go
  45. 1 0
      internal/logic/member/updateMemberLogic.go
  46. 1 0
      internal/logic/perm/permListLogic.go
  47. 1 0
      internal/logic/product/createProductLogic.go
  48. 1 0
      internal/logic/product/productDetailLogic.go
  49. 1 0
      internal/logic/product/productListLogic.go
  50. 1 0
      internal/logic/product/updateProductLogic.go
  51. 1 0
      internal/logic/pub/adminLoginLogic.go
  52. 1 0
      internal/logic/pub/loginLogic.go
  53. 1 0
      internal/logic/pub/refreshTokenLogic.go
  54. 1 0
      internal/logic/pub/syncPermsLogic.go
  55. 1 0
      internal/logic/role/bindRolePermsLogic.go
  56. 1 0
      internal/logic/role/createRoleLogic.go
  57. 1 0
      internal/logic/role/deleteRoleLogic.go
  58. 1 0
      internal/logic/role/roleDetailLogic.go
  59. 1 0
      internal/logic/role/roleListLogic.go
  60. 1 0
      internal/logic/role/updateRoleLogic.go
  61. 1 0
      internal/logic/user/bindRolesLogic.go
  62. 1 0
      internal/logic/user/createUserLogic.go
  63. 1 0
      internal/logic/user/setUserPermsLogic.go
  64. 1 0
      internal/logic/user/updateUserLogic.go
  65. 1 0
      internal/logic/user/updateUserStatusLogic.go
  66. 1 0
      internal/logic/user/userDetailLogic.go
  67. 1 0
      internal/logic/user/userListLogic.go
  68. 6 0
      internal/server/permserver.go
  69. 6 0
      pb/perm.proto
  70. 49 2
      perm.api
  71. 7 7
      test-design.md

+ 67 - 46
README.md

@@ -12,6 +12,10 @@
 - **自动权限同步** — 产品启动时通过 API 自动上报权限列表,系统自动新增/更新/禁用
 - **JWT 本地验证** — 登录获取 JWT,产品后端可本地验证,无需每次请求回调权限系统
 - **登录端隔离** — 产品端(`/auth/login`)和管理后台(`/auth/adminLogin`)独立登录接口,超管仅能通过管理后台登录
+- **令牌轮转** — refreshToken 刷新时自动递增 tokenVersion,旧令牌即时失效,防止令牌被盗后的无限续期
+- **主动注销** — `/auth/logout` 接口递增 tokenVersion 使所有已签发令牌立即失效
+- **产品级熔断** — 禁用产品后所有在线成员的令牌即时失效,HTTP/gRPC 双通道同步拦截
+- **最后管理员保护** — 移除或降级产品最后一个 ADMIN 时自动拒绝,防止产品进入无管理状态
 
 ## 系统架构
 
@@ -156,7 +160,7 @@ erDiagram
                               └────────────────────────────────────┘
 ```
 
-**关键关系**:
+#### 关键关系
 
 1. **用户 → 产品**:通过 `sys_product_member` 建立,一个用户可以是多个产品的成员
 2. **用户 → 部门**:通过 `sys_user.deptId` 关联,一个用户只属于一个部门
@@ -178,10 +182,12 @@ erDiagram
 
 ```mermaid
 flowchart TD
-    START[获取用户权限] --> IS_SUPER{是超级管理员?}
+    START[获取用户权限] --> CHK_PROD{产品已启用?}
+    CHK_PROD -->|否| EMPTY_PROD[返回空权限]
+    CHK_PROD -->|是| IS_SUPER{是超级管理员?}
     IS_SUPER -->|是| ALL_PERMS[返回该产品全部权限码]
     IS_SUPER -->|否| FIND_MEMBER[查询 sys_product_member]
-    FIND_MEMBER --> HAS_MEMBER{是产品成员?}
+    FIND_MEMBER --> HAS_MEMBER{是活跃成员?}
     HAS_MEMBER -->|否| EMPTY[返回空权限]
     HAS_MEMBER -->|是| CHECK_TYPE{成员类型?}
     CHECK_TYPE -->|DEVELOPER / ADMIN| ALL_PERMS
@@ -247,7 +253,7 @@ POST /api/product/create  {"code": "oa", "name": "OA 系统"}
 POST /api/product/create  {"code": "mall", "name": "电商后台"}
 ```
 
-每个产品创建后会自动生成一个初始管理员账号(如 `admin_crm`),该账号是该产品的 `SUPER_ADMIN` 级别成员。
+每个产品创建后会自动生成一个初始管理员账号(如 `admin_crm`),该账号是该产品的 `ADMIN` 级别成员。
 
 ### 第三步:产品上报权限
 
@@ -372,16 +378,16 @@ flowchart TD
 flowchart LR
     REQ[HTTP 请求] --> L1["① JWT 中间件<br>解析 token / 验证签名"]
     L1 --> L2["② UserDetailsLoader<br>加载用户实时状态"]
-    L2 --> L3["③ 冻结检查<br>Status != 1 → 403"]
+    L2 --> L3["③ 多维状态检查<br>用户/产品/成员状态"]
     L3 --> L4["④ Logic 层<br>操作权限控制"]
     L4 --> BIZ[业务逻辑]
 ```
 
 | 层级 | 组件 | 职责 |
 | ------ | ------ | ------ |
-| 第一层 | JWT 中间件 | 解析 access token、验证签名、校验 `tokenType` |
-| 第二层 | UserDetailsLoader | 从 Redis 缓存或 DB 加载用户完整信息(含部门、角色、权限) |
-| 第三层 | 用户状态检查 | 冻结账号(`status ≠ 1`)直接返回 403 |
+| 第一层 | JWT 中间件 | 解析 access token、验证签名、校验 `tokenType`、校验 `tokenVersion` |
+| 第二层 | UserDetailsLoader | 从 Redis 缓存或 DB 加载用户完整信息(含部门、角色、权限、产品状态) |
+| 第三层 | 多维状态检查 | 用户冻结(`status ≠ 1`)→ 403;产品禁用(`productStatus ≠ 1`)→ 403;成员无效(`memberType` 为空)→ 403 |
 | 第四层 | access.go | 按接口类型检查超管/产品管理员/部门层级/权限级别 |
 
 ### 接口操作权限矩阵
@@ -396,27 +402,30 @@ flowchart LR
 | 更新部门 | 仅超级管理员 | — |
 | 删除部门 | 仅超级管理员 | 有子部门时拒绝 |
 | **角色管理** | | |
-| 创建角色 | 超管 或 产品管理员 |  |
-| 更新角色 | 超管 或 产品管理员 |  |
+| 创建角色 | 超管 或 产品管理员 | 产品必须启用 |
+| 更新角色 | 超管 或 产品管理员 | 非超管不可降低 permsLevel |
 | 删除角色 | 超管 或 产品管理员 | 级联删除关联数据 |
 | 绑定角色权限 | 超管 或 产品管理员 | — |
 | **用户管理** | | |
 | 创建用户 | 超管 或 产品管理员 | — |
 | 更新用户信息 | 仅本人 或 超管 | — |
 | 冻结/解冻用户 | 通过 `CheckManageAccess` | 不可冻结自己和超管 |
-| 绑定角色 | 通过 `CheckManageAccess` |  |
-| 设置权限覆盖 | 通过 `CheckManageAccess` |  |
+| 绑定角色 | 通过 `CheckManageAccess` | 目标用户的成员状态必须启用 |
+| 设置权限覆盖 | 通过 `CheckManageAccess` | 目标用户的成员状态必须启用;产品必须启用 |
 | **成员管理** | | |
-| 添加成员 | 通过 `CheckManageAccess` + `CheckMemberTypeAssignment` | 不可分配同级或更高类型 |
-| 更新成员 | 通过 `CheckManageAccess` + `CheckMemberTypeAssignment` |  |
-| 移除成员 | 通过 `CheckManageAccess` | 级联清理角色/权限绑定 |
+| 添加成员 | 通过 `CheckManageAccess` + `CheckMemberTypeAssignment` | 不可分配同级或更高类型;产品必须启用 |
+| 更新成员 | 通过 `CheckManageAccess` + `CheckMemberTypeAssignment` | 不可降级最后一个 ADMIN |
+| 移除成员 | 通过 `CheckManageAccess` | 不可移除最后一个 ADMIN;级联清理角色/权限绑定 |
 | **查询类接口** | | |
 | 产品/部门/角色/用户/成员列表与详情 | 已登录即可 | — |
 | 用户信息 (userInfo) | 已登录即可 | 返回当前登录用户自己的信息 |
+| **认证接口** | | |
+| 用户注销 (logout) | 已登录即可 | 递增 tokenVersion,所有已签发令牌即时失效 |
 | **公开接口** | | |
 | 产品端登录 (login) | 无需鉴权 | 超级管理员被拒绝,productCode 必传 |
-| 管理后台登录 (adminLogin) | 无需鉴权 | 需验证 managementKey |
-| 刷新令牌 / 同步权限 | 无需鉴权 | 同步权限通过 appKey/appSecret 认证 |
+| 管理后台登录 (adminLogin) | 无需鉴权 | 需验证 managementKey,限流在 managementKey 校验之后 |
+| 刷新令牌 | 无需鉴权 | 令牌轮转:旧令牌即时失效,返回全新令牌对;产品禁用时拒绝 |
+| 同步权限 | 无需鉴权 | 通过 appKey/appSecret 认证 |
 
 ### CheckManageAccess — 用户管理权限检查
 
@@ -444,7 +453,7 @@ flowchart TD
     CMP_PERM -->|相等或更大| DENY4[❌ 同级或更低]
 ```
 
-**检查维度说明**:
+#### 检查维度说明
 
 1. **超管豁免**:`SUPER_ADMIN` 不受任何限制
 2. **自我豁免**:操作自己的记录总是允许
@@ -457,18 +466,18 @@ flowchart TD
 
 `UserDetailsLoader` 是一个集中式的用户信息加载与缓存组件,为中间件、登录、用户信息查询等多个场景提供统一的数据来源。
 
-**加载的完整数据**:
+#### 加载的完整数据
 
 | 数据来源 | 加载的字段 |
 | ---------- | ----------- |
 | `sys_user` | userId, username, nickname, avatar, email, phone, remark, isSuperAdmin, mustChangePassword, status |
 | `sys_dept` | deptId, deptName, deptPath, deptType |
-| `sys_product` | productCode, productName |
+| `sys_product` | productCode, productName, productStatus |
 | `sys_product_member` | memberType |
 | `sys_role` (当前产品) | roles[], minPermsLevel |
 | 计算后的权限 | perms[] (权限 code 集合) |
 
-**缓存策略**:
+#### 缓存策略
 
 - **存储**:Redis JSON,key 格式 `{prefix}:ud:{userId}:{productCode}`
 - **TTL**:300 秒(5 分钟)自然过期
@@ -476,11 +485,12 @@ flowchart TD
 
 | 操作 | 失效方法 | 失效范围 |
 | ------ | ---------- | ---------- |
-| 更新用户信息 / 冻结解冻 / 修改密码 | `Clean(userId)` | 该用户所有产品缓存 |
+| 更新用户信息 / 冻结解冻 / 修改密码 / 注销 | `Clean(userId)` | 该用户所有产品缓存 |
 | 设置用户权限覆盖 / 添加成员 / 更新成员 | `Del(userId, productCode)` | 该用户在指定产品的缓存 |
 | 更新角色 / 删除角色 / 绑定角色权限 | `BatchDel(userIds, productCode)` | 受影响用户在指定产品的缓存 |
 | 更新产品 / 同步权限 | `CleanByProduct(productCode)` | 该产品下所有用户的缓存 |
 | 更新部门 | `Clean(uid)` × N | 该部门下所有用户的缓存 |
+| 刷新令牌 | `Clean(userId)` | 轮转时递增 tokenVersion 后清除缓存 |
 
 ---
 
@@ -604,7 +614,7 @@ POST /api/perm/sync
 }
 ```
 
-**Go 代码示例(放在 main 启动流程中):**
+#### Go 代码示例(放在 main 启动流程中)
 
 ```go
 var permsList = []map[string]string{
@@ -657,17 +667,19 @@ resp, err := client.Login(ctx, "crm", "zhangsan", "123456")
 
 ```go
 type Claims struct {
-    TokenType   string   `json:"tokenType"`
-    UserId      int64    `json:"userId"`
-    Username    string   `json:"username"`
-    ProductCode string   `json:"productCode"`
-    MemberType  string   `json:"memberType"`
-    Perms       []string `json:"perms"`
+    TokenType    string   `json:"tokenType"`
+    TokenVersion int64    `json:"tokenVersion"`
+    UserId       int64    `json:"userId"`
+    Username     string   `json:"username"`
+    ProductCode  string   `json:"productCode"`
+    MemberType   string   `json:"memberType"`
+    Perms        []string `json:"perms"`
     jwt.RegisteredClaims
 }
 ```
 
-> `tokenType` 字段区分 `"access"` 和 `"refresh"`,验证时应检查 `tokenType == "access"`。
+> - `tokenType` 字段区分 `"access"` 和 `"refresh"`,验证时应检查 `tokenType == "access"`
+> - `tokenVersion` 用于令牌吊销:用户注销或刷新令牌时版本递增,旧版本令牌即时失效
 
 #### 3. 业务接口中检查权限
 
@@ -692,7 +704,7 @@ Content-Type: application/json
 {"productCode": "crm"}
 ```
 
-> `refreshToken` 有效期默认 7 天,刷新时返回原始 refreshToken(不重新签发),过期后必须重新登录。这确保了 token 有固定的生命周期
+> `refreshToken` 有效期默认 7 天。系统采用令牌轮转策略:每次刷新都返回全新的 accessToken 和 refreshToken,旧令牌即时失效(通过递增 `tokenVersion` 实现)。过期后必须重新登录
 
 ### 接入检查清单
 
@@ -702,7 +714,8 @@ Content-Type: application/json
 - [ ] 登录接口正确调用权限系统并返回 token
 - [ ] JWT 鉴权中间件已加入受保护路由,并验证 `tokenType == "access"`
 - [ ] 业务接口中根据 `claims.Perms` 做了权限校验
-- [ ] 前端在 `accessToken` 过期时能自动调用 `refreshToken` 续期
+- [ ] 前端在 `accessToken` 过期时能自动调用 `refreshToken` 续期(注意:刷新后旧令牌失效,需立即替换)
+- [ ] 前端实现注销功能(调用 `/api/auth/logout`),确保令牌在服务端即时吊销
 
 ---
 
@@ -752,7 +765,7 @@ Content-Type: application/json
 | password | string | 是 | 密码 |
 | productCode | string | 是 | 产品编码 |
 
-**响应 data:**
+#### 响应 data
 
 | 字段 | 类型 | 说明 |
 | ------ | ------ | ------ |
@@ -782,7 +795,7 @@ Content-Type: application/json
 | Authorization | header | 是 | `Bearer {refreshToken}` |
 | productCode | string | 否 | 切换产品上下文时传入(Body) |
 
-**响应 data:** 与登录接口相同。注意返回的 `refreshToken` 是原始值(不重新签发),refresh token 有固定有效期,过期后需重新登录。
+**响应 data:** 与登录接口相同。采用令牌轮转策略:每次刷新都会递增 `tokenVersion`,返回全新的 accessToken 和 refreshToken,旧令牌即时失效。refresh token 有固定有效期,过期后需重新登录。
 
 #### POST /api/perm/sync — 同步产品权限
 
@@ -801,6 +814,12 @@ Content-Type: application/json
 
 ### 认证接口(需鉴权)
 
+#### POST /api/auth/logout — 用户注销
+
+无请求参数。递增当前用户的 `tokenVersion`,使所有已签发的 access/refresh 令牌立即失效,并清除用户缓存。
+
+**响应 data:** `null`
+
 #### POST /api/auth/userInfo — 获取当前用户信息
 
 无请求参数。**响应 data:** `UserInfo` 对象。
@@ -912,6 +931,8 @@ Content-Type: application/json
 
 #### POST /api/role/update — 更新角色
 
+非超级管理员不可降低角色的 `permsLevel`(即不可将数值改大)。
+
 | 字段 | 类型 | 必填 | 说明 |
 | ------ | ------ | ------ | ------ |
 | id | int64 | 是 | 角色 ID |
@@ -1044,7 +1065,7 @@ Content-Type: application/json
 
 #### POST /api/member/update — 更新成员
 
-需通过 `CheckManageAccess` + `CheckMemberTypeAssignment` 权限检查。
+需通过 `CheckManageAccess` + `CheckMemberTypeAssignment` 权限检查。降级产品最后一个 ADMIN 时会被拒绝。
 
 | 字段 | 类型 | 必填 | 说明 |
 | ------ | ------ | ------ | ------ |
@@ -1054,7 +1075,7 @@ Content-Type: application/json
 
 #### POST /api/member/remove — 移除成员
 
-需通过 `CheckManageAccess` 权限检查。级联清理该成员在该产品下的角色绑定和权限覆盖。
+需通过 `CheckManageAccess` 权限检查。不可移除产品最后一个 ADMIN。级联清理该成员在该产品下的角色绑定和权限覆盖。
 
 | 字段 | 类型 | 必填 | 说明 |
 | ------ | ------ | ------ | ------ |
@@ -1078,10 +1099,10 @@ gRPC 服务定义见 `pb/perm.proto`,默认监听 `:10002`。
 
 | 方法 | 说明 | 使用场景 |
 | ------ | ------ | ---------- |
-| `SyncPermissions` | 同步产品权限列表 | 产品启动时调用 |
+| `SyncPermissions` | 同步产品权限列表 | 产品启动时调用,通过 appKey/appSecret 认证 |
 | `Login` | 产品端登录 | 产品后端代理用户登录(productCode 必传,超管被拒绝) |
-| `RefreshToken` | 刷新令牌 | accessToken 过期续期 |
-| `VerifyToken` | 验证令牌 | 产品后端验证用户 token(可选,推荐本地 JWT 验证) |
+| `RefreshToken` | 刷新令牌(轮转) | accessToken 过期续期,旧令牌即时失效;产品禁用时拒绝 |
+| `VerifyToken` | 验证令牌 | 产品后端验证用户 token(可选,推荐本地 JWT 验证);产品禁用时拒绝 |
 | `GetUserPerms` | 获取用户权限 | 实时查询用户最新权限 |
 
 所有 gRPC 错误使用标准 `status.Error(codes.Xxx, msg)` 格式。
@@ -1131,14 +1152,14 @@ server/
     ├── loaders/
     │   └── userDetailsLoader.go      # 用户详情加载器(Redis 缓存 + DB 回源)
     ├── middleware/
-    │   └── jwtauthMiddleware.go      # JWT 鉴权中间件(token 验证 + 状态检查 + UserDetails 注入)
+    │   └── jwtauthMiddleware.go      # JWT 鉴权中间件(token/tokenVersion 验证 + 用户/产品/成员状态检查 + UserDetails 注入)
     ├── svc/serviceContext.go         # 依赖注入容器
     ├── server/permserver.go          # gRPC 服务实现
     ├── types/types.go                # 请求/响应结构体(goctl 生成)
     ├── handler/                      # HTTP handler(按模块分组,goctl 生成)
     │   ├── routes.go
-    │   ├── pub/                      # 公开接口
-    │   ├── auth/                     # 认证接口
+    │   ├── pub/                      # 公开接口(登录/刷新令牌/同步权限)
+    │   ├── auth/                     # 认证接口(用户信息/修改密码/注销)
     │   ├── product/                  # 产品管理
     │   ├── dept/                     # 部门管理
     │   ├── perm/                     # 权限管理
@@ -1195,13 +1216,13 @@ server/
 
 当服务部署在 Nginx 等反向代理后面时,需要开启 `BehindProxy` 配置以正确获取客户端真实 IP(用于登录限流等安全策略):
 
-**1. 配置文件设置**
+#### 1. 配置文件设置
 
 ```yaml
 BehindProxy: true
 ```
 
-**2. Nginx 配置要求**
+#### 2. Nginx 配置要求
 
 必须在 Nginx 中正确设置 `X-Real-IP` 并清除客户端可伪造的 `X-Forwarded-For`:
 
@@ -1216,7 +1237,7 @@ server {
 }
 ```
 
-**安全说明**:
+#### 安全说明
 
 - `BehindProxy: false`(默认)— 仅使用 TCP 连接的 `RemoteAddr` 作为客户端 IP,适合服务直接暴露或在无法信任代理头的场景
 - `BehindProxy: true` — 信任 Nginx 设置的 `X-Real-IP` 头获取真实客户端 IP,**必须**确保 Nginx 正确配置且外部无法绕过 Nginx 直连后端
@@ -1276,7 +1297,7 @@ server {
 ./run-test.sh -h
 ```
 
-**环境变量**:
+#### 环境变量
 
 | 变量 | 默认值 | 说明 |
 | ------ | -------- | ------ |

+ 1 - 1
internal/handler/auth/changePasswordHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// ChangePasswordHandler 修改密码接口。验证原密码后设置新密码,令牌即时失效。
 func ChangePasswordHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.ChangePasswordReq

+ 1 - 1
internal/handler/auth/logoutHandler.go

@@ -10,7 +10,7 @@ import (
 	"perms-system-server/internal/logic/auth"
 	"perms-system-server/internal/svc"
 )
-
+// LogoutHandler 用户注销接口。使所有已签发令牌立即失效并清除缓存。
 func LogoutHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		l := auth.NewLogoutLogic(r.Context(), svcCtx)

+ 1 - 1
internal/handler/auth/userInfoHandler.go

@@ -10,7 +10,7 @@ import (
 	"perms-system-server/internal/logic/auth"
 	"perms-system-server/internal/svc"
 )
-
+// UserInfoHandler 获取当前登录用户信息接口。返回用户个人信息、成员类型和权限列表。
 func UserInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		l := auth.NewUserInfoLogic(r.Context(), svcCtx)

+ 1 - 1
internal/handler/dept/createDeptHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// CreateDeptHandler 创建部门接口。在指定父部门下新建子部门。
 func CreateDeptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.CreateDeptReq

+ 1 - 1
internal/handler/dept/deleteDeptHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// DeleteDeptHandler 删除部门接口。检查无子部门和关联用户后删除。
 func DeleteDeptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.DeleteDeptReq

+ 1 - 1
internal/handler/dept/deptTreeHandler.go

@@ -10,7 +10,7 @@ import (
 	"perms-system-server/internal/logic/dept"
 	"perms-system-server/internal/svc"
 )
-
+// DeptTreeHandler 部门树接口。返回完整的组织架构树形结构。
 func DeptTreeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		l := dept.NewDeptTreeLogic(r.Context(), svcCtx)

+ 1 - 1
internal/handler/dept/updateDeptHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// UpdateDeptHandler 更新部门接口。修改名称、排序、类型、备注或启用/禁用状态。
 func UpdateDeptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.UpdateDeptReq

+ 1 - 1
internal/handler/member/addMemberHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// AddMemberHandler 添加产品成员接口。将已有用户加入指定产品并设置成员类型。
 func AddMemberHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.AddMemberReq

+ 1 - 1
internal/handler/member/memberListHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// MemberListHandler 成员列表接口。按产品分页查询成员信息。
 func MemberListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.MemberListReq

+ 1 - 1
internal/handler/member/removeMemberHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// RemoveMemberHandler 移除产品成员接口。同时清理角色和权限绑定。
 func RemoveMemberHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.RemoveMemberReq

+ 1 - 1
internal/handler/member/updateMemberHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// UpdateMemberHandler 更新产品成员接口。修改成员类型或启用/禁用状态。
 func UpdateMemberHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.UpdateMemberReq

+ 1 - 1
internal/handler/perm/permListHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// PermListHandler 权限列表接口。按产品分页查询已注册的权限定义。
 func PermListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.PermListReq

+ 1 - 1
internal/handler/product/createProductHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// CreateProductHandler 创建产品接口。自动生成 appKey/appSecret 和产品管理员账号。
 func CreateProductHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.CreateProductReq

+ 1 - 1
internal/handler/product/productDetailHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// ProductDetailHandler 产品详情接口。根据产品 ID 查询完整信息。
 func ProductDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.ProductDetailReq

+ 1 - 1
internal/handler/product/productListHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// ProductListHandler 产品列表接口。分页查询系统中所有产品的基本信息。
 func ProductListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.ProductListReq

+ 1 - 1
internal/handler/product/updateProductHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// UpdateProductHandler 更新产品信息接口。可修改名称、备注和启用/禁用状态。
 func UpdateProductHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.UpdateProductReq

+ 1 - 1
internal/handler/pub/adminLoginHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// AdminLoginHandler 管理后台登录接口。仅限超级管理员通过 managementKey + 用户名密码登录。
 func AdminLoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.AdminLoginReq

+ 1 - 1
internal/handler/pub/loginHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// LoginHandler 产品端登录接口。产品成员通过用户名密码 + productCode 登录指定产品。
 func LoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.LoginReq

+ 1 - 1
internal/handler/pub/refreshTokenHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// RefreshTokenHandler 刷新令牌接口。使用 refreshToken 换取新的令牌对,旧令牌即时失效。
 func RefreshTokenHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.RefreshTokenReq

+ 1 - 1
internal/handler/pub/syncPermsHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// SyncPermsHandler 同步权限声明接口。产品服务端通过 appKey/appSecret 认证后批量同步权限定义。
 func SyncPermsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.SyncPermsReq

+ 1 - 1
internal/handler/role/bindRolePermsHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// BindRolePermsHandler 绑定角色权限接口。对指定角色做权限全量覆盖。
 func BindRolePermsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.BindPermsReq

+ 1 - 1
internal/handler/role/createRoleHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// CreateRoleHandler 创建角色接口。在指定产品下新建角色并设置权限级别。
 func CreateRoleHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.CreateRoleReq

+ 1 - 1
internal/handler/role/deleteRoleHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// DeleteRoleHandler 删除角色接口。同时清理角色-权限和用户-角色绑定后删除。
 func DeleteRoleHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.DeleteRoleReq

+ 1 - 1
internal/handler/role/roleDetailHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// RoleDetailHandler 角色详情接口。查询角色完整信息及已绑定的权限 ID 列表。
 func RoleDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.RoleDetailReq

+ 1 - 1
internal/handler/role/roleListHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// RoleListHandler 角色列表接口。按产品分页查询角色信息。
 func RoleListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.RoleListReq

+ 1 - 1
internal/handler/role/updateRoleHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// UpdateRoleHandler 更新角色接口。修改名称、备注、权限级别和启用/禁用状态。
 func UpdateRoleHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.UpdateRoleReq

+ 1 - 1
internal/handler/user/bindRolesHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// BindRolesHandler 绑定用户角色接口。对指定用户做角色全量覆盖。
 func BindRolesHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.BindRolesReq

+ 1 - 1
internal/handler/user/createUserHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// CreateUserHandler 创建用户接口。新建系统用户账号,可指定部门归属。
 func CreateUserHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.CreateUserReq

+ 1 - 1
internal/handler/user/setUserPermsHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// SetUserPermsHandler 设置用户个性化权限接口。支持 ALLOW 和 DENY 两种效果。
 func SetUserPermsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.SetPermsReq

+ 1 - 1
internal/handler/user/updateUserHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// UpdateUserHandler 更新用户信息接口。修改昵称、邮箱、手机、备注、部门等。
 func UpdateUserHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.UpdateUserReq

+ 1 - 1
internal/handler/user/updateUserStatusHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// UpdateUserStatusHandler 冻结/解冻用户接口。修改启用状态并使令牌失效。
 func UpdateUserStatusHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.UpdateUserStatusReq

+ 1 - 1
internal/handler/user/userDetailHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// UserDetailHandler 用户详情接口。查询指定用户基本信息和角色绑定。
 func UserDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.UserDetailReq

+ 1 - 1
internal/handler/user/userListHandler.go

@@ -12,7 +12,7 @@ import (
 	"perms-system-server/internal/svc"
 	"perms-system-server/internal/types"
 )
-
+// UserListHandler 用户列表接口。分页查询用户信息。
 func UserListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var req types.UserListReq

+ 1 - 0
internal/logic/auth/changePasswordLogic.go

@@ -28,6 +28,7 @@ func NewChangePasswordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Ch
 	}
 }
 
+// ChangePassword 修改密码。已登录用户验证原密码后设置新密码,同时递增 tokenVersion 使所有已签发令牌失效,强制重新登录。
 func (l *ChangePasswordLogic) ChangePassword(req *types.ChangePasswordReq) error {
 	if msg := util.ValidatePassword(req.NewPassword); msg != "" {
 		return response.ErrBadRequest(msg)

+ 1 - 0
internal/logic/auth/logoutLogic.go

@@ -27,6 +27,7 @@ func NewLogoutLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LogoutLogi
 	}
 }
 
+// Logout 用户注销。递增当前用户的 tokenVersion 使所有已签发的 access/refresh 令牌立即失效,并清除用户缓存。
 func (l *LogoutLogic) Logout() error {
 	userId := middleware.GetUserId(l.ctx)
 	if userId == 0 {

+ 1 - 0
internal/logic/auth/userInfoLogic.go

@@ -25,6 +25,7 @@ func NewUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserInfo
 	}
 }
 
+// UserInfo 获取当前登录用户信息。返回当前 JWT 令牌对应用户的完整个人信息、成员类型和权限列表,用于前端初始化用户状态。
 func (l *UserInfoLogic) UserInfo() (resp *types.UserInfo, err error) {
 	ud := middleware.GetUserDetails(l.ctx)
 	if ud == nil {

+ 1 - 0
internal/logic/dept/createDeptLogic.go

@@ -30,6 +30,7 @@ func NewCreateDeptLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Create
 	}
 }
 
+// CreateDept 创建部门。在指定父部门下新建子部门,自动继承路径层级。仅超管可调用。
 func (l *CreateDeptLogic) CreateDept(req *types.CreateDeptReq) (resp *types.IdResp, err error) {
 	if err := authHelper.RequireSuperAdmin(l.ctx); err != nil {
 		return nil, err

+ 1 - 0
internal/logic/dept/deleteDeptLogic.go

@@ -27,6 +27,7 @@ func NewDeleteDeptLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delete
 	}
 }
 
+// DeleteDept 删除部门。在事务内加行锁后检查是否存在子部门或关联用户,均无则删除。仅超管可调用。
 func (l *DeleteDeptLogic) DeleteDept(req *types.DeleteDeptReq) error {
 	if err := authHelper.RequireSuperAdmin(l.ctx); err != nil {
 		return err

+ 1 - 0
internal/logic/dept/deptTreeLogic.go

@@ -23,6 +23,7 @@ func NewDeptTreeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeptTree
 	}
 }
 
+// DeptTree 部门树。一次性返回完整的组织架构树形结构,用于前端部门选择器和组织架构展示。
 func (l *DeptTreeLogic) DeptTree() (resp []*types.DeptItem, err error) {
 	list, err := l.svcCtx.SysDeptModel.FindAll(l.ctx)
 	if err != nil {

+ 1 - 0
internal/logic/dept/updateDeptLogic.go

@@ -29,6 +29,7 @@ func NewUpdateDeptLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Update
 	}
 }
 
+// UpdateDept 更新部门。修改部门名称、排序、类型、备注或启用/禁用状态。使用乐观锁防止并发冲突,变更部门类型或状态时自动清理受影响用户的权限缓存。
 func (l *UpdateDeptLogic) UpdateDept(req *types.UpdateDeptReq) error {
 	if err := authHelper.RequireSuperAdmin(l.ctx); err != nil {
 		return err

+ 1 - 0
internal/logic/member/addMemberLogic.go

@@ -29,6 +29,7 @@ func NewAddMemberLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddMemb
 	}
 }
 
+// AddMember 添加产品成员。将已有用户加入指定产品并设置成员类型(ADMIN/DEVELOPER/MEMBER),需产品 ADMIN 或超管权限。产品必须已启用。
 func (l *AddMemberLogic) AddMember(req *types.AddMemberReq) (resp *types.IdResp, err error) {
 	product, err := l.svcCtx.SysProductModel.FindOneByCode(l.ctx, req.ProductCode)
 	if err != nil {

+ 1 - 0
internal/logic/member/memberListLogic.go

@@ -26,6 +26,7 @@ func NewMemberListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Member
 	}
 }
 
+// MemberList 成员列表。按产品分页查询成员信息,包含用户名、昵称和成员类型,用于产品成员管理页面。
 func (l *MemberListLogic) MemberList(req *types.MemberListReq) (resp *types.PageResp, err error) {
 	page, pageSize := util.NormalizePage(req.Page, req.PageSize)
 

+ 1 - 0
internal/logic/member/removeMemberLogic.go

@@ -27,6 +27,7 @@ func NewRemoveMemberLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Remo
 	}
 }
 
+// RemoveMember 移除产品成员。在事务内同时清理该用户在产品下的角色和个性化权限绑定后移除成员记录。不能移除产品的最后一个 ADMIN。
 func (l *RemoveMemberLogic) RemoveMember(req *types.RemoveMemberReq) error {
 	member, err := l.svcCtx.SysProductMemberModel.FindOne(l.ctx, req.Id)
 	if err != nil {

+ 1 - 0
internal/logic/member/updateMemberLogic.go

@@ -27,6 +27,7 @@ func NewUpdateMemberLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Upda
 	}
 }
 
+// UpdateMember 更新产品成员。修改成员类型或启用/禁用状态。降级最后一个 ADMIN 时会被拒绝以保证产品始终有管理员。
 func (l *UpdateMemberLogic) UpdateMember(req *types.UpdateMemberReq) error {
 	member, err := l.svcCtx.SysProductMemberModel.FindOne(l.ctx, req.Id)
 	if err != nil {

+ 1 - 0
internal/logic/perm/permListLogic.go

@@ -26,6 +26,7 @@ func NewPermListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PermList
 	}
 }
 
+// PermList 权限列表。按产品分页查询已注册的权限定义(code/name/status),用于角色权限配置和用户权限分配的选择列表。
 func (l *PermListLogic) PermList(req *types.PermListReq) (resp *types.PageResp, err error) {
 	page, pageSize := util.NormalizePage(req.Page, req.PageSize)
 

+ 1 - 0
internal/logic/product/createProductLogic.go

@@ -39,6 +39,7 @@ func NewCreateProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Cre
 	}
 }
 
+// CreateProduct 创建产品。仅超管可调用,自动生成 appKey/appSecret 和产品专属管理员账号,用于接入新的业务产品。
 func (l *CreateProductLogic) CreateProduct(req *types.CreateProductReq) (resp *types.CreateProductResp, err error) {
 	if err := authHelper.RequireSuperAdmin(l.ctx); err != nil {
 		return nil, err

+ 1 - 0
internal/logic/product/productDetailLogic.go

@@ -25,6 +25,7 @@ func NewProductDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Pro
 	}
 }
 
+// ProductDetail 产品详情。根据产品 ID 查询产品的完整信息,超管可见 appKey。
 func (l *ProductDetailLogic) ProductDetail(req *types.ProductDetailReq) (resp *types.ProductItem, err error) {
 	product, err := l.svcCtx.SysProductModel.FindOne(l.ctx, req.Id)
 	if err != nil {

+ 1 - 0
internal/logic/product/productListLogic.go

@@ -25,6 +25,7 @@ func NewProductListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Produ
 	}
 }
 
+// ProductList 产品列表。分页查询系统中所有产品的基本信息,超管可见全部产品的 appKey。
 func (l *ProductListLogic) ProductList(req *types.ProductListReq) (resp *types.PageResp, err error) {
 	page, pageSize := util.NormalizePage(req.Page, req.PageSize)
 

+ 1 - 0
internal/logic/product/updateProductLogic.go

@@ -27,6 +27,7 @@ func NewUpdateProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Upd
 	}
 }
 
+// UpdateProduct 更新产品信息。仅超管可调用,可修改产品名称、备注和启用/禁用状态。禁用产品后其成员将无法访问。
 func (l *UpdateProductLogic) UpdateProduct(req *types.UpdateProductReq) error {
 	if err := authHelper.RequireSuperAdmin(l.ctx); err != nil {
 		return err

+ 1 - 0
internal/logic/pub/adminLoginLogic.go

@@ -32,6 +32,7 @@ func NewAdminLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminL
 	}
 }
 
+// AdminLogin 管理后台登录。仅限超级管理员通过 managementKey + 用户名密码登录管理后台,返回 JWT 令牌对。
 func (l *AdminLoginLogic) AdminLogin(req *types.AdminLoginReq) (resp *types.LoginResp, err error) {
 	if subtle.ConstantTimeCompare([]byte(req.ManagementKey), []byte(l.svcCtx.Config.Auth.ManagementKey)) != 1 {
 		return nil, response.ErrUnauthorized("managementKey无效")

+ 1 - 0
internal/logic/pub/loginLogic.go

@@ -25,6 +25,7 @@ func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic
 	}
 }
 
+// Login 产品端登录。产品成员通过用户名密码 + productCode 登录指定产品,返回 JWT 令牌对及用户权限信息。
 func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginResp, err error) {
 	result, err := ValidateProductLogin(l.ctx, l.svcCtx, req.Username, req.Password, req.ProductCode)
 	if err != nil {

+ 1 - 0
internal/logic/pub/refreshTokenLogic.go

@@ -28,6 +28,7 @@ func NewRefreshTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Refr
 	}
 }
 
+// RefreshToken 刷新令牌。使用有效的 refreshToken 换取新的 accessToken/refreshToken 令牌对,旧令牌即时失效(单会话轮转)。
 func (l *RefreshTokenLogic) RefreshToken(req *types.RefreshTokenReq) (resp *types.LoginResp, err error) {
 	tokenStr := strings.TrimPrefix(req.Authorization, "Bearer ")
 	if tokenStr == "" || tokenStr == req.Authorization {

+ 1 - 0
internal/logic/pub/syncPermsLogic.go

@@ -24,6 +24,7 @@ func NewSyncPermsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SyncPer
 	}
 }
 
+// SyncPerms 同步权限声明。产品服务端通过 appKey/appSecret 认证后,批量同步权限定义(新增/更新/禁用不在列表中的权限)。
 func (l *SyncPermsLogic) SyncPerms(req *types.SyncPermsReq) (resp *types.SyncPermsResp, err error) {
 	items := make([]SyncPermItem, len(req.Perms))
 	for i, p := range req.Perms {

+ 1 - 0
internal/logic/role/bindRolePermsLogic.go

@@ -30,6 +30,7 @@ func NewBindRolePermsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Bin
 	}
 }
 
+// BindRolePerms 绑定角色权限。对指定角色做权限全量覆盖(diff 后批量新增/删除),变更后自动清理该角色下所有用户的权限缓存。
 func (l *BindRolePermsLogic) BindRolePerms(req *types.BindPermsReq) error {
 	role, err := l.svcCtx.SysRoleModel.FindOne(l.ctx, req.RoleId)
 	if err != nil {

+ 1 - 0
internal/logic/role/createRoleLogic.go

@@ -29,6 +29,7 @@ func NewCreateRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Create
 	}
 }
 
+// CreateRole 创建角色。在指定产品下新建角色并设置权限级别,需产品 ADMIN 或超管权限。产品必须存在且已启用。
 func (l *CreateRoleLogic) CreateRole(req *types.CreateRoleReq) (resp *types.IdResp, err error) {
 	if err := authHelper.RequireProductAdminFor(l.ctx, req.ProductCode); err != nil {
 		return nil, err

+ 1 - 0
internal/logic/role/deleteRoleLogic.go

@@ -26,6 +26,7 @@ func NewDeleteRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delete
 	}
 }
 
+// DeleteRole 删除角色。在事务内同时清理角色-权限和用户-角色绑定关系后删除角色,并批量清理受影响用户的权限缓存。
 func (l *DeleteRoleLogic) DeleteRole(req *types.DeleteRoleReq) error {
 	role, err := l.svcCtx.SysRoleModel.FindOne(l.ctx, req.Id)
 	if err != nil {

+ 1 - 0
internal/logic/role/roleDetailLogic.go

@@ -25,6 +25,7 @@ func NewRoleDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RoleDe
 	}
 }
 
+// RoleDetail 角色详情。根据角色 ID 查询角色完整信息及其已绑定的权限 ID 列表。
 func (l *RoleDetailLogic) RoleDetail(req *types.RoleDetailReq) (resp *types.RoleItem, err error) {
 	role, err := l.svcCtx.SysRoleModel.FindOne(l.ctx, req.Id)
 	if err != nil {

+ 1 - 0
internal/logic/role/roleListLogic.go

@@ -26,6 +26,7 @@ func NewRoleListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RoleList
 	}
 }
 
+// RoleList 角色列表。按产品分页查询角色信息,用于角色管理和用户角色分配的选择列表。
 func (l *RoleListLogic) RoleList(req *types.RoleListReq) (resp *types.PageResp, err error) {
 	page, pageSize := util.NormalizePage(req.Page, req.PageSize)
 

+ 1 - 0
internal/logic/role/updateRoleLogic.go

@@ -28,6 +28,7 @@ func NewUpdateRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Update
 	}
 }
 
+// UpdateRole 更新角色。修改角色名称、备注、权限级别和启用/禁用状态。非超管不能降低权限级别。变更后自动清理绑定该角色的用户缓存。
 func (l *UpdateRoleLogic) UpdateRole(req *types.UpdateRoleReq) error {
 	role, err := l.svcCtx.SysRoleModel.FindOne(l.ctx, req.Id)
 	if err != nil {

+ 1 - 0
internal/logic/user/bindRolesLogic.go

@@ -31,6 +31,7 @@ func NewBindRolesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BindRol
 	}
 }
 
+// BindRoles 绑定用户角色。对指定用户在当前产品下做角色全量覆盖(diff 后批量新增/删除),支持权限级别校验防止越权分配。
 func (l *BindRolesLogic) BindRoles(req *types.BindRolesReq) error {
 	if _, err := l.svcCtx.SysUserModel.FindOne(l.ctx, req.UserId); err != nil {
 		return response.ErrNotFound("用户不存在")

+ 1 - 0
internal/logic/user/createUserLogic.go

@@ -35,6 +35,7 @@ func NewCreateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Create
 	}
 }
 
+// CreateUser 创建用户。新建系统用户账号,可指定部门归属。仅超管可调用。
 func (l *CreateUserLogic) CreateUser(req *types.CreateUserReq) (resp *types.IdResp, err error) {
 	productCode := middleware.GetProductCode(l.ctx)
 	if err := authHelper.RequireProductAdminFor(l.ctx, productCode); err != nil {

+ 1 - 0
internal/logic/user/setUserPermsLogic.go

@@ -31,6 +31,7 @@ func NewSetUserPermsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SetU
 	}
 }
 
+// SetUserPerms 设置用户个性化权限。对指定用户在当前产品下做权限全量覆盖,支持 ALLOW(附加)和 DENY(拒绝)两种效果,用于角色权限之外的细粒度调整。
 func (l *SetUserPermsLogic) SetUserPerms(req *types.SetPermsReq) error {
 	if _, err := l.svcCtx.SysUserModel.FindOne(l.ctx, req.UserId); err != nil {
 		return response.ErrNotFound("用户不存在")

+ 1 - 0
internal/logic/user/updateUserLogic.go

@@ -30,6 +30,7 @@ func NewUpdateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Update
 	}
 }
 
+// UpdateUser 更新用户信息。修改用户昵称、邮箱、手机、备注、部门归属等。用户可修改自身非敏感字段,管理者可修改下属用户信息。
 func (l *UpdateUserLogic) UpdateUser(req *types.UpdateUserReq) error {
 	caller := middleware.GetUserDetails(l.ctx)
 	if caller == nil {

+ 1 - 0
internal/logic/user/updateUserStatusLogic.go

@@ -27,6 +27,7 @@ func NewUpdateUserStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *
 	}
 }
 
+// UpdateUserStatus 冻结/解冻用户。修改用户启用状态并递增 tokenVersion 使其令牌失效。不能修改自身或超管状态。
 func (l *UpdateUserStatusLogic) UpdateUserStatus(req *types.UpdateUserStatusReq) error {
 	if req.Status != consts.StatusEnabled && req.Status != consts.StatusDisabled {
 		return response.ErrBadRequest("状态值无效,仅支持 1(启用) 和 2(冻结)")

+ 1 - 0
internal/logic/user/userDetailLogic.go

@@ -25,6 +25,7 @@ func NewUserDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserDe
 	}
 }
 
+// UserDetail 用户详情。查询指定用户的基本信息和当前产品下的角色绑定。产品成员只能查看同产品下用户,超管可查看任意用户。
 func (l *UserDetailLogic) UserDetail(req *types.UserDetailReq) (resp *types.UserItem, err error) {
 	caller := middleware.GetUserDetails(l.ctx)
 	if caller == nil {

+ 1 - 0
internal/logic/user/userListLogic.go

@@ -27,6 +27,7 @@ func NewUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserList
 	}
 }
 
+// UserList 用户列表。超管查看全量用户列表,产品管理者查看当前产品下的成员列表。支持分页。
 func (l *UserListLogic) UserList(req *types.UserListReq) (resp *types.PageResp, err error) {
 	page, pageSize := util.NormalizePage(req.Page, req.PageSize)
 

+ 6 - 0
internal/server/permserver.go

@@ -21,6 +21,7 @@ import (
 	"google.golang.org/grpc/status"
 )
 
+// PermServer 权限管理系统 gRPC 服务实现,供接入产品的服务端调用。
 type PermServer struct {
 	svcCtx *svc.ServiceContext
 	pb.UnimplementedPermServiceServer
@@ -30,6 +31,7 @@ func NewPermServer(svcCtx *svc.ServiceContext) *PermServer {
 	return &PermServer{svcCtx: svcCtx}
 }
 
+// SyncPermissions 同步权限声明。产品服务端通过 appKey/appSecret 认证后批量同步权限定义(新增/更新/禁用不在列表中的权限)。
 func (s *PermServer) SyncPermissions(ctx context.Context, req *pb.SyncPermissionsReq) (*pb.SyncPermissionsResp, error) {
 	items := make([]pub.SyncPermItem, len(req.Perms))
 	for i, p := range req.Perms {
@@ -56,6 +58,7 @@ func (s *PermServer) SyncPermissions(ctx context.Context, req *pb.SyncPermission
 	return &pb.SyncPermissionsResp{Added: result.Added, Updated: result.Updated, Disabled: result.Disabled}, nil
 }
 
+// Login 产品端登录。产品成员通过用户名密码 + productCode 登录,返回 JWT 令牌对及用户权限信息。受 IP 维度限流保护。
 func (s *PermServer) Login(ctx context.Context, req *pb.LoginReq) (*pb.LoginResp, error) {
 	if s.svcCtx.GrpcLoginLimiter != nil {
 		p, ok := peer.FromContext(ctx)
@@ -105,6 +108,7 @@ func (s *PermServer) Login(ctx context.Context, req *pb.LoginReq) (*pb.LoginResp
 	}, nil
 }
 
+// RefreshToken 刷新令牌。使用有效的 refreshToken 换取新的令牌对,同时递增 tokenVersion 使旧令牌即时失效(单会话轮转)。
 func (s *PermServer) RefreshToken(ctx context.Context, req *pb.RefreshTokenReq) (*pb.RefreshTokenResp, error) {
 	claims, err := authHelper.ParseRefreshToken(req.RefreshToken, s.svcCtx.Config.Auth.RefreshSecret)
 	if err != nil {
@@ -164,6 +168,7 @@ func (s *PermServer) RefreshToken(ctx context.Context, req *pb.RefreshTokenReq)
 	}, nil
 }
 
+// VerifyToken 验证令牌。校验 accessToken 的有效性(签名、过期、用户状态、产品状态、成员资格、tokenVersion),有效时返回用户身份和权限信息。
 func (s *PermServer) VerifyToken(ctx context.Context, req *pb.VerifyTokenReq) (*pb.VerifyTokenResp, error) {
 	token, err := jwt.ParseWithClaims(req.AccessToken, &middleware.Claims{}, func(token *jwt.Token) (interface{}, error) {
 		return []byte(s.svcCtx.Config.Auth.AccessSecret), nil
@@ -201,6 +206,7 @@ func (s *PermServer) VerifyToken(ctx context.Context, req *pb.VerifyTokenReq) (*
 	}, nil
 }
 
+// GetUserPerms 查询用户权限。产品服务端通过 appKey/appSecret 认证后查询指定用户在该产品下的成员类型和权限列表,用于产品侧的权限网关判定。
 func (s *PermServer) GetUserPerms(ctx context.Context, req *pb.GetUserPermsReq) (*pb.GetUserPermsResp, error) {
 	product, err := s.svcCtx.SysProductModel.FindOneByAppKey(ctx, req.AppKey)
 	if err != nil {

+ 6 - 0
pb/perm.proto

@@ -4,11 +4,17 @@ package pb;
 
 option go_package = "perms-system-server/pb";
 
+// PermService 权限管理系统 gRPC 服务,供接入产品的服务端调用。
 service PermService {
+  // SyncPermissions 同步权限声明。产品服务端通过 appKey/appSecret 认证后批量同步权限定义(新增/更新/禁用不在列表中的权限)。
   rpc SyncPermissions(SyncPermissionsReq) returns (SyncPermissionsResp);
+  // Login 产品端登录。产品成员通过用户名密码 + productCode 登录,返回 JWT 令牌对及用户权限信息。
   rpc Login(LoginReq) returns (LoginResp);
+  // RefreshToken 刷新令牌。使用有效的 refreshToken 换取新的令牌对,旧令牌即时失效(单会话轮转)。
   rpc RefreshToken(RefreshTokenReq) returns (RefreshTokenResp);
+  // VerifyToken 验证令牌。校验 accessToken 的有效性(签名、过期、用户状态、产品状态、成员资格、tokenVersion),返回用户权限信息。
   rpc VerifyToken(VerifyTokenReq) returns (VerifyTokenResp);
+  // GetUserPerms 查询用户权限。产品服务端通过 appKey/appSecret 认证后查询指定用户在该产品下的成员类型和权限列表。
   rpc GetUserPerms(GetUserPermsReq) returns (GetUserPermsResp);
 }
 

+ 49 - 2
perm.api

@@ -299,179 +299,226 @@ type IdResp {
 }
 
 // ==================== Routes ====================
-// 公开接口(无需鉴权)
+
+// -------- 公开接口(无需 JWT 鉴权) --------
+
+// 管理后台登录,需携带 managementKey 凭证,受 IP 维度限流保护
 @server (
 	prefix:     /api
 	group:      pub
 	middleware: AdminLoginRateLimit
 )
 service perm-api {
+	// AdminLogin 管理后台登录。仅限超级管理员通过 managementKey + 用户名密码登录管理后台,返回 JWT 令牌对
 	@handler AdminLogin
 	post /auth/adminLogin (AdminLoginReq) returns (LoginResp)
 }
 
+// 产品端登录,受 IP 维度限流保护
 @server (
 	prefix:     /api
 	group:      pub
 	middleware: ProductLoginRateLimit
 )
 service perm-api {
+	// Login 产品端登录。产品成员通过用户名密码 + productCode 登录指定产品,返回 JWT 令牌对及用户权限信息
 	@handler Login
 	post /auth/login (LoginReq) returns (LoginResp)
 }
 
+// 令牌刷新,不需要鉴权中间件,自行验证 refreshToken 有效性
 @server (
 	prefix: /api
 	group:  pub
 )
 service perm-api {
+	// RefreshToken 刷新令牌。使用有效的 refreshToken 换取新的 accessToken/refreshToken 令牌对,旧令牌即时失效(单会话轮转)
 	@handler RefreshToken
 	post /auth/refreshToken (RefreshTokenReq) returns (LoginResp)
 }
 
+// 权限同步,产品服务端通过 appKey/appSecret 认证,受 IP 维度限流保护
 @server (
 	prefix:     /api
 	group:      pub
 	middleware: SyncRateLimit
 )
 service perm-api {
+	// SyncPerms 同步权限声明。产品服务端通过 appKey/appSecret 认证后,批量同步权限定义(新增/更新/禁用不在列表中的权限)
 	@handler SyncPerms
 	post /perm/sync (SyncPermsReq) returns (SyncPermsResp)
 }
 
-// 需要鉴权的接口
+// -------- 需要 JWT 鉴权的接口 --------
+
+// 认证相关(修改密码、获取用户信息、注销)
 @server (
 	prefix:     /api
 	group:      auth
 	middleware: JwtAuth
 )
 service perm-api {
+	// UserInfo 获取当前登录用户信息。返回当前 JWT 令牌对应用户的个人信息、成员类型和权限列表,用于前端初始化用户状态
 	@handler UserInfoHandler
 	post /auth/userInfo returns (UserInfo)
 
+	// ChangePassword 修改密码。已登录用户验证原密码后设置新密码,同时递增 tokenVersion 使所有已签发令牌失效
 	@handler ChangePassword
 	post /auth/changePassword (ChangePasswordReq)
 
+	// Logout 用户注销。递增 tokenVersion 使所有已签发的 access/refresh 令牌立即失效,并清除用户缓存
 	@handler Logout
 	post /auth/logout
 }
 
+// 产品管理(仅超管可操作)
 @server (
 	prefix:     /api/product
 	group:      product
 	middleware: JwtAuth
 )
 service perm-api {
+	// CreateProduct 创建产品。自动生成 appKey/appSecret 和产品专属管理员账号,用于接入新的业务产品
 	@handler CreateProduct
 	post /create (CreateProductReq) returns (CreateProductResp)
 
+	// UpdateProduct 更新产品信息。可修改名称、备注和启用/禁用状态,禁用后其成员将无法访问
 	@handler UpdateProduct
 	post /update (UpdateProductReq)
 
+	// ProductList 产品列表。分页查询系统中所有产品的基本信息
 	@handler ProductList
 	post /list (ProductListReq) returns (PageResp)
 
+	// ProductDetail 产品详情。根据产品 ID 查询完整信息
 	@handler ProductDetail
 	post /detail (ProductDetailReq) returns (ProductItem)
 }
 
+// 部门管理(仅超管可操作)
 @server (
 	prefix:     /api/dept
 	group:      dept
 	middleware: JwtAuth
 )
 service perm-api {
+	// CreateDept 创建部门。在指定父部门下新建子部门,自动继承路径层级
 	@handler CreateDept
 	post /create (CreateDeptReq) returns (IdResp)
 
+	// UpdateDept 更新部门。修改名称、排序、类型、备注或启用/禁用状态,使用乐观锁防止并发冲突
 	@handler UpdateDept
 	post /update (UpdateDeptReq)
 
+	// DeleteDept 删除部门。在事务内加行锁后检查是否存在子部门或关联用户,均无则删除
 	@handler DeleteDept
 	post /delete (DeleteDeptReq)
 
+	// DeptTree 部门树。返回完整的组织架构树形结构,用于前端部门选择器和组织架构展示
 	@handler DeptTree
 	post /tree returns ([]*DeptItem)
 }
 
+// 权限查询
 @server (
 	prefix:     /api/perm
 	group:      perm
 	middleware: JwtAuth
 )
 service perm-api {
+	// PermList 权限列表。按产品分页查询已注册的权限定义,用于角色权限配置和用户权限分配的选择列表
 	@handler PermList
 	post /list (PermListReq) returns (PageResp)
 }
 
+// 角色管理(需产品 ADMIN 或超管权限)
 @server (
 	prefix:     /api/role
 	group:      role
 	middleware: JwtAuth
 )
 service perm-api {
+	// CreateRole 创建角色。在指定产品下新建角色并设置权限级别,产品必须存在且已启用
 	@handler CreateRole
 	post /create (CreateRoleReq) returns (IdResp)
 
+	// UpdateRole 更新角色。修改名称、备注、权限级别和启用/禁用状态,非超管不能降低权限级别
 	@handler UpdateRole
 	post /update (UpdateRoleReq)
 
+	// DeleteRole 删除角色。在事务内同时清理角色-权限和用户-角色绑定后删除,并批量清理受影响用户缓存
 	@handler DeleteRole
 	post /delete (DeleteRoleReq)
 
+	// RoleList 角色列表。按产品分页查询角色信息
 	@handler RoleList
 	post /list (RoleListReq) returns (PageResp)
 
+	// RoleDetail 角色详情。根据角色 ID 查询完整信息及已绑定的权限 ID 列表
 	@handler RoleDetail
 	post /detail (RoleDetailReq) returns (RoleItem)
 
+	// BindRolePerms 绑定角色权限。对指定角色做权限全量覆盖(diff 后批量新增/删除)
 	@handler BindRolePerms
 	post /bindPerms (BindPermsReq)
 }
 
+// 用户管理
 @server (
 	prefix:     /api/user
 	group:      user
 	middleware: JwtAuth
 )
 service perm-api {
+	// CreateUser 创建用户。新建系统用户账号,可指定部门归属。仅超管可调用
 	@handler CreateUser
 	post /create (CreateUserReq) returns (IdResp)
 
+	// UpdateUser 更新用户信息。修改昵称、邮箱、手机、备注、部门归属等
 	@handler UpdateUser
 	post /update (UpdateUserReq)
 
+	// UserList 用户列表。超管查看全量,产品管理者查看当前产品下的成员列表
 	@handler UserList
 	post /list (UserListReq) returns (PageResp)
 
+	// UserDetail 用户详情。查询指定用户基本信息和当前产品下的角色绑定
 	@handler UserDetail
 	post /detail (UserDetailReq) returns (UserItem)
 
+	// BindRoles 绑定用户角色。对指定用户在当前产品下做角色全量覆盖,支持权限级别校验防止越权分配
 	@handler BindRoles
 	post /bindRoles (BindRolesReq)
 
+	// SetUserPerms 设置用户个性化权限。支持 ALLOW(附加)和 DENY(拒绝)两种效果,用于角色权限之外的细粒度调整
 	@handler SetUserPerms
 	post /setPerms (SetPermsReq)
 
+	// UpdateUserStatus 冻结/解冻用户。修改启用状态并递增 tokenVersion 使其令牌失效
 	@handler UpdateUserStatus
 	post /updateStatus (UpdateUserStatusReq)
 }
 
+// 产品成员管理(需产品 ADMIN 或超管权限)
 @server (
 	prefix:     /api/member
 	group:      member
 	middleware: JwtAuth
 )
 service perm-api {
+	// AddMember 添加产品成员。将已有用户加入指定产品并设置成员类型(ADMIN/DEVELOPER/MEMBER),产品必须已启用
 	@handler AddMember
 	post /add (AddMemberReq) returns (IdResp)
 
+	// UpdateMember 更新产品成员。修改成员类型或启用/禁用状态,降级最后一个 ADMIN 时会被拒绝
 	@handler UpdateMember
 	post /update (UpdateMemberReq)
 
+	// RemoveMember 移除产品成员。同时清理该用户在产品下的角色和个性化权限绑定,不能移除最后一个 ADMIN
 	@handler RemoveMember
 	post /remove (RemoveMemberReq)
 
+	// MemberList 成员列表。按产品分页查询成员信息,用于产品成员管理页面
 	@handler MemberList
 	post /list (MemberListReq) returns (PageResp)
 }

+ 7 - 7
test-design.md

@@ -172,7 +172,7 @@ MySQL (InnoDB) + Redis Cache
 | TC-0070 | POST /api/product/create | createProduct 含特殊字符被拒绝 | code="abc@def" | 400 | 输入校验 | P0 | productCodeRegexp |
 | TC-0071 | POST /api/product/create | createProduct 全中文被拒绝 | code="产品一" | 400 | 输入校验 | P0 | productCodeRegexp |
 | TC-0072 | POST /api/product/create | createProduct 纯数字开头被拒绝 | code="1abc" | 400 | 输入校验 | P0 | productCodeRegexp 首字符限定 |
-| TC-0073 | POST /api/product/create | createProduct 空字符串被拒绝 | code="" | 400 | 边界 | P0 |  |
+| TC-0073 | POST /api/product/create | createProduct 空字符串被拒绝 | code="" | 400 | 边界 | P0 | |
 | TC-0074 | POST /api/product/create | createProduct 长度>64 被拒绝 | code="a"*65 | 400 "产品编码长度不能超过64个字符" | 边界 | P0 | len>64 |
 | TC-0075 | POST /api/product/create | createProduct 合法编码(含下划线/中划线/数字) | code="pc_01-test" | 创建成功 | 正常路径 | P0 | Regexp 正向匹配 |
 
@@ -693,11 +693,11 @@ MySQL (InnoDB) + Redis Cache
 | TC-0415 | FindByIds | DB异常 | 连接失败 | 返回nil,err | 异常路径 | P1 | err透传 |
 | TC-0416 | FindIdsByDeptId | 有用户的部门 | deptId=1(有用户) | 返回id列表 | 正常路径 | P0 | WHERE deptId=? |
 | TC-0417 | FindIdsByDeptId | 无用户部门 | deptId=999 | 空slice | 边界 | P1 | |
-| TC-0418 | UpdateProfile 状态未变-不递增tokenVersion | statusChanged=false | 成功, tokenVersion不变 | 正常路径 | P0 | H-1修复: 非状态字段更新不影响会话 |
-| TC-0419 | UpdateProfile 状态变更-tokenVersion+1 | statusChanged=true | 成功, tokenVersion+1 | 正常路径 | P0 | H-1修复: 状态变更使会话失效 |
-| TC-0420 | UpdateProfile 乐观锁冲突 | expectedUpdateTime 与DB不符 | 返回ErrUpdateConflict | 异常路径 | P0 | H-1修复: WHERE updateTime=? |
-| TC-0421 | UpdateProfile 并发场景 | 两个 goroutine 基于同一 updateTime 并发更新 | 仅一方成功, 另一方得到 ErrUpdateConflict | 并发 | P0 | H-1修复: 乐观锁仅允许一个成功 |
-| TC-0422 | UpdateProfile userId不存在 | id=9999999 | 返回 ErrUpdateConflict (affected=0) | 异常路径 | P1 | WHERE 不匹配 |
+| TC-0418 | UpdateProfile | 状态未变-不递增tokenVersion | statusChanged=false | 成功, tokenVersion不变 | 正常路径 | P0 | H-1修复: 非状态字段更新不影响会话 |
+| TC-0419 | UpdateProfile | 状态变更-tokenVersion+1 | statusChanged=true | 成功, tokenVersion+1 | 正常路径 | P0 | H-1修复: 状态变更使会话失效 |
+| TC-0420 | UpdateProfile | 乐观锁冲突 | expectedUpdateTime 与DB不符 | 返回ErrUpdateConflict | 异常路径 | P0 | H-1修复: WHERE updateTime=? |
+| TC-0421 | UpdateProfile | 并发场景 | 两个 goroutine 基于同一 updateTime 并发更新 | 仅一方成功, 另一方得到 ErrUpdateConflict | 并发 | P0 | H-1修复: 乐观锁仅允许一个成功 |
+| TC-0422 | UpdateProfile | userId不存在 | id=9999999 | 返回 ErrUpdateConflict (affected=0) | 异常路径 | P1 | WHERE 不匹配 |
 
 ### 8.2 SysProductModel
 
@@ -1023,6 +1023,7 @@ MySQL (InnoDB) + Redis Cache
 ## 十一、 本轮新增对抗性用例(审计修复回归)
 
 > 针对 `audit-report.md` 中 H-4 / M-1 / M-14 / L-3 / L-5 五个关键修复点补充的"攻击性"测试,覆盖:
+>
 > * 最后 ADMIN 保护(移除 & 降级、活跃/禁用 ADMIN 计数差异)
 > * Logout 接口 tokenVersion 递增 + loader 缓存清理
 > * setUserPerms 对产品禁用的拦截
@@ -1064,4 +1065,3 @@ MySQL (InnoDB) + Redis Cache
 | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
 | TC-0734 | 产品已禁用 | product.status=2 | 400 "产品已被禁用,无法设置权限" | 安全 | P0 | M-14:新增 product.Status 校验 |
 | TC-0735 | 产品不存在 | 虚构 productCode | 404 "产品不存在" | 错误路径 | P0 | M-14:FindOneByCode ErrNotFound |
-