|
|
@@ -0,0 +1,285 @@
|
|
|
+# Story 008.001: 完善角色权限定义和默认数据
|
|
|
+
|
|
|
+## Status
|
|
|
+🔄 In Progress
|
|
|
+
|
|
|
+## Story
|
|
|
+**As a** 系统架构师
|
|
|
+**I want** 明确定义超级管理员和普通管理员角色及其权限
|
|
|
+**so that** 为系统提供清晰的权限基础
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+1. 在`user-module`中定义标准权限常量:`PERMISSION_ADVERTISEMENT_MANAGE = 'advertisement:manage'`等
|
|
|
+2. 创建超级管理员角色:`super-admin`,包含广告管理权限
|
|
|
+3. 创建普通管理员角色:`admin`,不包含广告管理权限
|
|
|
+4. 权限定义仅针对广告管理,其他模块权限保持现有状态
|
|
|
+5. 创建数据库迁移脚本添加默认角色数据到`role`表
|
|
|
+6. 提供角色权限管理API:角色列表、权限分配、用户角色分配
|
|
|
+7. 编写单元测试验证角色权限逻辑
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+- [x] **定义标准权限常量** (AC: 1)
|
|
|
+ - [x] 在`packages/user-module/src/constants/`目录下创建`permissions.constants.ts`文件
|
|
|
+ - [x] 定义广告管理相关权限常量:`ADVERTISEMENT_VIEW`, `ADVERTISEMENT_CREATE`, `ADVERTISEMENT_EDIT`, `ADVERTISEMENT_DELETE`, `ADVERTISEMENT_MANAGE`
|
|
|
+ - [x] 采用`entity:action`命名规范:`advertisement:view`, `advertisement:create`, `advertisement:edit`, `advertisement:delete`, `advertisement:manage`
|
|
|
+ - [x] 确保常量命名符合项目命名规范
|
|
|
+
|
|
|
+- [x] **创建超级管理员和普通管理员角色定义** (AC: 2, 3)
|
|
|
+ - [x] 在`user-module`中定义角色常量:`ROLE_SUPER_ADMIN = 'super-admin'`, `ROLE_ADMIN = 'admin'`
|
|
|
+ - [x] 确保超级管理员角色包含`advertisement:manage`权限
|
|
|
+ - [x] 确保普通管理员角色不包含广告管理相关权限
|
|
|
+ - [x] 保持现有其他模块权限不变
|
|
|
+
|
|
|
+- [x] **创建数据库迁移脚本** (AC: 5)
|
|
|
+ - [x] 在`packages/user-module/src/migrations/`目录下创建迁移文件:`1234567890-add-default-roles.ts`
|
|
|
+ - [x] 实现SQL插入语句添加默认角色数据到`role`表
|
|
|
+ - [x] 使用`ON CONFLICT`语句确保幂等性:如果角色已存在则更新权限
|
|
|
+ - [x] 确保多租户环境下的默认数据一致性
|
|
|
+ - [x] 迁移脚本应包含回滚逻辑
|
|
|
+
|
|
|
+- [x] **扩展角色服务提供权限管理功能** (AC: 6)
|
|
|
+ - [x] 扩展`RoleService`类,添加权限管理方法
|
|
|
+ - [x] 实现`hasPermission(userId, permission)`方法检查用户权限(实现为 checkUserPermission)
|
|
|
+ - [x] 实现`getUserPermissions(userId)`方法获取用户权限列表
|
|
|
+ - [x] 实现`assignRoleToUser(userId, roleId)`方法分配用户角色
|
|
|
+ - [x] 确保所有方法支持多租户上下文
|
|
|
+
|
|
|
+- [x] **实现角色权限管理API** (AC: 6)
|
|
|
+ - [x] 在`user-module`中创建权限相关API路由
|
|
|
+ - [x] `GET /api/user/permissions` - 获取当前用户权限列表
|
|
|
+ - [x] `GET /api/roles` - 获取角色列表(带权限)
|
|
|
+ - [x] `PUT /api/roles/{id}/permissions` - 更新角色权限
|
|
|
+ - [x] `GET /api/users/{id}/roles` - 获取用户角色
|
|
|
+ - [x] `PUT /api/users/{id}/roles` - 更新用户角色
|
|
|
+ - [x] 所有API需要身份验证和权限检查
|
|
|
+
|
|
|
+- [x] **编写单元测试** (AC: 7)
|
|
|
+ - [x] 编写权限常量定义测试(已创建 permissions.constants.test.ts)
|
|
|
+ - [ ] 编写角色服务权限检查逻辑测试(待扩展现有测试)
|
|
|
+ - [ ] 编写角色权限管理API测试(待创建)
|
|
|
+ - [ ] 确保测试覆盖率 ≥ 80%(待验证)
|
|
|
+ - [ ] 测试多租户环境下的权限隔离(待实现)
|
|
|
+
|
|
|
+- [ ] **集成测试和验证** (AC: 2, 3, 4)
|
|
|
+ - [ ] 创建超级管理员测试账号
|
|
|
+ - [ ] 创建普通管理员测试账号
|
|
|
+ - [ ] 验证角色权限分配正确性
|
|
|
+ - [ ] 验证数据库迁移脚本执行正确
|
|
|
+ - [ ] 验证API功能正常工作
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### 技术栈信息 [Source: architecture/tech-stack.md]
|
|
|
+- **运行时**: Node.js 20.18.3
|
|
|
+- **框架**: Hono 4.8.5 (Web框架和API路由,RPC类型安全)
|
|
|
+- **数据库**: PostgreSQL 17 (通过TypeORM进行数据持久化存储)
|
|
|
+- **ORM**: TypeORM 0.3.25 (数据库操作抽象,实体管理)
|
|
|
+- **测试框架**: Vitest 2.x (单元测试框架,更好的TypeORM支持)
|
|
|
+- **API测试**: hono/testing (内置,API端点测试,更好的类型安全)
|
|
|
+
|
|
|
+### 项目结构信息 [Source: architecture/source-tree.md]
|
|
|
+- **包管理**: 使用pnpm workspace管理多包依赖关系
|
|
|
+- **包架构层次**:
|
|
|
+ - **基础设施层**: shared-types → shared-utils → shared-crud
|
|
|
+ - **测试基础设施**: shared-test-util
|
|
|
+ - **业务模块层**: 多租户模块包(-mt后缀),支持租户数据隔离
|
|
|
+ - **应用层**: server (重构后)
|
|
|
+- **多租户架构**:
|
|
|
+ - **包复制策略**: 基于Epic-007方案,通过复制单租户包创建多租户版本
|
|
|
+ - **租户隔离**: 通过租户ID实现数据隔离,支持多租户部署
|
|
|
+ - **后端包**: 10个多租户模块包,支持租户数据隔离
|
|
|
+- **文件命名**: 保持现有kebab-case命名约定
|
|
|
+- **模块化架构**: 采用分层包结构,支持按需安装和独立开发
|
|
|
+
|
|
|
+### 编码标准 [Source: architecture/coding-standards.md]
|
|
|
+- **代码风格**: TypeScript严格模式,一致的缩进和命名
|
|
|
+- **测试位置**: `__tests__` 文件夹与源码并列(但实际使用`tests/`目录)
|
|
|
+- **覆盖率目标**: 核心业务逻辑 > 80%
|
|
|
+- **测试类型**: 单元测试、集成测试、E2E测试
|
|
|
+- **现有API兼容性**: 确保测试不破坏现有API契约
|
|
|
+- **数据库集成**: 使用测试数据库,避免污染生产数据
|
|
|
+
|
|
|
+### 测试策略 [Source: architecture/testing-strategy.md]
|
|
|
+- **单元测试范围**: 单个函数、类或组件,验证独立单元的正确性
|
|
|
+- **单元测试位置**: `packages/*-module/tests/unit/**/*.test.ts`
|
|
|
+- **集成测试范围**: 多个组件/服务协作,验证模块间集成和交互
|
|
|
+- **集成测试位置**: `packages/*-module/tests/integration/**/*.test.ts`
|
|
|
+- **测试框架**: Vitest + Testing Library + hono/testing + shared-test-util
|
|
|
+- **单元测试覆盖率目标**: ≥ 80%
|
|
|
+- **集成测试覆盖率目标**: ≥ 60%
|
|
|
+- **测试执行频率**: 单元测试每次代码变更,集成测试每次API变更
|
|
|
+
|
|
|
+### 数据模型设计 [Source: docs/prd/epic-008-permission-role-management.md#数据库设计]
|
|
|
+**role表结构**:
|
|
|
+基于现有Role实体,使用simple-array存储权限列表:
|
|
|
+```sql
|
|
|
+-- 现有role表结构
|
|
|
+CREATE TABLE role (
|
|
|
+ id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
|
|
|
+ name VARCHAR(100) NOT NULL COMMENT '角色名称',
|
|
|
+ description VARCHAR(500) COMMENT '角色描述',
|
|
|
+ permissions TEXT COMMENT '权限列表(simple-array格式)',
|
|
|
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ UNIQUE KEY uk_tenant_name (tenant_id, name)
|
|
|
+) COMMENT='角色表';
|
|
|
+```
|
|
|
+
|
|
|
+**默认角色数据迁移脚本**:
|
|
|
+```sql
|
|
|
+INSERT INTO role (tenant_id, name, description, permissions)
|
|
|
+VALUES
|
|
|
+(1, 'super-admin', '超级管理员', 'advertisement:manage'),
|
|
|
+(1, 'admin', '普通管理员', '')
|
|
|
+ON CONFLICT (tenant_id, name) DO UPDATE
|
|
|
+SET permissions =
|
|
|
+ CASE
|
|
|
+ WHEN EXCLUDED.name = 'super-admin' THEN
|
|
|
+ -- 超级管理员:确保有 advertisement:manage 权限,保留其他现有权限
|
|
|
+ CASE
|
|
|
+ WHEN role.permissions = '' THEN 'advertisement:manage'
|
|
|
+ ELSE CONCAT(role.permissions, ',advertisement:manage')
|
|
|
+ END
|
|
|
+ WHEN EXCLUDED.name = 'admin' THEN
|
|
|
+ -- 普通管理员:确保没有 advertisement:manage 权限,保留其他现有权限
|
|
|
+ REPLACE(role.permissions, 'advertisement:manage', '')
|
|
|
+ END,
|
|
|
+description = EXCLUDED.description;
|
|
|
+```
|
|
|
+
|
|
|
+### 权限命名规范 [Source: docs/prd/epic-008-permission-role-management.md#权限命名规范]
|
|
|
+采用`entity:action`格式:
|
|
|
+- `advertisement:view` - 查看广告
|
|
|
+- `advertisement:create` - 创建广告
|
|
|
+- `advertisement:edit` - 编辑广告
|
|
|
+- `advertisement:delete` - 删除广告
|
|
|
+- `advertisement:manage` - 广告管理(包含所有操作)
|
|
|
+
|
|
|
+### 模块结构
|
|
|
+```
|
|
|
+packages/
|
|
|
+├── user-module/ # 用户模块(增强)
|
|
|
+│ ├── src/
|
|
|
+│ │ ├── constants/ # 新增:权限常量定义
|
|
|
+│ │ │ └── permissions.constants.ts
|
|
|
+│ │ ├── entities/ # 现有:角色实体
|
|
|
+│ │ │ └── role.entity.ts
|
|
|
+│ │ ├── services/ # 现有:角色服务(增强)
|
|
|
+│ │ │ └── role.service.ts
|
|
|
+│ │ ├── migrations/ # 新增:默认角色数据迁移
|
|
|
+│ │ │ └── 1234567890-add-default-roles.ts
|
|
|
+│ │ └── routes/ # 新增:角色权限管理API
|
|
|
+│ │ └── role-permission.routes.ts
|
|
|
+│ └── package.json
|
|
|
+```
|
|
|
+
|
|
|
+### 文件位置和命名约定
|
|
|
+- **权限常量文件**: `packages/user-module/src/constants/permissions.constants.ts`
|
|
|
+- **角色服务文件**: `packages/user-module/src/services/role.service.ts` (现有文件扩展)
|
|
|
+- **迁移文件**: `packages/user-module/src/migrations/1234567890-add-default-roles.ts`
|
|
|
+- **权限API路由文件**: `packages/user-module/src/routes/role-permission.routes.ts`
|
|
|
+- **测试文件**: `packages/user-module/tests/unit/role-permission.test.ts`
|
|
|
+
|
|
|
+### 多租户实体命名模式
|
|
|
+基于现有多租户模块观察:
|
|
|
+- **实体类名**: 以`Mt`结尾(如`RoleMt`)
|
|
|
+- **表名**: 以`_mt`结尾(如`role_mt`)
|
|
|
+- **文件命名**: `*.mt.ts` 或 `*.entity.ts`
|
|
|
+- **必须包含**: `tenant_id`字段用于租户隔离
|
|
|
+
|
|
|
+### 技术约束
|
|
|
+- **数据库**: 使用PostgreSQL 17,支持simple-array类型存储权限列表
|
|
|
+- **权限存储**: 使用TypeORM的`simple-array`类型存储权限字符串数组
|
|
|
+- **多租户支持**: 所有权限检查必须在租户上下文中进行
|
|
|
+- **缓存策略**: 用户权限信息需要缓存,避免重复数据库查询
|
|
|
+- **兼容性**: 保持现有API接口不变,仅添加新API
|
|
|
+
|
|
|
+### 集成点
|
|
|
+1. **用户模块集成**: 扩展现有`user-module`,保持向后兼容
|
|
|
+2. **服务器集成**: 使用现有的`permission.middleware.ts`中间件
|
|
|
+3. **广告模块集成**: 后续故事中将广告模块路由集成权限检查
|
|
|
+4. **前端集成**: 后续故事中前端将使用权限API获取用户权限
|
|
|
+
|
|
|
+### 测试要求
|
|
|
+- **单元测试**: 测试权限常量定义、角色服务权限检查、API路由
|
|
|
+- **集成测试**: 测试数据库迁移、API端点功能、权限检查流程
|
|
|
+- **边界条件测试**: 测试无效权限、跨租户访问、重复角色等场景
|
|
|
+- **覆盖率**: 核心业务逻辑必须达到80%以上单元测试覆盖率
|
|
|
+
|
|
|
+### 项目结构注意事项
|
|
|
+- 需要遵循现有的模块包架构模式
|
|
|
+- 权限系统基于现有`user-module`扩展,不创建新模块
|
|
|
+- 保持向后兼容性,不影响现有功能
|
|
|
+- 参考现有的多租户模块实现模式
|
|
|
+
|
|
|
+### 没有在架构文档中找到的特定指导
|
|
|
+- TypeORM simple-array类型的具体使用示例
|
|
|
+- 权限中间件的具体集成方式
|
|
|
+- 多租户权限检查的具体实现模式
|
|
|
+
|
|
|
+## Testing
|
|
|
+### 测试标准 [Source: architecture/testing-strategy.md]
|
|
|
+- **测试文件位置**: `packages/user-module/tests/` 目录下
|
|
|
+- **单元测试位置**: `tests/unit/**/*.test.ts`
|
|
|
+- **集成测试位置**: `tests/integration/**/*.test.ts`
|
|
|
+- **测试框架**: Vitest + hono/testing + shared-test-util
|
|
|
+- **覆盖率要求**: 单元测试 ≥ 80%,集成测试 ≥ 60%
|
|
|
+- **测试模式**: 使用测试数据工厂模式,避免硬编码测试数据
|
|
|
+- **数据库测试**: 使用专用测试数据库,事务回滚机制
|
|
|
+
|
|
|
+### 测试策略要求
|
|
|
+- **单元测试**: 验证权限常量定义、角色服务方法、权限检查逻辑
|
|
|
+- **集成测试**: 验证API端点功能、数据库迁移、模块间集成
|
|
|
+- **边界测试**: 测试无效权限字符串、跨租户访问、重复角色分配
|
|
|
+- **错误处理测试**: 测试各种错误场景和异常情况
|
|
|
+- **性能测试**: 确保权限检查响应时间 < 50ms (p95)
|
|
|
+
|
|
|
+### 测试数据管理
|
|
|
+- 使用测试数据工厂模式创建测试角色和用户
|
|
|
+- 每个测试后清理测试数据(事务回滚)
|
|
|
+- 使用唯一标识符确保测试数据隔离
|
|
|
+- 模拟外部依赖(如认证中间件)
|
|
|
+
|
|
|
+## Change Log
|
|
|
+| Date | Version | Description | Author |
|
|
|
+|------|---------|-------------|--------|
|
|
|
+| 2025-12-19 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
|
|
|
+| 2025-12-19 | 1.1 | 实现角色权限定义和API | James (Developer Agent) |
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+*此部分由开发代理在实现过程中填写*
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+- Claude Code (Sonnet 4.5)
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+- 无重大调试问题
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+1. 成功创建权限常量定义文件(permissions.constants.ts, roles.constants.ts)
|
|
|
+2. 更新 Role 实体添加 tenantId 字段和唯一约束
|
|
|
+3. 创建数据库迁移脚本(1234567890-add-default-roles.ts)
|
|
|
+4. 扩展 RoleService 添加权限管理方法(checkUserPermission, getUserPermissions, assignRoleToUser, removeRoleFromUser, getUserRoles)
|
|
|
+5. 创建角色权限管理 API 路由(role-permission.routes.ts)包含所有要求的端点
|
|
|
+6. 创建权限常量单元测试文件(permissions.constants.test.ts)
|
|
|
+7. 更新项目导出结构(index.ts, constants/index.ts, routes/index.ts)
|
|
|
+
|
|
|
+### File List
|
|
|
+**创建的文件:**
|
|
|
+- packages/user-module/src/constants/permissions.constants.ts
|
|
|
+- packages/user-module/src/constants/roles.constants.ts
|
|
|
+- packages/user-module/src/constants/index.ts
|
|
|
+- packages/user-module/src/migrations/1234567890-add-default-roles.ts
|
|
|
+- packages/user-module/src/routes/role-permission.routes.ts
|
|
|
+- packages/user-module/tests/unit/permissions.constants.test.ts
|
|
|
+
|
|
|
+**修改的文件:**
|
|
|
+- packages/user-module/src/index.ts(添加常量导出)
|
|
|
+- packages/user-module/src/entities/role.entity.ts(添加 tenantId 字段、索引和唯一约束)
|
|
|
+- packages/user-module/src/services/role.service.ts(扩展权限管理方法)
|
|
|
+- packages/user-module/src/routes/index.ts(添加 rolePermissionRoutes 导出)
|
|
|
+- docs/stories/008.001.permission-role-definition.story.md(更新任务状态和开发记录)
|
|
|
+
|
|
|
+## QA Results
|
|
|
+*此部分由QA代理在审查完成后填写*
|