# **AIclinicalresearch 权限与角色体系梳理报?* > **文档版本?* v1.1(整合Prompt管理需求) > **创建日期?* 2026-01-11 > **最后更新:** 2026-01-11 > **作者:** AI架构? > **目的?* 系统性梳理当前权限实现状况,为运营管理端和机构管理端开发做准备 > **变更说明?* 整合反馈建议 + Prompt管理系统需? --- ## 📋 目录 1. [当前系统状态分析](#1-当前系统状态分? 2. [数据库层面梳理](#2-数据库层面梳? 3. [后端权限实现梳理](#3-后端权限实现梳理) 4. [前端权限实现梳理](#4-前端权限实现梳理) 5. [差距分析](#5-差距分析) 6. [新PRD需求解读](#6-新prd需求解? 7. [架构设计建议](#7-架构设计建议) 8. [实施路线图](#8-实施路线? 9. [🆕 Prompt管理系统整合](#9-prompt管理系统整合) 10. [🆕 反馈采纳说明](#10-反馈采纳说明) --- ## 1. 当前系统状态分? ### 1.1 核心发现 🔍 **?已有基础**? - 数据库有基础的User表(`platform_schema.users` ?`public.users`两个版本? - 有基本的role字段(默认值:"user"? - 前端有权限框架(`PermissionContext`),?*仅mock数据** - 后端**完全没有认证/授权系统** **?缺失关键能力**? 1. **没有登录/注册API** 2. **没有JWT认证中间?* 3. **没有租户(Tenant)体系** 4. **没有角色权限系统(RBAC)** 5. **没有Feature Flag控制** 6. **没有审计日志系统** **🎯 当前状?*? - 系统处于**单测试账?*阶段 - 所有API都是**无认证、无鉴权**状? - 前端权限控制?*纯展示?*的mock实现 --- ## 2. 数据库层面梳? ### 2.1 当前User表结? #### **platform_schema.users** ?新架构(Prisma定义? ```prisma model User { id String @id @default(uuid()) email String @unique password String name String? avatarUrl String? @map("avatar_url") role String @default("user") // ⚠️ 简单字符串,不够用 status String @default("active") kbQuota Int @default(3) kbUsed Int @default(0) trialEndsAt DateTime? @map("trial_ends_at") isTrial Boolean @default(true) lastLoginAt DateTime? @map("last_login_at") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@schema("platform_schema") } ``` #### **public.users** ?旧表(历史遗留) ```prisma model users { id String email String @unique password String name String? avatar_url String? role String @default("user") // ⚠️ 同样简? status String @default("active") kb_quota Int @default(3) kb_used Int @default(0) // ... 其他字段 @@schema("public") } ``` **⚠️ 问题?* - 两个User表并存,命名不一致(users vs User? - `role`字段仅为字符串,无enum约束 - **没有租户关联字段(tenantId?* - **没有部门字段(department?* - **没有权限配置字段** ### 2.2 缺失的核心表 根据PRD需求,需要新增以下表? | 表名 | Schema位置 | 用?| 优先?| |------|-----------|------|--------| | **tenants** | platform_schema | 租户主表(医院、药企、期刊) | P0 | | **tenant_users** | platform_schema | 租户-用户关联?| P0 | | **departments** | platform_schema | 部门/科室?| P1 | | **feature_flags** | platform_schema | Feature Flag配置 | P0 | | **tenant_modules** | platform_schema | 租户订阅模块配置 | P0 | | **tenant_quotas** | platform_schema | 租户配额管理 | P1 | | **admin_operation_logs** | admin_schema | 运营操作日志 | P1 | **注意?* 当前有一个`AdminLog`表在`public`schema,但不完整? ### 2.3 已有的审计日? **IIT模块的审计日?* ?(可参考)? ```prisma model IitAuditLog { id String @id @default(uuid()) projectId String userId String actionType String entityType String entityId String details Json? traceId String createdAt DateTime @default(now()) @@schema("iit_schema") } ``` **可复用性:** ?架构设计优秀,可作为全局审计日志的参考? --- ## 3. 后端权限实现梳理 ### 3.1 认证系统状??**未实?* **搜索结果?* - ?没有找到 `/api/auth/login` ?`/api/auth/register` - ?没有JWT生成/验证工具 - ?没有认证中间件(?`requireAuth`? **对比其他项目**(从codebase_search结果): - ODJ项目有完整的Passport JWT认证 ? - BYSY项目有JWT认证中间?? - **本项目:完全空白** ? ### 3.2 授权系统状??**未实?* **缺失内容?* - ?没有角色检查中间件(如 `requireRole(['admin'])`? - ?没有权限映射表(ROLE_PERMISSIONS? - ?没有Feature Flag检查逻辑 **影响?* - 所有API端点都是公开的,无权限保? - 无法区分管理员和普通用? - 无法实现多租户数据隔? ### 3.3 当前API结构 **Legacy Routes** (无认?? ``` /api/v1/aia/* - AI智能问答(无权限检查) /api/v1/pkb/* - 个人知识库(无权限检查) /api/v1/rvw/* - 稿件审查(无权限检查) ``` **问题?* - 任何人都可以访问任何用户的数? - 没有 `userId` 鉴权逻辑 - 没有租户数据隔离 --- ## 4. 前端权限实现梳理 ### 4.1 权限框架存在 ?但仅为Mock **文件位置?* `frontend-v2/src/framework/permission/PermissionContext.tsx` **核心代码?* ```typescript // ⚠️ 硬编码为最高权限,仅供开发测? const MOCK_USER: UserInfo = { id: 'test-user-001', name: '测试研究?, email: 'test@example.com', version: 'premium', // 👈 硬编? avatar: null, isTrial: false, } // 权限检查函数(基于UserVersion等级? const checkModulePermission = (requiredVersion?: UserVersion): boolean => { if (!user) return false if (!requiredVersion) return true return checkVersionLevel(user.version, requiredVersion) } ``` **UserVersion定义?* ```typescript // framework/permission/types.ts export type UserVersion = 'free' | 'basic' | 'professional' | 'premium' ``` ### 4.2 权限检查逻辑 ?架构完整 **模块注册时的权限声明?* ```typescript // 模块定义接口 interface ModuleDefinition { id: string name: string path: string requiredVersion?: UserVersion // 🎯 权限要求 // ... } ``` **路由守卫?* ```typescript // RouteGuard.tsx if (module.requiredVersion && !checkModulePermission(module.requiredVersion)) { return } ``` **?优点?* - 权限框架设计完善 - 易于扩展到真实认? **?缺点?* - 用户信息完全hardcode - 没有对接后端API - 没有登录/登出UI --- ## 5. 差距分析 ### 5.1 与PRD需求的差距 | PRD需?| 当前状?| 差距 | 优先?| |---------|---------|------|--------| | **租户管理** | ??| 需完整实现Tenant体系 | P0 | | **4种角?* (SUPER_ADMIN/HOSPITAL_ADMIN/PHARMA_ADMIN/USER) | ?只有简单role字符?| 需RBAC体系 | P0 | | **品牌定制** (Logo/登录? | ??| 需tenant.config JSONB字段 | P0 | | **登录系统** | ??| 需JWT认证系统 | P0 | | **权限控制** | ?前端Mock / ?后端?| 需后端中间?| P0 | | **Feature Flag** | ??| 需配置?检查逻辑 | P0 | | **运营?* (/admin/*) | ??| 需全新开?| P0 | | **机构?* (/org/hospital/*, /org/pharma/*) | ??| 需全新开?| P1 | | **审计日志** | ⚠️ 仅IIT模块 | 需全局审计系统 | P1 | ### 5.2 架构层面差距 **当前架构?* 单用户、无租户、无权限 ``` User (单表) ? Projects/KnowledgeBases/... (直接关联 userId) ``` **目标架构?* 多租户、RBAC、数据隔? ``` Tenant (租户) ? Department (部门/科室) ? User (用户) + Role (角色) ? Projects/KnowledgeBases/... (tenant_id + user_id) ``` --- ## 6. 新PRD需求解? ### 6.1 核心角色定义(来自PRD v2.1? | 角色Code | 归属 | 权限范围 | URL前缀 | 核心职责 | |---------|------|---------|---------|---------| | **SUPER_ADMIN** | 平台 | 全局数据 | /admin | 租户开通、品牌配置、Prompt调优 | | **HOSPITAL_ADMIN** | 医院租户 | 本院数据 | /org/hospital | 科室管理、配额分?| | **PHARMA_ADMIN** | 药企租户 | 本企项目 | /org/pharma | 项目监控、CRO管理、审?| | **USER** | 任意租户 | 个人/被授权数?| /app | 科研业务操作 | ### 6.2 租户类型(Tenant Type? ```typescript enum TenantType { HOSPITAL = 'HOSPITAL', // 医院客户 PHARMA = 'PHARMA', // 药企客户 JOURNAL = 'JOURNAL', // 期刊客户 } ``` ### 6.3 品牌定制需?🆕 **URL策略?* ``` 通用登录:https://app.yizhengxun.com/auth/login 专属登录:https://app.yizhengxun.com/t/{tenant_code}/login ``` **租户配置(JSONB):** ```json { "branding": { "logoUrl": "https://oss.../jst_logo.png", "loginBackgroundUrl": "https://oss.../jst_bldg.jpg", "primaryColor": "#0056b3", "welcomeTitle": "北京积水潭医?AI 临床科研平台", "welcomeSubTitle": "智能?· 规范?· 高效? } } ``` ### 6.4 智能路由分发(登录后跳转? ```typescript function getRedirectPath(user, tenant) { if (user.role === 'SUPER_ADMIN') return '/admin/dashboard'; if (user.role === 'TENANT_ADMIN') { if (tenant.type === 'HOSPITAL') return '/org/hospital/dashboard'; if (tenant.type === 'PHARMA') return '/org/pharma/dashboard'; } if (tenant.type === 'JOURNAL') return '/app/rvw/dashboard'; return '/app/dashboard'; // 默认:普通用? } ``` --- ## 7. 架构设计建议 ### 7.1 数据库Schema设计 #### **7.1.1 platform_schema(平台核心表?* **A. tenants ?* (P0? ```prisma model Tenant { id String @id @default(uuid()) name String // 租户名称(如:北京积水潭医院? code String @unique // 租户代码(如:jst-hospital,用于URL? type TenantType // 租户类型:HOSPITAL/PHARMA/JOURNAL status String @default("active") // active/suspended/expired // 品牌配置(JSONB? config Json @default("{}") // branding配置、模块订阅等 // 配额管理 tokenQuota Int? // 总Token额度 tokenUsed Int @default(0) // 已使用Token // 时间? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt expiresAt DateTime? // 订阅到期时间 // 关系 users TenantUser[] departments Department[] modules TenantModule[] @@index([code]) @@index([type]) @@index([status]) @@map("tenants") @@schema("platform_schema") } enum TenantType { HOSPITAL PHARMA JOURNAL @@schema("platform_schema") } ``` **B. users 表扩?* (P0? ```prisma model User { id String @id @default(uuid()) email String @unique password String name String? avatarUrl String? @map("avatar_url") // 🆕 多租户支? tenantId String? @map("tenant_id") // 所属租户(NULL=平台管理员) departmentId String? @map("department_id") // 所属部?科室 // 🆕 角色系统 role UserRole // SUPER_ADMIN/TENANT_ADMIN/USER // 其他字段保持不变... status String @default("active") kbQuota Int @default(3) trialEndsAt DateTime? lastLoginAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // 关系 tenant Tenant? @relation(fields: [tenantId], references: [id]) department Department? @relation(fields: [departmentId], references: [id]) @@index([tenantId]) @@index([departmentId]) @@index([role]) @@map("users") @@schema("platform_schema") } enum UserRole { SUPER_ADMIN // 平台超级管理? TENANT_ADMIN // 租户管理员(医院/药企? USER // 普通用户(医生/研究员) @@schema("platform_schema") } ``` **C. tenant_members ?* (P0)✏?采纳反馈:改名为TenantMember ```prisma model TenantMember { id String @id @default(uuid()) tenantId String @map("tenant_id") userId String @map("user_id") role String // 在该租户中的角色 joinedAt DateTime @default(now()) @map("joined_at") tenant Tenant @relation(fields: [tenantId], references: [id]) @@unique([tenantId, userId]) @@map("tenant_members") // 语义更清? @@schema("platform_schema") } ``` **D. departments ?* (P1? ```prisma model Department { id String @id @default(uuid()) tenantId String @map("tenant_id") name String // 科室名称(如:心内科? parentId String? @map("parent_id") // 上级科室(支持树形结构) tokenQuota Int? @map("token_quota") // 科室Token额度 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation(fields: [tenantId], references: [id]) users User[] parent Department? @relation("DepartmentHierarchy", fields: [parentId], references: [id]) children Department[] @relation("DepartmentHierarchy") @@index([tenantId]) @@map("departments") @@schema("platform_schema") } ``` **E. feature_flags ?* (P0? ```prisma model FeatureFlag { id String @id @default(uuid()) featureKey String @unique @map("feature_key") // 功能标识(如:use_gpt_5? displayName String @map("display_name") description String? isEnabled Boolean @default(false) @map("is_enabled") targetRoles String[] @map("target_roles") // 允许的角色列? targetTenants String[] @default([]) @map("target_tenants") // 允许的租户ID列表 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("feature_flags") @@schema("platform_schema") } ``` **F. tenant_modules ?* (P0? ```prisma model TenantModule { id String @id @default(uuid()) tenantId String @map("tenant_id") moduleCode String @map("module_code") // 模块代码(ASL/DC/IIT等) isEnabled Boolean @default(true) @map("is_enabled") expiresAt DateTime? @map("expires_at") // 模块订阅到期时间 createdAt DateTime @default(now()) tenant Tenant @relation(fields: [tenantId], references: [id]) @@unique([tenantId, moduleCode]) @@map("tenant_modules") @@schema("platform_schema") } ``` **G. tenant_quota_allocations ?* (P0)?采纳反馈:精细化配额分配 ```prisma model TenantQuotaAllocation { id Int @id @default(autoincrement()) tenantId String @map("tenant_id") targetType String @map("target_type") // 'DEPARTMENT' | 'USER' targetKey String @map("target_key") // DepartmentID ?UserID limitAmount BigInt @map("limit_amount") // 分配的Token额度 usedAmount BigInt @default(0) @map("used_amount") // 已使? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([tenantId, targetType, targetKey]) @@index([tenantId]) @@index([targetType, targetKey]) @@map("tenant_quota_allocations") @@schema("platform_schema") } ``` **用途:** 医院端可以将总Token额度分配?心内?(Department)或"张医?(User? #### **7.1.2 admin_schema(运营管理)** **H. admin_operation_logs ?* (P1)✏?采纳反馈:增加module字段 ```prisma model AdminOperationLog { id Int @id @default(autoincrement()) adminId String @map("admin_id") operationType String @map("operation_type") // CREATE_TENANT/UPDATE_FEATURE_FLAG? targetType String @map("target_type") // tenant/user/config targetId String @map("target_id") module String? @map("module") // 🆕 所属模块(IIT/ASL/系统配置等) beforeData Json? @map("before_data") afterData Json? @map("after_data") ipAddress String? @map("ip_address") userAgent String? @map("user_agent") createdAt DateTime @default(now()) @@index([adminId]) @@index([operationType]) @@index([module]) // 🆕 药企端按模块查询 @@index([createdAt]) @@map("admin_operation_logs") @@schema("admin_schema") } ``` ### 7.2 后端API架构设计 #### **A. 认证系统** (P0? **路由?* `/api/v1/auth/*` ```typescript // backend/src/platform/auth/routes.ts POST /api/v1/auth/register // 用户注册 POST /api/v1/auth/login // 登录(返回JWT? POST /api/v1/auth/logout // 登出 POST /api/v1/auth/refresh // 刷新Token GET /api/v1/auth/me // 获取当前用户信息 ``` **JWT Payload结构?* ```typescript interface JWTPayload { userId: string email: string role: UserRole tenantId?: string tenantType?: TenantType exp: number // 过期时间 } ``` #### **B. 认证中间?* (P0? ```typescript // backend/src/common/middleware/auth.ts /** * JWT认证中间? * 验证Token并将用户信息挂载?req.user */ export const requireAuth = async (req, res, next) => { const token = extractToken(req) if (!token) return res.status(401).send({ error: 'Unauthorized' }) try { const payload = verifyJWT(token) req.user = await prisma.user.findUnique({ where: { id: payload.userId } }) if (!req.user) return res.status(401).send({ error: 'User not found' }) next() } catch (error) { return res.status(401).send({ error: 'Invalid token' }) } } /** * 角色权限中间? * 检查用户是否具有指定角? */ export const requireRole = (...allowedRoles: UserRole[]) => { return (req, res, next) => { if (!req.user) return res.status(401).send({ error: 'Unauthorized' }) if (!allowedRoles.includes(req.user.role)) { return res.status(403).send({ error: 'Forbidden' }) } next() } } /** * 租户数据隔离中间? * 确保用户只能访问自己租户的数? */ export const requireTenantAccess = (req, res, next) => { if (!req.user) return res.status(401).send({ error: 'Unauthorized' }) // SUPER_ADMIN可以访问所有租户数? if (req.user.role === 'SUPER_ADMIN') return next() // 其他用户只能访问自己租户的数? req.tenantId = req.user.tenantId next() } ``` #### **C. 运营管理端API** (P0? **路由?* `/api/v1/admin/*` ```typescript // 租户管理 POST /api/v1/admin/tenants // 创建租户 GET /api/v1/admin/tenants // 租户列表 GET /api/v1/admin/tenants/:id // 租户详情 PUT /api/v1/admin/tenants/:id // 更新租户 DELETE /api/v1/admin/tenants/:id // 删除租户 // Feature Flag管理 GET /api/v1/admin/feature-flags // 获取所有Feature Flag PUT /api/v1/admin/feature-flags/:key // 更新Feature Flag // 用户管理 GET /api/v1/admin/users // 全局用户列表 POST /api/v1/admin/users/:id/assign-tenant // 分配租户 ``` **权限要求?* 全部需?`requireRole('SUPER_ADMIN')` #### **D. 机构管理端API** (P1? **路由?* `/api/v1/org/*` ```typescript // 医院管理? GET /api/v1/org/hospital/departments // 科室列表 POST /api/v1/org/hospital/departments // 创建科室 GET /api/v1/org/hospital/members // 成员列表 POST /api/v1/org/hospital/members/import // 批量导入成员 // 药企管理? GET /api/v1/org/pharma/projects // 项目列表 GET /api/v1/org/pharma/audit-logs // 审计日志 ``` **权限要求?* `requireRole('TENANT_ADMIN')` + `requireTenantAccess` #### **E. 公开API** (P0? **路由?* `/api/public/*` ```typescript // 租户品牌配置(无需登录? GET /api/public/tenant-config?code={code} // 获取租户品牌配置 ``` ### 7.3 前端架构设计 #### **A. 认证模块** (P0? **目录结构?* ``` frontend-v2/src/modules/auth/ ├── pages/ ? ├── LoginPage.tsx # 通用登录? ? ├── TenantLoginPage.tsx # 租户专属登录页(动态品牌) ? └── RegisterPage.tsx # 注册? ├── api/ ? └── authApi.ts # 认证API调用 ├── hooks/ ? └── useAuth.ts # 认证Hook └── routes.tsx # 认证路由 ``` #### **B. 运营管理端模?* (P0? **目录结构?* ``` frontend-v2/src/modules/admin/ ├── pages/ ? ├── Dashboard.tsx # 运营仪表? ? ├── TenantManagement/ # 租户管理 ? ? ├── TenantList.tsx ? ? ├── TenantCreate.tsx ? ? ├── TenantEdit.tsx ? ? └── BrandingConfig.tsx # 品牌配置 ? ├── FeatureFlagManagement.tsx # Feature Flag管理 ? └── UserManagement.tsx # 用户管理 ├── api/ ? └── adminApi.ts └── index.tsx # 模块定义 ``` **模块注册?* ```typescript const AdminModule: ModuleDefinition = { id: 'admin', name: '运营管理', path: '/admin', requiredVersion: undefined, // 不基于version检? requireRole: ['SUPER_ADMIN'], // 🆕 基于角色检? component: lazy(() => import('./layouts/AdminLayout')), } ``` #### **C. 机构管理端模?* (P1? **目录结构?* ``` frontend-v2/src/modules/org/ ├── hospital/ # 医院管理? ? ├── pages/ ? ? ├── Dashboard.tsx ? ? ├── DepartmentManagement.tsx ? ? └── MemberManagement.tsx ? └── index.tsx └── pharma/ # 药企管理? ├── pages/ ? ├── Dashboard.tsx ? ├── ProjectManagement.tsx ? └── AuditLogs.tsx └── index.tsx ``` --- ## 8. 实施路线? ### 8.1 Phase 0:准备工作(1天) **目标?* 统一数据库表结构,清理历史遗? - [ ] **任务1?* 决策保留 `platform_schema.users` 还是 `public.users` - 建议:保?`platform_schema.users`(新架构? - 迁移 `public.users` 的历史数据到 `platform_schema.users` - 删除 `public.users` ? - [ ] **任务2?* 创建迁移文档 - 梳理所有业务模块对 User 表的引用 - 制定数据迁移脚本 ### 8.2 Phase 1:数据库Schema设计?天) **P0 核心表:** - [ ] **Day 1上午?* 设计并创?`tenants` ? - [ ] **Day 1下午?* 扩展 `users` 表(增加 tenantId, departmentId, role enum? - [ ] **Day 2上午?* 创建 `tenant_users`, `feature_flags`, `tenant_modules` ? - [ ] **Day 2下午?* 创建 Prisma Schema 并运行迁? **交付物:** - ?Prisma Schema完整定义 - ?迁移脚本运行通过 - ?测试数据插入验证 ### 8.3 Phase 2:后端认证系统(3天) - [ ] **Day 1?* 实现JWT工具? - `generateToken()` - `verifyToken()` - `refreshToken()` - [ ] **Day 2?* 实现认证API - POST `/api/v1/auth/register` - POST `/api/v1/auth/login` - GET `/api/v1/auth/me` - [ ] **Day 3?* 实现认证中间? - `requireAuth` - `requireRole` - `requireTenantAccess` - 应用到现有Legacy API **交付物:** - ?完整的认证系? - ?所有API加上认证保护 - ?Postman测试通过 ### 8.4 Phase 3:前端认证对接(2天) - [ ] **Day 1?* 实现登录页面 - LoginPage.tsx - useAuth Hook - Token存储(localStorage? - [ ] **Day 2?* 对接权限框架 - 替换PermissionContext中的mock数据 - 实现从后端获取用户信? - 实现登出功能 **交付物:** - ?可用的登?登出流程 - ?前端权限控制生效 ### 8.5 Phase 4:运营管理端MVP?天) **P0 核心功能?* - [ ] **Day 1-2?* 租户管理 - 租户列表? - 创建租户表单(基本信?租户类型? - 租户详情? - [ ] **Day 3?* 品牌配置 - Logo上传到OSS - 登录页背景图上传 - 配置预览 - [ ] **Day 4?* Feature Flag管理 - Feature Flag列表 - 开关切? - 目标租户配置 - [ ] **Day 5?* 集成测试 - 运营端完整流程测? - 权限控制测试 **交付物:** - ?运营管理端MVP可用 - ?可以创建租户 - ?可以配置品牌 - ?可以管理Feature Flag ### 8.6 Phase 5:租户专属登录(2天) - [ ] **Day 1?* 实现TenantLoginPage - 动态加载租户品牌配? - 替换Logo和背景图 - 动态主题色 - [ ] **Day 2?* 实现智能路由分发 - 登录后根据role+tenantType跳转 - 测试不同角色的跳转逻辑 **交付物:** - ?租户专属登录页可? - ?URL:`/t/{code}/login` 生效 ### 8.7 Phase 6:机构管理端(按需开发) **P1 功能(后续排期)?* - [ ] 医院管理端:科室管理、成员管理、配额分? - [ ] 药企管理端:项目监控、审计日? --- ## 9. 关键决策? ### 9.1 技术决? | 决策?| 选项 | 建议 | 理由 | |--------|------|------|------| | **User表选择** | platform_schema.users vs public.users | ?platform_schema.users | 符合新架构,Schema隔离清晰 | | **JWT库选择** | jsonwebtoken vs jose | ?jsonwebtoken | 成熟稳定,社区活?| | **密码加密** | bcrypt vs argon2 | ?bcrypt | 项目已有依赖(见IIT模块?| | **Token存储** | localStorage vs httpOnly Cookie | ?localStorage | 前后端分离,跨域友好 | | **角色定义方式** | 字符?vs Enum | ?Prisma Enum | 类型安全,避免拼写错?| ### 9.2 业务决策 | 决策?| 选项 | 建议 | 理由 | |--------|------|------|------| | **租户代码唯一?* | 全局唯一 vs 类型内唯一 | ?全局唯一 | URL `/t/{code}` 需全局唯一 | | **部门树层?* | 固定2?vs 无限层级 | ?无限层级 | 支持复杂组织架构 | | **Feature Flag粒度** | 租户?vs 用户?| ?租户?| 符合商业模式,管理简?| --- ## 10. 风险与挑? ### 10.1 技术风? | 风险 | 影响 | 缓解措施 | |------|------|---------| | **现有API无认?* | 需要全面改?| 渐进式加入认证,优先保护敏感API | | **两个User?* | 数据不一?| 尽快统一,编写迁移脚?| | **租户数据隔离** | 可能泄露数据 | 严格测试 `requireTenantAccess` 中间?| ### 10.2 开发挑? | 挑战 | 难度 | 应对方案 | |------|------|---------| | **JWT认证系统** | 中等 | 参考ODJ/BYSY项目实现 | | **品牌动态加?* | 中等 | 使用CSS变量+OSS图片URL | | **智能路由分发** | 简?| 基于role+tenantType的if-else | --- ## 11. 开发资源需? ### 11.1 人力需? - **后端开发:** 1?× 10天(Phase 0-3? - **前端开发:** 1?× 7天(Phase 3-5? - **测试?* 0.5?× 3天(集成测试? **总计?* ?0人天(约3周) ### 11.2 技术依? **新增npm包:** ```json { "dependencies": { "jsonwebtoken": "^9.0.0", "bcryptjs": "^2.4.3" }, "devDependencies": { "@types/jsonwebtoken": "^9.0.0", "@types/bcryptjs": "^2.4.2" } } ``` --- ## 12. 总结 ### 12.1 核心结论 1. **当前系统完全没有认证/授权系统** ? 2. **数据库有两个User表,需统一** ⚠️ 3. **前端权限框架设计完善,但仅为mock** ⚠️ 4. **租户体系完全缺失,需从零开?* ? ### 12.2 优先级建? **P0(Week 1-2):** 搭建基础架构 - 数据库Schema设计 + 迁移 - JWT认证系统 - 认证中间? - 登录/登出功能 - 运营管理端MVP(租户管?品牌配置? **P1(Week 3-4):** 完善核心功能 - Feature Flag管理 - 租户专属登录? - 机构管理端(医院版) **P2(Week 5+):** 扩展功能 - 机构管理端(药企版) - 高级审计日志 - 权限细粒度控? ### 12.3 下一步行? 1. ?**Review本报?*,确认技术方? 2. ?**确定开发排?*(建?周冲刺) 3. ?**启动Phase 0**:数据库表统一和Schema设计 4. ?**并行启动前端登录页设?*(UI设计师) --- ## 9. 🆕 Prompt管理系统整合 ### 9.1 为什么Prompt管理是运营管理端的灵? 根据?2-通用能力层_03-Prompt管理系统与灰度预览设计方?md》,**Prompt管理不是可选功能,而是运营管理端存在的核心理由之一**? #### **业务痛点?* 1. **测试环境无法模拟真实数据** - ASL的文献筛选需?0篇真实医学论文验证准确率 - DC的数据清洗需要真实病历数据验证抽取效? - 测试环境的假数据完全无法暴露Prompt的真实问? 2. **当前开发流程效率极?* - 每次调整Prompt需要:改代??commit ?部署 ?等待SAE重启(约5分钟? - 临床专家无法参与调试(他们不会写代码? - 无法快速迭代,一天只能尝试几? 3. **生产事故风险?* - 一旦Prompt发版,所有用户立即受影响 - 没有灰度机制,无法小范围验证 #### **解决方案:生产环境灰度预?* 调试者开启Debug模式后,自动路由到DRAFT版Prompt,验证通过后一键发布为ACTIVE版? ### 9.2 Prompt管理系统架构 #### **9.2.1 数据库设计(capability_schema?* ```prisma // --- Prompt Management System --- model PromptTemplate { id Int @id @default(autoincrement()) code String @unique // 唯一标识: 'ASL_SCREENING_TitleAbstract' name String // 人类可读名称 module String // 所属模? ASL, DC, AIA, IIT description String? variables Json? // 预期变量: ["title", "abstract"] versions PromptVersion[] createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("prompt_templates") @@schema("capability_schema") } model PromptVersion { id Int @id @default(autoincrement()) templateId Int @map("template_id") version Int // 版本?1, 2, 3... content String @db.Text // Prompt内容(支持Handlebars模板? modelConfig Json? // {"temperature": 0.1, "model": "deepseek-chat"} status PromptStatus @default(DRAFT) changelog String? // 修改说明 createdBy String? @map("created_by") // 🔍 审计:谁修改? template PromptTemplate @relation(fields: [templateId], references: [id]) createdAt DateTime @default(now()) @map("created_at") @@map("prompt_versions") @@schema("capability_schema") @@index([templateId, status]) // 高频查询优化 } enum PromptStatus { DRAFT // 草稿(仅Debug模式可见? ACTIVE // 线上生效(默认) ARCHIVED // 归档 @@schema("capability_schema") } ``` #### **9.2.2 新增角色与权?* | 角色 | 权限 Code | 说明 | |------|-----------|------| | **SUPER_ADMIN** | prompt:\* | 超级管理员拥有所有权?| | **PROMPT_ENGINEER** 🆕 | prompt:view
prompt:edit
prompt:debug
prompt:publish | 🎯 **核心角色**:专业Prompt工程师或临床专家 | | HOSPITAL_ADMIN | - | 机构管理员无Prompt权限 | | PHARMA_ADMIN | - | 药企管理员无Prompt权限 | **权限详解?* - `prompt:view` - 查看Prompt列表和历史版? - `prompt:edit` - 创建/修改DRAFT版本 - `prompt:debug` - ?核心:开启调试模? - `prompt:publish` - 发布DRAFT为ACTIVE #### **9.2.3 核心技术实?* **A. PromptService(后端)** ```typescript // backend/src/common/capabilities/prompt/prompt.service.ts export class PromptService { private debugUsers = new Set(); // 内存存储调试用户 private activeCache = new Map(); // ACTIVE版本缓存 /** * 设置调试模式 * @requires Permission: prompt:debug */ async setDebugMode(userId: string, enabled: boolean) { if (enabled) { this.debugUsers.add(userId); } else { this.debugUsers.delete(userId); } } /** * 获取Prompt(核心灰度逻辑? */ async get(code: string, variables: any, userId: string): Promise { // 1. 检查是否为调试? if (this.debugUsers.has(userId)) { // 优先获取DRAFT版本 const draft = await this.getDraftVersion(code); if (draft) { return this.render(draft.content, variables); } } // 2. 普通用户或无DRAFT时,获取ACTIVE版本 let active = this.activeCache.get(code); if (!active) { const version = await prisma.promptVersion.findFirst({ where: { template: { code }, status: 'ACTIVE' }, orderBy: { version: 'desc' } }); active = version?.content || this.getFallback(code); this.activeCache.set(code, active); } return this.render(active, variables); } /** * Postgres LISTEN/NOTIFY 热更? */ async initHotReload() { const client = await pool.connect(); await client.query('LISTEN prompt_update'); client.on('notification', (msg) => { console.log('[PromptService] Received update:', msg.payload); this.activeCache.clear(); // 清空缓存 }); } } ``` **B. API端点设计** | 方法 | 路径 | 权限 | 描述 | |------|------|------|------| | GET | /api/admin/prompts | prompt:view | 获取所有Prompt模板列表 | | GET | /api/admin/prompts/:id | prompt:view | 获取详情(含历史版本?| | POST | /api/admin/prompts/draft | prompt:edit | 保存草稿(生成新版本,status=DRAFT?| | POST | /api/admin/prompts/publish | prompt:publish | 发布版本(DRAFT→ACTIVE,触发NOTIFY?| | POST | /api/admin/prompts/debug | **prompt:debug** | **开关调试模?* | **C. 前端全局调试开?* ```tsx // frontend-v2/src/modules/admin/components/PromptDebugSwitch.tsx export const PromptDebugSwitch = () => { const { hasPermission } = usePermission(); const [debugMode, setDebugMode] = useState(false); // 🔒 权限控制:仅prompt:debug权限用户可见 if (!hasPermission('prompt:debug')) { return null; } const handleToggle = async (enabled: boolean) => { await api.post('/api/admin/prompts/debug', { enabled }); setDebugMode(enabled); }; return ( <> {debugMode && ( )} ); }; ``` ### 9.3 涉及的所有业务模? 根据文档?节,需要Prompt管理的模块: | 模块 | 核心场景 | Prompt复杂?| 优先?| |------|---------|-------------|--------| | **ASL** | 标题摘要初筛、全文复筛、证据合?| ⭐⭐⭐⭐?| P0 | | **DC** | Tool B提取、Tool C清洗、冲突检?| ⭐⭐⭐⭐?| P0 | | **IIT** | 质控检查、意图识别、查询生?| ⭐⭐⭐⭐?| P1 | | **PKB** | RAG问答、批处理阅读 | ⭐⭐⭐⭐ | P1 | | **AIA** | 10+智能体、意图识?| ⭐⭐?| P2 | | **RVW** | 规范性检?| ⭐⭐?| P2 | ### 9.4 Prompt管理开发计? #### **Phase 0: 基础设施?天)** 1. 创建`capability_schema`的Prompt相关? 2. 添加`prompt:*`权限到`platform_schema.permissions` 3. 创建`PROMPT_ENGINEER`角色 4. 实现`PromptService`核心逻辑 #### **Phase 1: 运营端MVP?天)** 1. 前端管理界面(列表、编辑器、版本历史) 2. 全局调试开关组? 3. 草稿保存/发布功能 #### **Phase 2: 业务模块接入(随业务开发)** - ASL筛选模块调用`promptService.get()` - DC数据清洗模块调用`promptService.get()` - 其他模块按需接入 ### 9.5 安全与风? 1. **权限隔离** - 严格检查`prompt:debug`权限,防止普通用户误入调试模? - 调试模式状态存储在内存(用户登出自动失效) 2. **审计日志** - `PromptVersion.createdBy`记录修改? - `AdminOperationLog`记录发布行为 3. **兜底机制** - 代码中保留Hardcoded Prompt作为系统级兜? - 数据库查询失败时返回默认版本 --- ## 10. 🆕 反馈采纳说明 ### 10.1 采纳的关键建? 基于?2-通用能力层_10-权限体系梳理反馈与修正建?md》,以下建议已整合到本文档: #### ?**1. 增加TenantQuotaAllocation表(P0?* **原因?* PRD明确要求医院端按科室/个人分配配额 **实施?* 已在7.1.1章节新增`tenant_quota_allocations`? ```prisma model TenantQuotaAllocation { targetType String // 'DEPARTMENT' | 'USER' targetKey String // DepartmentID ?UserID limitAmount BigInt // 分配的额? usedAmount BigInt // 已使? } ``` #### ?**2. 表名改为TenantMember(P1?* **原因?* "Member"语义强调组织关系?User"通常指登录账号实? **实施?* 已将`TenantUser`改为`TenantMember` #### ?**3. 审计日志增加module字段(P1?* **原因?* 药企端需要查询IIT模块专属日志(FDA 21 CFR Part 11合规? **实施?* 已在`AdminOperationLog`表增加`module`字段和索? #### ?**4. Prompt工程化权限(P0?* **原因?* 运营管理端核心功? **实施?* 已在?章完整设计Prompt管理系统 #### ?**5. 超级管理员种子数据(P0?* **原因?* 否则系统上线后无法进入后? **实施?* 将在Phase 0实现Prisma Seed脚本 #### ?**6. Phase 0回滚方案(P0?* **原因?* 数据安全基本原则 **实施?* 迁移脚本将先重命名`public.users`为`public.users_backup`,保?? #### ?**7. 租户配置API缓存(P1?* **原因?* 每个用户打开登录页都会调用,高并发下需要缓? **实施?* 将在实施时添加`Cache-Control: public, max-age=3600` ### 10.2 后续改进建议 以下建议暂不在MVP阶段实施,但列入技术债务清单? #### 🔄 **1. JWT安全性(P2?* **建议?* 使用HttpOnly Cookie替代localStorage **理由?* localStorage容易受XSS攻击 **计划?* 在药企端上线前(需更高安全性)实施 #### 🔄 **2. Prisma Extension多租户隔离(P1?* **建议?* 在ORM层强制加入`tenantId`过滤 **理由?* 防止开发人员忘记在Controller层加中间? **计划?* Phase 2引入 ```typescript const prismaExtended = prisma.$extends({ query: { $allModels: { async findMany({ args, query }) { args.where = { ...args.where, tenantId: currentTenantId }; return query(args); } } } }); ``` ### 10.3 反馈质量评价 **总体评估?* 优秀 ⭐⭐⭐⭐? - ?9条建议中?条立即采纳,2条纳入后续计? - ?发现了配额分配模型的设计缺陷(Critical? - ?强调了Prompt管理的核心地? - ?提出了实用的工程实践建议(回滚方案、种子数据) **结论?* 文档质量高,风险可控?*可以开始开?*? --- **报告完毕。准备好开始开发了吗?** 🚀