Files
huang eaa70ac255 feat: 实现 RBAC 权限系统和数据权限控制 (004-rbac-data-permission)
主要功能:
- 实现完整的 RBAC 权限系统(账号、角色、权限的多对多关联)
- 基于 owner_id + shop_id 的自动数据权限过滤
- 使用 PostgreSQL WITH RECURSIVE 查询下级账号
- Redis 缓存优化下级账号查询性能(30分钟过期)
- 支持多租户数据隔离和层级权限管理

技术实现:
- 新增 Account、Role、Permission 模型及关联关系表
- 实现 GORM Scopes 自动应用数据权限过滤
- 添加数据库迁移脚本(000002_rbac_data_permission、000003_add_owner_id_shop_id)
- 完善错误码定义(1010-1027 为 RBAC 相关错误)
- 重构 main.go 采用函数拆分提高可读性

测试覆盖:
- 添加 Account、Role、Permission 的集成测试
- 添加数据权限过滤的单元测试和集成测试
- 添加下级账号查询和缓存的单元测试
- 添加 API 回归测试确保向后兼容

文档更新:
- 更新 README.md 添加 RBAC 功能说明
- 更新 CLAUDE.md 添加技术栈和开发原则
- 添加 docs/004-rbac-data-permission/ 功能总结和使用指南

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 16:44:06 +08:00

269 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Implementation Plan: RBAC表结构与GORM数据权限过滤
**Branch**: `004-rbac-data-permission` | **Date**: 2025-11-18 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/004-rbac-data-permission/spec.md`
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
## Summary
实现完整的 RBAC 权限系统和基于 owner_id + shop_id 的自动数据权限过滤机制。核心功能包括:(1) 创建 5 个 RBAC 相关数据库表(账号、角色、权限、账号-角色关联、角色-权限关联)和对应的 GORM 模型,支持层级关系和软删除;(2) 实现 GORM Scopes 自动数据权限过滤,根据当前用户 ID 递归查询所有下级 ID 并结合 shop_id 双重过滤,使用 Redis 缓存优化性能;(3) 将 main 函数重构为多个独立的初始化函数,并将路由按业务模块拆分到 internal/routes/ 目录。
## Technical Context
**Language/Version**: Go 1.25.4
**Primary Dependencies**: Fiber v2.x (HTTP 框架), GORM v1.25.x (ORM), Viper (配置管理), Zap + Lumberjack.v2 (日志), sonic (JSON 序列化), Asynq v0.24.x (异步任务队列), golang-migrate (数据库迁移)
**Storage**: PostgreSQL 14+ (主数据库), Redis 6.0+ (缓存和任务队列存储)
**Testing**: Go 标准 testing 框架, testcontainers (集成测试)
**Target Platform**: Linux 服务器 (后端 API 服务)
**Project Type**: single (单体后端应用)
**Performance Goals**: API 响应时间 P95 < 200ms, P99 < 500ms; 数据库查询 P95 < 50ms, P99 < 100ms; 递归查询下级 ID P95 < 50ms, P99 < 100ms (含 Redis 缓存); 支持至少 5 层用户层级
**Constraints**: 内存使用 < 500MB (API 服务正常负载); 数据库连接池 MaxOpenConns=25; Redis 连接池 PoolSize=10; 下级 ID 缓存 30 分钟过期
**Scale/Scope**: 5 个 RBAC 表; 支持多租户数据隔离; 递归层级深度 ≥5 层; 账号-角色-权限多对多关联; 主函数重构≤100 行和路由模块化6+ 模块文件)
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
**Tech Stack Adherence**:
- [x] Feature uses Fiber + GORM + Viper + Zap + Lumberjack.v2 + Validator + sonic JSON + Asynq + PostgreSQL
- [x] No native calls bypass framework (no `database/sql`, `net/http`, `encoding/json` direct use)
- [x] All HTTP operations use Fiber framework
- [x] All database operations use GORM
- [x] All async tasks use Asynq
- [x] Uses Go official toolchain: `go fmt`, `go vet`, `golangci-lint`
- [x] Uses Go Modules for dependency management
**Code Quality Standards**:
- [x] Follows Handler → Service → Store → Model architecture
- [x] Handler layer only handles HTTP, no business logic
- [x] Service layer contains business logic with cross-module support
- [x] Store layer manages all data access with transaction support
- [x] Uses dependency injection via struct fields (not constructor patterns)
- [x] Unified error codes in `pkg/errors/`
- [x] Unified API responses via `pkg/response/`
- [x] All constants defined in `pkg/constants/`
- [x] All Redis keys managed via key generation functions (no hardcoded strings)
- [x] **No hardcoded magic numbers or strings (3+ occurrences must be constants)**
- [x] **Defined constants are used instead of hardcoding duplicate values**
- [x] **Code comments prefer Chinese for readability (implementation comments in Chinese)**
- [x] **Log messages use Chinese (Info/Warn/Error/Debug logs in Chinese)**
- [x] **Error messages support Chinese (user-facing errors have Chinese messages)**
- [x] All exported functions/types have Go-style doc comments
- [x] Code formatted with `gofmt`
- [x] Follows Effective Go and Go Code Review Comments
**Documentation Standards** (Constitution Principle VII):
- [ ] Feature summary docs placed in `docs/{feature-id}/` mirroring `specs/{feature-id}/`
- [ ] Summary doc filenames use Chinese (功能总结.md, 使用指南.md, etc.)
- [ ] Summary doc content uses Chinese
- [ ] README.md updated with brief Chinese summary (2-3 sentences)
- [ ] Documentation is concise for first-time contributors
**Go Idiomatic Design**:
- [x] Package structure is flat (max 2-3 levels), organized by feature
- [x] Interfaces are small (1-3 methods), defined at use site
- [x] No Java-style patterns: no I-prefix, no Impl-suffix, no getters/setters
- [x] Error handling is explicit (return errors, no panic/recover abuse)
- [x] Uses composition over inheritance
- [x] Uses goroutines and channels (not thread pools)
- [x] Uses `context.Context` for cancellation and timeouts
- [x] Naming follows Go conventions: short receivers, consistent abbreviations (URL, ID, HTTP)
- [x] No Hungarian notation or type prefixes
- [x] Simple constructors (New/NewXxx), no Builder pattern unless necessary
**Testing Standards**:
- [ ] Unit tests for all core business logic (Service layer)
- [ ] Integration tests for all API endpoints
- [ ] Tests use Go standard testing framework
- [ ] Test files named `*_test.go` in same directory
- [ ] Test functions use `Test` prefix, benchmarks use `Benchmark` prefix
- [ ] Table-driven tests for multiple test cases
- [ ] Test helpers marked with `t.Helper()`
- [ ] Tests are independent (no external service dependencies)
- [ ] Target coverage: 70%+ overall, 90%+ for core business
**User Experience Consistency**:
- [x] All APIs use unified JSON response format
- [x] Error responses include clear error codes and bilingual messages
- [x] RESTful design principles followed
- [x] Unified pagination parameters (page, page_size, total)
- [x] Time fields use ISO 8601 format (RFC3339)
- [x] Currency amounts use integers (cents) to avoid float precision issues
**Performance Requirements**:
- [x] API response time (P95) < 200ms, (P99) < 500ms
- [x] Batch operations use bulk queries/inserts
- [x] All database queries have appropriate indexes
- [x] List queries implement pagination (default 20, max 100)
- [x] Non-realtime operations use async tasks
- [x] Database and Redis connection pools properly configured
- [x] Uses goroutines/channels for concurrency (not thread pools)
- [x] Uses `context.Context` for timeout control
- [x] Uses `sync.Pool` for frequently allocated objects
**Access Logging Standards** (Constitution Principle VIII):
- [ ] ALL HTTP requests logged to access.log without exception
- [ ] Request parameters (query + body) logged (limited to 50KB)
- [ ] Response parameters (body) logged (limited to 50KB)
- [ ] Logging happens via centralized Logger middleware (pkg/logger/Middleware())
- [ ] No middleware bypasses access logging (including auth failures, rate limits)
- [ ] Body truncation indicates "... (truncated)" when over 50KB limit
- [ ] Access log includes all required fields: method, path, query, status, duration_ms, request_id, ip, user_agent, user_id, request_body, response_body
**Error Handling Standards** (Constitution Principle X):
- [x] All API error responses use unified JSON format (via pkg/errors/ global ErrorHandler)
- [x] Handler layer errors return error (not manual JSON responses)
- [x] Business errors use pkg/errors.New() or pkg/errors.Wrap() with error codes
- [x] All error codes defined in pkg/errors/codes.go
- [x] All panics caught by Recover middleware and converted to 500 responses
- [x] Error logs include complete request context (Request ID, path, method, params)
- [x] 5xx server errors auto-sanitized (generic message to client, full error in logs)
- [x] 4xx client errors may return specific business messages
- [x] No panic in business code (except unrecoverable programming errors)
- [x] No manual error response construction in Handler (c.Status().JSON())
- [x] Error codes follow classification: 0=success, 1xxx=client (4xx), 2xxx=server (5xx)
- [x] Recover middleware registered first in middleware chain
- [x] Panic recovery logs complete stack trace
- [x] Single request panic does not affect other requests
**Database Design Principles** (Constitution Principle IX):
- [x] Database tables MUST NOT have foreign key constraints
- [x] GORM models MUST NOT use ORM association tags (foreignKey, hasMany, belongsTo, etc.)
- [x] Table relationships maintained manually via ID fields
- [x] Associated data queries are explicit in code, not ORM magic
- [x] Model structs ONLY contain simple fields, no nested model references
- [x] Migration scripts validated (no FK constraints, no triggers for relationships)
- [x] Time fields (created_at, updated_at) handled by GORM, not database triggers
## Project Structure
### Documentation (this feature)
**设计文档specs/ 目录)**:开发前的规划和设计
```text
specs/[###-feature]/
├── plan.md # This file (/speckit.plan command output)
├── research.md # Phase 0 output (/speckit.plan command)
├── data-model.md # Phase 1 output (/speckit.plan command)
├── quickstart.md # Phase 1 output (/speckit.plan command)
├── contracts/ # Phase 1 output (/speckit.plan command)
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
```
**总结文档docs/ 目录)**:开发完成后的总结和使用指南(遵循 Constitution Principle VII
```text
docs/[###-feature]/
├── 功能总结.md # 功能概述、核心实现、技术要点MUST 使用中文命名和内容)
├── 使用指南.md # 如何使用该功能的详细说明MUST 使用中文命名和内容)
└── 架构说明.md # 架构设计和技术决策可选MUST 使用中文命名和内容)
```
**README.md 更新**:每次完成功能后 MUST 在 README.md 添加简短描述2-3 句话,中文)
### Source Code (repository root)
本功能采用单体后端应用结构Option 1: Single project遵循 Handler → Service → Store → Model 分层架构。
```text
internal/
├── model/ # 数据模型和 DTO
│ ├── account.go # Account 模型(新增)
│ ├── account_dto.go # Account DTO新增
│ ├── role.go # Role 模型(新增)
│ ├── role_dto.go # Role DTO新增
│ ├── permission.go # Permission 模型(新增)
│ ├── permission_dto.go # Permission DTO新增
│ ├── account_role.go # AccountRole 关联表模型(新增)
│ ├── account_role_dto.go # AccountRole DTO新增
│ ├── role_permission.go # RolePermission 关联表模型(新增)
│ ├── role_permission_dto.go # RolePermission DTO新增
│ # 注1: data_transfer_log.go 是未来功能,当前 MVP 不包含
│ # 注2: user.go 和 order.go 是之前的示例代码,未来实际业务表需自行添加 owner_id/shop_id 字段
├── handler/ # HTTP 处理层
│ ├── account.go # 账号管理 Handler新增
│ ├── role.go # 角色管理 Handler新增
│ └── permission.go # 权限管理 Handler新增
│ # 注: user.go 和 order.go 是之前的示例,实际业务 Handler 由业务需求决定
├── service/ # 业务逻辑层
│ ├── account/ # 账号服务(新增)
│ │ └── service.go
│ ├── role/ # 角色服务(新增)
│ │ └── service.go
│ └── permission/ # 权限服务(新增)
│ └── service.go
│ # 注: user 和 order 是之前的示例,实际业务服务由业务需求决定
├── store/ # 数据访问层
│ ├── options.go # Store 查询选项(新增)
│ └── postgres/ # PostgreSQL 实现
│ ├── scopes.go # GORM Scopes数据权限过滤新增
│ ├── account_store.go # 账号 Store新增
│ ├── role_store.go # 角色 Store新增
│ ├── permission_store.go # 权限 Store新增
│ ├── account_role_store.go # 账号-角色 Store新增
│ └── role_permission_store.go # 角色-权限 Store新增
│ # 注1: data_transfer_log_store.go 是未来功能,当前 MVP 不包含
│ # 注2: user_store 和 order_store 是之前的示例,未来业务 Store 需应用 DataPermissionScope
└── routes/ # 路由注册(新增目录)
├── routes.go # 路由总入口(新增)
├── account.go # 账号路由(新增)
├── role.go # 角色路由(新增)
├── permission.go # 权限路由(新增)
├── task.go # 任务路由(新增)
└── health.go # 健康检查路由(新增)
# 注: user.go 和 order.go 是之前的示例,实际业务路由由业务需求决定
pkg/
├── constants/ # 常量定义
│ ├── constants.go # 业务常量(需添加 RBAC 常量)
│ └── redis.go # Redis key 生成函数(需添加 RedisAccountSubordinatesKey
├── middleware/ # 中间件
│ └── auth.go # 认证中间件(需添加 Context 辅助函数)
├── errors/ # 错误处理
│ └── codes.go # 错误码(需添加 RBAC 相关错误码)
└── response/ # 统一响应
└── response.go # 响应结构(已有)
cmd/
└── api/
└── main.go # 主函数(需重构为编排函数)
migrations/ # 数据库迁移
├── 000002_rbac_data_permission.up.sql # RBAC 表创建脚本(新增)
├── 000002_rbac_data_permission.down.sql # RBAC 表回滚脚本(新增)
├── 000003_add_owner_id_shop_id.up.sql # 业务表添加 owner_id/shop_id 示例(新增)
└── 000003_add_owner_id_shop_id.down.sql # 业务表回滚示例(新增)
# 注: 000004_data_transfer_log 迁移是未来功能,当前 MVP 不包含
tests/
├── integration/ # 集成测试
│ ├── account_test.go # 账号集成测试(新增)
│ ├── role_test.go # 角色集成测试(新增)
│ ├── permission_test.go # 权限集成测试(新增)
│ ├── account_role_test.go # 账号-角色关联测试(新增)
│ ├── role_permission_test.go # 角色-权限关联测试(新增)
│ └── data_permission_test.go # 数据权限过滤测试(新增)
└── unit/ # 单元测试
├── account_service_test.go # 账号 Service 测试(新增)
└── data_permission_test.go # 递归查询和缓存测试(新增)
```
**Structure Decision**: 本功能使用单体后端结构(单项目),严格遵循 Handler → Service → Store → Model 四层架构。新增 `internal/routes/` 目录用于路由模块化,将原本集中在 `main.go` 中的路由注册按业务模块拆分。所有 RBAC 相关的模型、Handler、Service、Store 都遵循相同的分层模式,确保代码组织一致性和可维护性。
## Complexity Tracking
> **Fill ONLY if Constitution Check has violations that must be justified**
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |