Files
AIclinicalresearch/docs/03-业务模块/IIT Manager Agent/04-开发计划/V3.0全新开发计划/用户权限与多租户三阶段实施计划.md
HaHafeng 0b29fe88b5 feat(iit): QC deep fix + V3.1 architecture plan + project member management
QC System Deep Fix:
- HardRuleEngine: add null tolerance + field availability pre-check (skipped status)
- SkillRunner: baseline data merge for follow-up events + field availability check
- QcReportService: record-level pass rate calculation + accurate LLM XML report
- iitBatchController: legacy log cleanup (eventId=null) + upsert RecordSummary
- seed-iit-qc-rules: null/empty string tolerance + applicableEvents config

V3.1 Architecture Design (docs only, no code changes):
- QC engine V3.1 plan: 5-level data structure (CDISC ODM) + D1-D7 dimensions
- Three-batch implementation strategy (A: foundation, B: bubbling, C: new engines)
- Architecture team review: 4 whitepapers reviewed + feedback doc + 4 critical suggestions
- CRA Agent strategy roadmap + CRA 4-tool explanation doc for clinical experts

Project Member Management:
- Cross-tenant member search and assignment (remove tenant restriction)
- IIT project detail page enhancement with tabbed layout (KB + members)
- IitProjectContext for business-side project selection
- System-KB route access control adjustment for project operators

Frontend:
- AdminLayout sidebar menu restructure
- IitLayout with project context provider
- IitMemberManagePage new component
- Business-side pages adapt to project context

Prisma:
- 2 new migrations (user-project RBAC + is_demo flag)
- Schema updates for project member management

Made-with: Cursor
2026-03-01 15:27:05 +08:00

16 KiB
Raw Permalink Blame History

CRA Agent V3.0 — 用户权限与多租户三阶段实施计划

版本: v1.0
日期: 2026-02-28
状态: 待实施
前置依赖: P0 + P1 已完成(质控流水线 + ChatOrchestrator
关联文档:


1. 问题背景

1.1 当前系统存在的三个核心问题

问题 A业务端 CRA 质控平台无法运行

  • 所有业务端页面驾驶舱、eQuery、报告、AI 对话)从 URL 参数 ?projectId=xxx 获取项目 ID
  • 没有任何机制把登录用户与 IIT 项目关联,导致页面显示"请先选择一个项目"
  • 侧边栏项目信息为硬编码假数据("IIT-2026-001"

问题 B运营管理端 IIT 项目管理定位不当

  • "IIT 项目管理"与"Prompt 管理""租户管理""用户管理"混在同一菜单中
  • 普通项目运营人员不应看到平台级管理功能
  • 药企/医院客户的项目管理人员不应看到其他企业的项目

问题 C用户-项目关联机制缺失

  • IitUserMapping.systemUserId 存储的是随意字符串(当前值为 "FengZhiBo"),未关联平台 User
  • IitProject 没有 tenantId 字段,无法实现租户隔离
  • IIT API 路由没有认证中间件,无访问控制

1.2 当前数据库实际状态

-- iit_schema.projects1 条记录)
id: test0102-pd-study | name: test0207 | status: active

-- iit_schema.user_mappings1 条记录)
system_user_id: FengZhiBo | wecom_user_id: FengZhiBo | role: PI

-- public.users1 条记录)
id: user-mock-001 | name: 测试用户 | role: user
(注:此用户为占位假数据,非真实用户)

两张表之间没有任何外键关联。

1.3 当前角色体系

平台级角色public.users.role

角色 说明 当前使用
SUPER_ADMIN 平台超级管理员 可访问运营管理端全部功能
PROMPT_ENGINEER Prompt 工程师 可访问运营管理端
HOSPITAL_ADMIN 医院管理员 已定义,未使用
PHARMA_ADMIN 药企管理员 已定义,未使用
DEPARTMENT_ADMIN 科室管理员 已定义,未使用
USER 普通用户 默认角色

IIT 项目级角色iit_schema.user_mappings.role

角色 说明 当前使用
PI 主要研究者 已使用
Sub-I 次要研究者 已定义
CRC 临床研究协调员 已定义
CRA 临床监查员 已定义
DM 数据管理员 已定义
Statistician 统计师 已定义
Other 其他 已定义

缺失的角色:

角色 层级 说明
PM IIT 项目级 项目管理员,负责项目配置和管理
IIT_OPERATOR 平台级 IIT 项目运营负责为客户创建和配置项目Phase 2 实现)

2. 三阶段实施计划

Phase 1立即       Phase 2近期           Phase 3中期
让业务端能跑           用户-项目关联              多租户隔离
───────────────── → ──────────────────── → ─────────────────
自动选中活跃项目       systemUserId 关联 User    IitProject 加 tenantId
Provider 注入上下文    /my-projects API          项目按租户过滤
管理端侧边栏分组       项目角色权限矩阵          PHARMA_ADMIN 自助管理
配置功能补全           IIT 路由加认证
                      IIT_OPERATOR 平台角色

3. Phase 1让业务端能跑预估 0.5 天)

3.1 目标

  • CRA 质控平台业务端页面能正常加载和显示数据
  • 运营管理端 IIT 项目管理菜单位置合理
  • 项目配置功能补全(定时质控、变量清单)

3.2 方案

3.2.1 创建 IitProjectContext Provider

设计原则: 通用方案,适用于用户关联 0 / 1 / N 个项目的所有场景。

核心逻辑:

用户进入 /iit → IitProjectProvider 初始化
  → 调用 GET /api/v1/admin/iit-projects 获取项目列表
  → 过滤 status = 'active'
  → 0 个 → 显示空状态页:"暂无关联的 IIT 项目"
  → 1 个 → 自动选中,不弹选择器
  → N 个 → 恢复 localStorage 上次选择;若无记录,默认选第一个
  → 用户可随时通过侧边栏顶部下拉选择器切换项目
  → 切换后写入 localStorage子页面自动刷新
  → 通过 useIitProject() hook 暴露:
      { projectId, project, projects, loading, switchProject(id) }

项目选择器 UI

放在 IitLayout 侧边栏顶部(替换当前硬编码的项目名称),具体表现:

  • 1 个项目:显示项目名称(纯文本,无下拉箭头)
  • N 个项目:显示当前项目名 + 下拉箭头,点击弹出 Select 选择器
  • 选择器选项:项目名称 + 项目编号(如 "原发性痛经队列研究 / IIT-2026-001"
  • 切换项目后,所有子页面通过 Context 自动获取新 projectId 并刷新数据

改动文件:

文件 改动
frontend-v2/src/modules/iit/context/IitProjectContext.tsx 新建 Context + Provider + useIitProject hook
frontend-v2/src/modules/iit/IitLayout.tsx 集成 Provider侧边栏顶部改为项目选择器
frontend-v2/src/modules/iit/pages/DashboardPage.tsx 删除 URL 参数读取,改用 useIitProject()
frontend-v2/src/modules/iit/pages/EQueryPage.tsx 同上
frontend-v2/src/modules/iit/pages/ReportsPage.tsx 同上
frontend-v2/src/modules/iit/pages/AiStreamPage.tsx 同上
frontend-v2/src/modules/iit/pages/AiChatPage.tsx 同上

3.2.2 管理端侧边栏三区重组(方案 B逻辑拆分

决策背景: 概念上存在三种管理职能(平台管理、项目运营、商务运营),但当前阶段团队规模小,同一人可能跨职能操作。采用方案 B逻辑拆分:保留单一 /admin 入口,侧边栏按职能分为三个带标题的菜单组,通过 RBAC 控制每个角色看到哪些组。未来用户群体分化后可平滑升级为物理拆分(独立路由 + 独立 Layout

侧边栏结构SUPER_ADMIN 视角,看到全部):

┌─ 平台管理 ─────────────┐
│  运营概览               │
│  Prompt 管理            │
│  系统知识库             │
│  LLM 配置              │
│  系统设置              │
├─ 项目运营 ─────────────┤
│  IIT 项目管理           │
├─ 商务运营 ─────────────┤
│  租户管理              │
│  用户管理              │
└────────────────────────┘

各角色可见性:

菜单组 SUPER_ADMIN PROMPT_ENGINEER IIT_OPERATOR PHARMA_ADMIN
平台管理 全部 Prompt 管理 + 系统知识库 - -
项目运营 全部项目 - 全部项目 本租户项目
商务运营 全部 - - -

改动文件: frontend-v2/src/framework/layout/AdminLayout.tsx

3.2.3 项目配置功能补全

A. 定时质控配置 UI

数据库 iit_schema.projects 已有 cron_enabledcron_expression 字段,前端未暴露。

IitProjectDetailPage.tsx 的"REDCap 配置"Tab 中增加:

  • 定时质控开关Switch绑定 cronEnabled
  • Cron 表达式输入Input + 预设选项:"每天 8:00" / "每周一 9:00" / 自定义)

B. 变量清单 Tab

后端 GET /:id/field-metadata API 已存在。在 IitProjectDetailPage.tsx 新增第 5 个 Tab"变量清单",展示 REDCap 变量表格。

C. PM 角色新增

iitUserMappingService.tsgetRoleOptions() 中添加:

{ value: 'PM', label: '项目管理员 (PM)' }

3.3 Phase 1 不做的事

  • 不改数据库 Schema
  • 不做用户-项目关联systemUserId 改造)
  • 不加认证中间件
  • 不做租户隔离

4. Phase 2用户-项目关联 + 角色权限(预估 2 天)

4.1 目标

  • 登录用户自动看到自己关联的 IIT 项目
  • IIT 项目角色对应明确的权限
  • IIT API 路由有认证保护
  • 运营管理端按角色控制菜单可见性
  • 新增 IIT_OPERATOR 平台角色,使项目运营人员无需 SUPER_ADMIN 权限即可创建和配置 IIT 项目

4.2 数据模型改动

4.2.1 IitUserMapping 增强

model IitUserMapping {
  // ... 现有字段 ...
  systemUserId  String     @map("system_user_id")  // 改为必须是 User.id
  // 新增:
  userId        String?    @map("user_id")          // 平台 User 表外键(可选,渐进式关联)
  
  // 新增关联
  user          User?      @relation(fields: [userId], references: [id])
}

迁移策略:

  • 新增 userId 字段nullable不破坏现有数据
  • 新建用户映射时要求填写真实 userId
  • 旧数据逐步补齐

4.2.2 IitProject 增强(为 Phase 3 预留)

model IitProject {
  // ... 现有字段 ...
  // 新增:
  tenantId      String?    @map("tenant_id")        // 租户归属Phase 3 正式启用)
}

4.3 API 改动

4.3.1 新增接口

GET /api/v1/iit/my-projects

逻辑:

  1. 从 JWT Token 获取当前用户 userId
  2. 查询 IitUserMapping WHERE userId = :userId
  3. 返回关联的项目列表 + 用户在每个项目中的角色

响应示例:

{
  "projects": [
    {
      "id": "test0102-pd-study",
      "name": "test0207",
      "status": "active",
      "myRole": "PI",
      "description": "原发性痛经队列研究"
    }
  ]
}

4.3.2 IIT 路由加认证

所有 /api/v1/admin/iit-projects 路由添加 authenticate 中间件。

4.3.3 项目级权限检查

中间件requireProjectRole(projectId, allowedRoles)
  → 查 IitUserMapping WHERE projectId AND userId
  → 检查 role 是否在 allowedRoles 中

4.4 项目角色权限矩阵

功能 PM PI CRA CRC DM Sub-I Statistician
查看驾驶舱
查看/处理 eQuery 读写 读写 读写 -
查看报告
AI 对话
项目配置REDCap/规则/通知/知识库) 读写 - - - - - -
查看变量清单
管理质控规则 读写 - - - -

4.5 管理端菜单权限(承接 Phase 1 三区分组)

Phase 1 已完成侧边栏三区分组的 UI 结构Phase 2 加入真正的 RBAC 控制:

角色 可进入 /admin 平台管理 项目运营 商务运营
SUPER_ADMIN 全部 全部项目 全部
PROMPT_ENGINEER Prompt + 知识库 - -
IIT_OPERATOR本阶段新增 - 全部项目 -
PHARMA_ADMIN - 本租户项目 -
HOSPITAL_ADMIN - 本租户项目 -
USER - - -

实现方式:

  • 路由守卫:/admin 入口检查 user.role 是否在允许列表中
  • 侧边栏渲染:根据 user.role 过滤 menuItems,角色看不到的组直接不渲染
  • API 层:每个管理端 API 添加 authenticate + requireRole(allowedRoles) 中间件

4.6 前端改动

  • IitProjectContext 改为调用 /api/v1/iit/my-projects
  • 根据 myRole 控制业务端 Tab 可见性PM 看到更多设置入口)
  • AdminLayout.tsxuser.role 过滤侧边栏菜单组可见性Phase 1 已分组,此处加权限判断)
  • /admin 路由入口添加角色守卫

5. Phase 3多租户隔离预估 1.5 天)

5.1 目标

  • IIT 项目按租户隔离,药企只能看到自己的项目
  • PHARMA_ADMIN 可在运营管理端管理自己租户的 IIT 项目
  • SUPER_ADMIN 可跨租户查看所有项目

5.2 数据模型

启用 Phase 2 预留的 tenantId 字段,设为必填:

model IitProject {
  tenantId  String  @map("tenant_id")
  tenant    Tenant  @relation(fields: [tenantId], references: [id])
}

5.3 API 改动

所有项目查询接口添加租户过滤:

-- 非 SUPER_ADMIN
SELECT * FROM iit_schema.projects WHERE tenant_id = :currentUserTenantId

-- SUPER_ADMIN
SELECT * FROM iit_schema.projects  -- 无限制

5.4 项目创建流程

Phase 2 完成后:
  SUPER_ADMIN 或 IIT_OPERATOR 创建项目 → 手动指定 tenantId选择为哪个客户创建

Phase 3 完成后(客户自助):
  PHARMA_ADMIN 创建项目 → 自动绑定自己的 tenantId

5.5 前端改动

  • 运营管理端项目列表SUPER_ADMIN 看到全部 + 租户筛选器PHARMA_ADMIN 只看到自己的
  • 项目创建表单SUPER_ADMIN 需选择租户PHARMA_ADMIN 自动绑定

6. 实施优先级总结

阶段 核心内容 预估工时 数据库改动 前置条件
Phase 1 Provider + 管理端分组 + 配置补全 0.5 天
Phase 2 userId 关联 + /my-projects + 角色权限 + 认证 + IIT_OPERATOR 角色 2 天 新增 userId 列、tenantId 列、IIT_OPERATOR 角色枚举 Phase 1
Phase 3 租户隔离 + PHARMA_ADMIN 自助 1.5 天 tenantId 改为必填 Phase 2

Phase 1 立即可执行的原因

  • 0 数据库改动
  • 只改前端代码
  • 当前只有 1 个活跃项目 + 1 个测试用户,自动选中即可
  • 让业务端立即可演示

Phase 2 的触发条件

  • 有真实用户需要登录系统
  • 需要区分不同用户看到不同项目
  • 需要保护 API 安全

Phase 3 的触发条件

  • 有多个客户(药企/医院)同时使用系统
  • 需要租户级别的数据隔离

7. 附录:改动文件清单

Phase 1

文件 类型 说明
frontend-v2/src/modules/iit/context/IitProjectContext.tsx 新建 项目上下文 Provider
frontend-v2/src/modules/iit/IitLayout.tsx 修改 集成 Provider + 真实项目信息
frontend-v2/src/modules/iit/pages/DashboardPage.tsx 修改 改用 useIitProject()
frontend-v2/src/modules/iit/pages/EQueryPage.tsx 修改 改用 useIitProject()
frontend-v2/src/modules/iit/pages/ReportsPage.tsx 修改 改用 useIitProject()
frontend-v2/src/modules/iit/pages/AiStreamPage.tsx 修改 改用 useIitProject()
frontend-v2/src/modules/iit/pages/AiChatPage.tsx 修改 改用 useIitProject()
frontend-v2/src/framework/layout/AdminLayout.tsx 修改 侧边栏分组
frontend-v2/src/modules/admin/pages/IitProjectDetailPage.tsx 修改 定时质控配置 + 变量清单 Tab
backend/src/modules/admin/iit-projects/iitUserMappingService.ts 修改 添加 PM 角色

Phase 2

文件 类型 说明
backend/prisma/schema.prisma 修改 IitUserMapping 加 userId、IitProject 加 tenantId
backend/src/modules/iit-manager/routes/index.ts 修改 加 /my-projects 路由 + authenticate 中间件
backend/src/common/auth/auth.middleware.ts 修改 新增 requireProjectRole 中间件
backend/prisma/schema.prisma (Role enum) 修改 新增 IIT_OPERATOR 角色枚举值
frontend-v2/src/modules/iit/context/IitProjectContext.tsx 修改 改调 /my-projects
frontend-v2/src/framework/layout/AdminLayout.tsx 修改 按角色控制菜单组可见性IIT_OPERATOR 只看项目运营)

Phase 3

文件 类型 说明
backend/prisma/schema.prisma 修改 tenantId 改为必填
backend/src/modules/admin/iit-projects/iitProjectService.ts 修改 查询加租户过滤
frontend-v2/src/modules/admin/pages/IitProjectListPage.tsx 修改 租户筛选器
frontend-v2/src/modules/admin/pages/IitProjectDetailPage.tsx 修改 创建时选择租户