# 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] |