docs(plan): add dynamic roles and doc visibility rbac implementation plan
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
# 动态角色管理与单文档可见性覆盖权限系统实现计划
|
||||
# (Dynamic Roles & Document Visibility Override RBAC Implementation Plan)
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 实现医疗器械全流程智能协同研发系统中的全局动态角色管理 (RBAC)、工作流文档可见性基线与单文档可见性覆盖 (Override) 机制,并完成关键业务动作(新建项目、指派文档负责人、文档覆盖配置)的权限拦截与交互式测试验证。
|
||||
|
||||
**Architecture:** 采用“全局动态角色 (RBAC) + 项目法定三权 (Project-Scoped Duties) + 单文档资源覆盖 (Doc-Level Visibility Override)”三层解耦模型。通过纯函数决策引擎 `isDeliverableVisible` 与 `hasPermission` 统一计算访问权,结合前端响应式 UI(动态角色管理面板、单文档可见性覆盖弹窗、动作拦截置灰与自动隐藏)与 localStorage 本地持久化,构建最小可测试与应用的完整闭环。
|
||||
|
||||
**Tech Stack:** React 19 + TypeScript 5.9 + Vite 7 + FlowMind Token 设计系统 + Node.js 内置 Test Runner (`tsx --test`) + Vitest
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- 严禁把所有改动揉合成单次庞大提交,严格执行分层渐进式提交:`feat(rbac)`, `feat(web)`, `test(rbac)`, `docs(test)`.
|
||||
- 纯函数逻辑优先:权限判定流水线与单文档覆盖必须在纯函数中完成计算并实现 100% 单元测试覆盖,严禁副作用侵入基础组件.
|
||||
- 三层交付物隔离红线:`private` 文档除创建者本人外绝对禁止任何人查阅(即使是 ADMIN 或单文档覆盖也不能穿透隐私隔离).
|
||||
- 文档三权流转纯净性:受控工作流交付物(`workflow`)必须保持严格法定三权流转,单文档覆盖仅影响“可否查阅”,不可篡改生命周期状态机.
|
||||
- 测试报告归档必须存放于 `.doc/test-reports/` 规范目录下.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 定义 RBAC 数据契约与交付物/用户扩展类型 (Data Contracts & Types)
|
||||
|
||||
**Files:**
|
||||
- Create: `web/src/types/rbac.ts`
|
||||
- Modify: `web/src/types/docgov.ts:20-33`
|
||||
- Modify: `web/src/types/workbench.ts:95-117`
|
||||
- Test: `web/src/engine/rbac.test.ts` (将在 Task 2 建立完整测试)
|
||||
|
||||
**Interfaces:**
|
||||
- Produces:
|
||||
- `PermissionKey`: `'project:create' | 'project:assign_lead' | 'perm:manage' | 'workflow:config_visibility' | 'doc:override_visibility' | 'doc:export' | 'workflow:view_all'`
|
||||
- `RoleDefinition`: `{ id: string; name: string; code: string; description: string; isSystem?: boolean; permissions: PermissionKey[]; createdAt: string; updatedAt: string; }`
|
||||
- `VisibilityMode`: `'inherit' | 'role_whitelist' | 'designated_only' | 'public'`
|
||||
- `DocVisibilityRule`: `{ mode: VisibilityMode; allowedRoleIds?: string[]; allowedUserIds?: number[]; overrideReason?: string; configuredBy?: string; configuredAt?: string; }`
|
||||
- `DeliverableItem.visibilityRule?: DocVisibilityRule`
|
||||
- `UserProfile.roleId: string`
|
||||
|
||||
- [ ] **Step 1: 创建 `web/src/types/rbac.ts` 类型契约文件**
|
||||
|
||||
```typescript
|
||||
import { DocPermissionRole } from './docgov';
|
||||
|
||||
export type PermissionKey =
|
||||
| 'project:create' // 创建新项目/立项
|
||||
| 'project:assign_lead' // 设置/变更文档责任人(编制/审核/批准)
|
||||
| 'perm:manage' // 系统权限与角色管理配置
|
||||
| 'workflow:config_visibility' // 配置工作流默认可见性
|
||||
| 'doc:override_visibility' // 配置单文档可见性覆盖
|
||||
| 'doc:export' // 导出受控交付物(DOCX/XLSX)
|
||||
| 'workflow:view_all'; // 默认查阅常规工作流文档
|
||||
|
||||
export interface RoleDefinition {
|
||||
id: string; // 唯一标识:如 'role-admin', 'role-director', 'role-engineer'
|
||||
name: string; // 显示名称:如 "系统管理员", "研发总监", "方案工程师"
|
||||
code: string; // 唯一代码:如 "ADMIN", "DIRECTOR", "ENGINEER"
|
||||
description: string; // 职责描述
|
||||
isSystem?: boolean; // 系统内置防死锁标记 (内置角色不可被删除)
|
||||
permissions: PermissionKey[]; // 默认拥有的全局权限集
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export type VisibilityMode =
|
||||
| 'inherit' // 默认:继承工作流/阶段默认可见性
|
||||
| 'role_whitelist' // 覆盖:仅指定全局角色可见 (如仅总监、质保QA)
|
||||
| 'designated_only' // 覆盖:严格收紧,仅该文档当前的三权责任人可见
|
||||
| 'public'; // 覆盖:放宽,所有成员均可查阅
|
||||
|
||||
export interface DocVisibilityRule {
|
||||
mode: VisibilityMode;
|
||||
allowedRoleIds?: string[]; // 当 mode === 'role_whitelist' 时生效
|
||||
allowedUserIds?: number[]; // 特例用户白名单 (例如特聘临床专家)
|
||||
overrideReason?: string; // 覆盖原因说明 (合规留痕审计)
|
||||
configuredBy?: string; // 设置人姓名
|
||||
configuredAt?: string; // 设置时间
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 扩展 `web/src/types/docgov.ts` 中的 `UserProfile`**
|
||||
|
||||
为 `UserProfile` 添加 `roleId: string` 与可选 `customPermissions?: PermissionKey[]`。
|
||||
|
||||
- [ ] **Step 3: 扩展 `web/src/types/workbench.ts` 中的 `DeliverableItem`**
|
||||
|
||||
为 `DeliverableItem` 增加可选字段 `visibilityRule?: DocVisibilityRule`。
|
||||
|
||||
- [ ] **Step 4: 运行 `npm test` 验证类型定义向下兼容性**
|
||||
|
||||
Run: `npm test`
|
||||
Expected: 40 tests passed, 0 failures.
|
||||
|
||||
- [ ] **Step 5: 提交数据契约**
|
||||
|
||||
```bash
|
||||
git add web/src/types/rbac.ts web/src/types/docgov.ts web/src/types/workbench.ts
|
||||
git commit -m "feat(rbac): define rbac data contracts and extend deliverable and user types"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 实现权限判定纯函数引擎与全量单元测试 (Permission Engine & Unit Tests)
|
||||
|
||||
**Files:**
|
||||
- Create: `web/src/engine/rbac.ts`
|
||||
- Create: `web/src/engine/rbac.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces:
|
||||
- `DEFAULT_ROLES: RoleDefinition[]`
|
||||
- `hasPermission(user: UserProfile, roles: RoleDefinition[], permKey: PermissionKey): boolean`
|
||||
- `isDeliverableVisible(user: UserProfile, roles: RoleDefinition[], doc: DeliverableItem): boolean`
|
||||
- `filterVisibleDeliverablesWithRBAC(deliverables: DeliverableItem[], user: UserProfile, roles: RoleDefinition[]): DeliverableItem[]`
|
||||
- `canPerformDocAction(action: 'assign_lead' | 'override_visibility' | 'create_project', user: UserProfile, roles: RoleDefinition[]): boolean`
|
||||
|
||||
- [ ] **Step 1: 编写单元测试 `web/src/engine/rbac.test.ts` (覆盖 8 大核心场景)**
|
||||
|
||||
测试清单:
|
||||
1. 默认系统角色与自定义角色权限解析
|
||||
2. 超级管理员 (ADMIN) 与具备 `perm:manage` 用户的通配豁免特权
|
||||
3. 工作流基线可见性 (`workflow:view_all`) 判定
|
||||
4. 单文档覆盖:`designated_only`(仅编制/审核/批准人可见,其他用户被拦截)
|
||||
5. 单文档覆盖:`role_whitelist`(仅指定角色可见,白名单外角色被拦截)
|
||||
6. 单文档覆盖:`public`(放宽可见性,无 `workflow:view_all` 权限的普通访客也能查阅)
|
||||
7. 私密文档隔离强红线:`category === 'private'` 无论任何管理员或单文档覆盖,非创建者本人绝对不可见
|
||||
8. 核心业务动作权限拦截:`project:create` 与 `project:assign_lead`
|
||||
|
||||
- [ ] **Step 2: 运行测试验证失败 (TDD 红灯)**
|
||||
|
||||
Run: `npx tsx --test web/src/engine/rbac.test.ts`
|
||||
Expected: FAIL with "Cannot find module '../engine/rbac'".
|
||||
|
||||
- [ ] **Step 3: 编写 `web/src/engine/rbac.ts` 纯函数引擎**
|
||||
|
||||
实现 `DEFAULT_ROLES` 初始预置角色(管理员、研发总监、主管、方案工程师、外聘访客),实现 `hasPermission`、`isDeliverableVisible` 与 5 步决策流水线。
|
||||
|
||||
- [ ] **Step 4: 运行测试验证通过 (TDD 绿灯)**
|
||||
|
||||
Run: `npx tsx --test web/src/engine/rbac.test.ts`
|
||||
Expected: PASS all 8 test cases.
|
||||
|
||||
- [ ] **Step 5: 提交权限引擎**
|
||||
|
||||
```bash
|
||||
git add web/src/engine/rbac.ts web/src/engine/rbac.test.ts
|
||||
git commit -m "feat(rbac): implement permission evaluation engine and unit test suite"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 升级系统设置面板实现动态角色 CRUD 与权限配置 (SettingsModal UI)
|
||||
|
||||
**Files:**
|
||||
- Modify: `web/src/components/user/SettingsModal.tsx`
|
||||
- Test: 手动与集成测试验证
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- `RoleDefinition`, `PermissionKey` from `web/src/types/rbac`
|
||||
- `DEFAULT_ROLES` from `web/src/engine/rbac`
|
||||
- Produces:
|
||||
- `SettingsModalProps` 增加 `roles: RoleDefinition[]`, `onSaveRoles: (roles: RoleDefinition[]) => void`, `users: UserProfile[]`, `currentUser: UserProfile`, `onUpdateUserRole: (userId: number, roleId: string) => void`, `onSwitchUser: (user: UserProfile) => void`
|
||||
|
||||
- [ ] **Step 1: 扩展 `SettingsModalProps` 接口**
|
||||
|
||||
增加角色与用户管理相关的回调属性与状态绑定。
|
||||
|
||||
- [ ] **Step 2: 在 `SettingsModal.tsx` 中实现双栏管理布局**
|
||||
|
||||
- 左栏:角色列表(展示内置角色徽章、自定义角色,底部提供「+ 新增自定义角色」按钮与删除按钮);
|
||||
- 右栏:
|
||||
- 角色基本信息(名称、代码、描述);
|
||||
- 7 大原子权限项复选矩阵(点击实时勾选/解绑,系统角色 ADMIN 默认只读全选);
|
||||
- 用户角色委派与当前登录人快速切换区(将张工、李主管、王总监快速分配给不同角色,一键切换测试)。
|
||||
|
||||
- [ ] **Step 3: 增加 localStorage 持久化支持**
|
||||
|
||||
在 `web/src/data/storage.ts` 或组件状态中支持 `loadRoles()` 与 `saveRoles()`,确保刷新浏览器后新增角色与权限配置不丢失。
|
||||
|
||||
- [ ] **Step 4: 运行前端构建与既有测试检验语法**
|
||||
|
||||
Run: `npm test`
|
||||
Expected: All tests pass.
|
||||
|
||||
- [ ] **Step 5: 提交系统设置动态角色面板**
|
||||
|
||||
```bash
|
||||
git add web/src/components/user/SettingsModal.tsx web/src/data/storage.ts
|
||||
git commit -m "feat(web): upgrade settings modal with dynamic roles CRUD and permission matrix"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 实现单文档可见性覆盖弹窗与大盘徽章联动 (DocVisibilityModal UI)
|
||||
|
||||
**Files:**
|
||||
- Create: `web/src/components/doc/DocVisibilityModal.tsx`
|
||||
- Modify: `web/src/components/doc/DocGovActionBar.tsx:270-340`
|
||||
- Modify: `web/src/components/doc/DeckDrawer.tsx:390-430`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- `DocVisibilityRule`, `VisibilityMode`, `RoleDefinition` from `web/src/types/rbac`
|
||||
- `DeliverableItem` from `web/src/types/workbench`
|
||||
- `hasPermission` from `web/src/engine/rbac`
|
||||
- Produces:
|
||||
- `<DocVisibilityModal isOpen={...} onClose={...} doc={...} roles={...} onSaveRule={(rule) => ...} />`
|
||||
- `DocGovActionBar` 中的「🔒 可见性覆盖」按钮与状态提示
|
||||
- `DeckDrawer` 卡片中的「🔒 覆盖受控」彩色角标
|
||||
|
||||
- [ ] **Step 1: 编写 `web/src/components/doc/DocVisibilityModal.tsx`**
|
||||
|
||||
包含 4 种覆盖模式单选、白名单角色勾选列表、覆盖原因输入框、保存与清除覆盖规则按钮。
|
||||
|
||||
- [ ] **Step 2: 在 `DocGovActionBar.tsx` 中增加权限覆盖操作入口**
|
||||
|
||||
根据当前用户是否具备 `doc:override_visibility` 权限(或管理员),在受控工作流交付物操作栏呈现【🔒 可见性覆盖】按钮。若当前文档已设置覆盖规则,展示明显的模式标签(如“仅三权责任人可见”)。
|
||||
|
||||
- [ ] **Step 3: 在 `DeckDrawer.tsx` 交付物大盘卡片增加覆盖标记**
|
||||
|
||||
若卡片文档存在 `visibilityRule && visibilityRule.mode !== 'inherit'`,渲染醒目的黄色/紫色安全微标:`🔒 仅责任人可见` 或 `🔒 角色白名单`。
|
||||
|
||||
- [ ] **Step 4: 运行测试确保无渲染与类型破坏**
|
||||
|
||||
Run: `npm test`
|
||||
Expected: All tests pass.
|
||||
|
||||
- [ ] **Step 5: 提交单文档可见性覆盖组件与卡片徽章**
|
||||
|
||||
```bash
|
||||
git add web/src/components/doc/DocVisibilityModal.tsx web/src/components/doc/DocGovActionBar.tsx web/src/components/doc/DeckDrawer.tsx
|
||||
git commit -m "feat(web): add doc visibility override modal and badges in deck drawer"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 全局集成、状态持久化与关键受控动作拦截 (Global Integration & Interception)
|
||||
|
||||
**Files:**
|
||||
- Modify: `web/src/App.tsx`
|
||||
- Modify: `web/src/components/layout/LeftRail.tsx:65-90`
|
||||
- Modify: `web/src/components/user/UserProjectRightsModal.tsx:450-480`
|
||||
- Test: `web/src/engine/rbacIntegration.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- `isDeliverableVisible`, `hasPermission`, `filterVisibleDeliverablesWithRBAC`
|
||||
- `DocVisibilityModal`, `SettingsModal`
|
||||
- Produces:
|
||||
- 核心动作受控拦截:「新建立项会话」无 `project:create` 权限时禁用并提示;
|
||||
- 核心动作受控拦截:「指派文档责任人」无 `project:assign_lead` 权限时选择器锁定只读;
|
||||
- 实时可见性过滤:配置单文档覆盖后,大盘、左侧目录与当前激活文档实时响应隐藏与自动跳选。
|
||||
|
||||
- [ ] **Step 1: 在 `web/src/App.tsx` 中初始化角色状态与可见性计算**
|
||||
|
||||
使用 `loadRoles()` 初始化 `roles` 状态;将 `visibleDeliverables` 过滤逻辑升级为调用 `filterVisibleDeliverablesWithRBAC(currentProjectDeliverables, currentUser, roles)`。
|
||||
|
||||
- [ ] **Step 2: 在 `LeftRail.tsx` 拦截「新建立项会话」**
|
||||
|
||||
判定 `hasPermission(currentUser, roles, 'project:create')`。若无权限,按钮禁用、透明度降低,悬停提示:“当前角色 [xxx] 无权发起新研发项目”。
|
||||
|
||||
- [ ] **Step 3: 在 `UserProjectRightsModal.tsx` 拦截「指派文档负责人」**
|
||||
|
||||
判定 `hasPermission(currentUser, roles, 'project:assign_lead')`。若无权限,责任人下拉选择器置为 `disabled`,悬停提示:“当前角色无权配置文档法定职责”。
|
||||
|
||||
- [ ] **Step 4: 编写全链路集成测试 `web/src/engine/rbacIntegration.test.ts`**
|
||||
|
||||
覆盖全流程联动测试:
|
||||
1. 动态新增自定义角色 "外聘合规审计员" 并赋予指定权限;
|
||||
2. 为某份工作流文档设置“仅三权责任人可见”单文档覆盖;
|
||||
3. 切换登录用户为不同全局角色,断言可见列表、创建项目权限与指派负责人权限均严格受控。
|
||||
|
||||
- [ ] **Step 5: 运行全量测试**
|
||||
|
||||
Run: `npm test`
|
||||
Expected: All tests pass.
|
||||
|
||||
- [ ] **Step 6: 提交全局集成与受控拦截**
|
||||
|
||||
```bash
|
||||
git add web/src/App.tsx web/src/components/layout/LeftRail.tsx web/src/components/user/UserProjectRightsModal.tsx web/src/engine/rbacIntegration.test.ts
|
||||
git commit -m "feat(web): wire rbac permission enforcement into left rail and rights modal"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: 执行全量自动化回归与归档测试报告 (Test Suite & Report Archival)
|
||||
|
||||
**Files:**
|
||||
- Create: `.doc/test-reports/2026-09-08-dynamic-roles-and-doc-visibility-rbac-test-report.md`
|
||||
|
||||
- [ ] **Step 1: 运行全量测试并捕获控制台输出**
|
||||
|
||||
Run: `npm test`
|
||||
Expected: 100% pass across all test files.
|
||||
|
||||
- [ ] **Step 2: 撰写标准化测试报告**
|
||||
|
||||
严格遵循 `test-reports-standard.mdc` 模板结构,录入:
|
||||
- 背景与目标
|
||||
- 测试方案与环境
|
||||
- 8 大单元用例 + 3 大全链路集成用例真实输入/输出/判定
|
||||
- 终端运行耗时统计与测试结论
|
||||
|
||||
- [ ] **Step 3: 提交测试报告与更新文档**
|
||||
|
||||
```bash
|
||||
git add .doc/test-reports/2026-09-08-dynamic-roles-and-doc-visibility-rbac-test-report.md
|
||||
git commit -m "test(rbac): archive dynamic roles and doc visibility rbac test report"
|
||||
```
|
||||
Reference in New Issue
Block a user