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

16 KiB
Raw Permalink Blame History

Implementation Plan: RBAC表结构与GORM数据权限过滤

Branch: 004-rbac-data-permission | Date: 2025-11-18 | Spec: 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:

  • Feature uses Fiber + GORM + Viper + Zap + Lumberjack.v2 + Validator + sonic JSON + Asynq + PostgreSQL
  • No native calls bypass framework (no database/sql, net/http, encoding/json direct use)
  • All HTTP operations use Fiber framework
  • All database operations use GORM
  • All async tasks use Asynq
  • Uses Go official toolchain: go fmt, go vet, golangci-lint
  • Uses Go Modules for dependency management

Code Quality Standards:

  • Follows Handler → Service → Store → Model architecture
  • Handler layer only handles HTTP, no business logic
  • Service layer contains business logic with cross-module support
  • Store layer manages all data access with transaction support
  • Uses dependency injection via struct fields (not constructor patterns)
  • Unified error codes in pkg/errors/
  • Unified API responses via pkg/response/
  • All constants defined in pkg/constants/
  • All Redis keys managed via key generation functions (no hardcoded strings)
  • No hardcoded magic numbers or strings (3+ occurrences must be constants)
  • Defined constants are used instead of hardcoding duplicate values
  • Code comments prefer Chinese for readability (implementation comments in Chinese)
  • Log messages use Chinese (Info/Warn/Error/Debug logs in Chinese)
  • Error messages support Chinese (user-facing errors have Chinese messages)
  • All exported functions/types have Go-style doc comments
  • Code formatted with gofmt
  • 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:

  • Package structure is flat (max 2-3 levels), organized by feature
  • Interfaces are small (1-3 methods), defined at use site
  • No Java-style patterns: no I-prefix, no Impl-suffix, no getters/setters
  • Error handling is explicit (return errors, no panic/recover abuse)
  • Uses composition over inheritance
  • Uses goroutines and channels (not thread pools)
  • Uses context.Context for cancellation and timeouts
  • Naming follows Go conventions: short receivers, consistent abbreviations (URL, ID, HTTP)
  • No Hungarian notation or type prefixes
  • 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:

  • All APIs use unified JSON response format
  • Error responses include clear error codes and bilingual messages
  • RESTful design principles followed
  • Unified pagination parameters (page, page_size, total)
  • Time fields use ISO 8601 format (RFC3339)
  • Currency amounts use integers (cents) to avoid float precision issues

Performance Requirements:

  • API response time (P95) < 200ms, (P99) < 500ms
  • Batch operations use bulk queries/inserts
  • All database queries have appropriate indexes
  • List queries implement pagination (default 20, max 100)
  • Non-realtime operations use async tasks
  • Database and Redis connection pools properly configured
  • Uses goroutines/channels for concurrency (not thread pools)
  • Uses context.Context for timeout control
  • 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):

  • All API error responses use unified JSON format (via pkg/errors/ global ErrorHandler)
  • Handler layer errors return error (not manual JSON responses)
  • Business errors use pkg/errors.New() or pkg/errors.Wrap() with error codes
  • All error codes defined in pkg/errors/codes.go
  • All panics caught by Recover middleware and converted to 500 responses
  • Error logs include complete request context (Request ID, path, method, params)
  • 5xx server errors auto-sanitized (generic message to client, full error in logs)
  • 4xx client errors may return specific business messages
  • No panic in business code (except unrecoverable programming errors)
  • No manual error response construction in Handler (c.Status().JSON())
  • Error codes follow classification: 0=success, 1xxx=client (4xx), 2xxx=server (5xx)
  • Recover middleware registered first in middleware chain
  • Panic recovery logs complete stack trace
  • Single request panic does not affect other requests

Database Design Principles (Constitution Principle IX):

  • Database tables MUST NOT have foreign key constraints
  • GORM models MUST NOT use ORM association tags (foreignKey, hasMany, belongsTo, etc.)
  • Table relationships maintained manually via ID fields
  • Associated data queries are explicit in code, not ORM magic
  • Model structs ONLY contain simple fields, no nested model references
  • Migration scripts validated (no FK constraints, no triggers for relationships)
  • Time fields (created_at, updated_at) handled by GORM, not database triggers

Project Structure

Documentation (this feature)

设计文档specs/ 目录):开发前的规划和设计

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

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 分层架构。

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]