Files
HaHafeng 66255368b7 feat(admin): Add user management and upgrade to module permission system
Features - User Management (Phase 4.1):
- Database: Add user_modules table for fine-grained module permissions
- Database: Add 4 user permissions (view/create/edit/delete) to role_permissions
- Backend: UserService (780 lines) - CRUD with tenant isolation
- Backend: UserController + UserRoutes (648 lines) - 13 API endpoints
- Backend: Batch import users from Excel
- Frontend: UserListPage (412 lines) - list/filter/search/pagination
- Frontend: UserFormPage (341 lines) - create/edit with module config
- Frontend: UserDetailPage (393 lines) - details/tenant/module management
- Frontend: 3 modal components (592 lines) - import/assign/configure
- API: GET/POST/PUT/DELETE /api/admin/users/* endpoints

Architecture Upgrade - Module Permission System:
- Backend: Add getUserModules() method in auth.service
- Backend: Login API returns modules array in user object
- Frontend: AuthContext adds hasModule() method
- Frontend: Navigation filters modules based on user.modules
- Frontend: RouteGuard checks requiredModule instead of requiredVersion
- Frontend: Remove deprecated version-based permission system
- UX: Only show accessible modules in navigation (clean UI)
- UX: Smart redirect after login (avoid 403 for regular users)

Fixes:
- Fix UTF-8 encoding corruption in ~100 docs files
- Fix pageSize type conversion in userService (String to Number)
- Fix authUser undefined error in TopNavigation
- Fix login redirect logic with role-based access check
- Update Git commit guidelines v1.2 with UTF-8 safety rules

Database Changes:
- CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled)
- ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code)
- INSERT 4 permissions + role assignments
- UPDATE PUBLIC tenant with 8 module subscriptions

Technical:
- Backend: 5 new files (~2400 lines)
- Frontend: 10 new files (~2500 lines)
- Docs: 1 development record + 2 status updates + 1 guideline update
- Total: ~4900 lines of code

Status: User management 100% complete, module permission system operational
2026-01-16 13:42:10 +08:00

8.7 KiB
Raw Permalink Blame History

Prompt管理系统快速参考

版本: v1.0
优先级: P0核心通用能力
状态: 待开发


📌 核心概念

什么是Prompt管理系统

一个允许专业人员在生产环境安全调试AI Prompt的灰度预览系统。

为什么需要它?

  • 痛点1 测试环境无法模拟真实医学数据20篇文献、真实病历
  • 痛点2 每次调整Prompt需要改代码→部署→等待5分钟
  • 痛点3 临床专家无法参与调试(他们不会写代码)
  • 解决: 生产环境灰度预览 + 调试者角色 + DRAFT/ACTIVE版本隔离

🗂️ 数据库Schema

位置:capability_schema

// --- Prompt Management System ---

model PromptTemplate {
  id          Int       @id @default(autoincrement())
  code        String    @unique                       // 'ASL_SCREENING_TitleAbstract'
  name        String                                  // "ASL标题摘要筛选"
  module      String                                  // ASL, DC, IIT, AIA, PKB, RVW
  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                                     // 版本号
  content     String         @db.Text                 // Prompt内容
  modelConfig Json?                                   // {"temperature": 0.1}
  status      PromptStatus   @default(DRAFT)
  changelog   String?                                 // "增加了排除标准"
  createdBy   String?        @map("created_by")      // UserID审计
  
  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")
}

🔐 权限与角色

新增权限

权限 Code 描述 适用角色
prompt:view 查看Prompt列表和历史 SUPER_ADMIN, PROMPT_ENGINEER
prompt:edit 创建/修改DRAFT版本 SUPER_ADMIN, PROMPT_ENGINEER
prompt:debug 开启调试模式 SUPER_ADMIN, PROMPT_ENGINEER
prompt:publish 发布DRAFT→ACTIVE SUPER_ADMIN, PROMPT_ENGINEER

新增角色

enum UserRole {
  SUPER_ADMIN      = 'SUPER_ADMIN',
  PROMPT_ENGINEER  = 'PROMPT_ENGINEER',    // 🆕 核心角色
  HOSPITAL_ADMIN   = 'HOSPITAL_ADMIN',
  PHARMA_ADMIN     = 'PHARMA_ADMIN',
  USER             = 'USER'
}

🚀 核心API

管理端接口

方法 路径 权限 描述
GET /api/admin/prompts prompt:view 获取所有模板
GET /api/admin/prompts/:id prompt:view 获取详情+历史版本
POST /api/admin/prompts/draft prompt:edit 保存草稿
POST /api/admin/prompts/publish prompt:publish 发布
POST /api/admin/prompts/debug prompt:debug 开关调试模式

业务模块集成

// backend/src/modules/asl/services/screening.service.ts

import { promptService } from '@/common/capabilities/prompt/prompt.service';

export class ScreeningService {
  async screenPaper(paper: any, userId: string) {
    // 🎯 核心调用:自动处理灰度逻辑
    const prompt = await promptService.get(
      'ASL_SCREENING_TitleAbstract',
      { title: paper.title, abstract: paper.abstract },
      userId   // ⭐ 必须传入userId
    );

    return await llmGateway.chat(prompt);
  }
}

🎨 前端组件

全局调试开关

// frontend-v2/src/modules/admin/components/PromptDebugSwitch.tsx

export const PromptDebugSwitch = () => {
  const { hasPermission } = usePermission();
  const [debugMode, setDebugMode] = useState(false);
  
  if (!hasPermission('prompt:debug')) {
    return null;  // 🔒 权限控制
  }
  
  return (
    <>
      <Switch 
        checked={debugMode} 
        onChange={(enabled) => api.post('/api/admin/prompts/debug', { enabled })}
        checkedChildren="🐛 调试模式"
        unCheckedChildren="生产模式"
      />
      {debugMode && (
        <Alert
          type="warning"
          message="⚠️ 调试模式已开启您当前正在使用草稿版DRAFT提示词"
          banner
        />
      )}
    </>
  );
};

📋 涉及模块

模块 核心场景 复杂度 优先级
ASL 标题摘要初筛、全文复筛、证据合成 P0
DC Tool B提取、Tool C清洗、冲突检测 P0
IIT 质控检查、意图识别 P1
PKB RAG问答、批处理阅读 P1
AIA 10+智能体、意图识别 P2
RVW 规范性检查 P2

⚙️ 核心逻辑PromptService

// backend/src/common/capabilities/prompt/prompt.service.ts

export class PromptService {
  private debugUsers = new Set<string>();        // 内存存储调试用户
  private activeCache = new Map<string, string>(); // ACTIVE版本缓存
  
  // 设置调试模式
  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<string> {
    // 1. 调试者优先获取DRAFT版本
    if (this.debugUsers.has(userId)) {
      const draft = await this.getDraftVersion(code);
      if (draft) {
        return this.render(draft.content, variables);
      }
    }
    
    // 2. 普通用户获取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) => {
      this.activeCache.clear();  // 清空缓存
    });
  }
}

📅 开发计划

Phase 0: 基础设施2天

  • 创建数据库表(prompt_templates, prompt_versions
  • 添加prompt:*权限到platform_schema.permissions
  • 创建PROMPT_ENGINEER角色
  • 实现PromptService核心逻辑

Phase 1: 运营端MVP3天

  • 前端管理界面(列表、编辑器、版本历史)
  • 全局调试开关组件
  • 草稿保存/发布功能

Phase 2: 业务模块接入(随业务开发)

  • ASL模块调用promptService.get()
  • DC模块调用promptService.get()
  • 其他模块按需接入

🔒 安全与风控

权限隔离

  • 严格检查prompt:debug权限
  • 调试模式状态存储在内存(登出自动失效)

审计日志

  • PromptVersion.createdBy记录修改人
  • AdminOperationLog记录发布行为module='prompt'

兜底机制

  • 代码中保留Hardcoded Prompt作为系统级兜底
  • 数据库查询失败时返回默认版本

🎯 典型工作流

  1. 场景: 临床专家Dr. Wang觉得ASL文献筛选准确率不够

  2. 修改: Dr. Wang登录运营管理端修改ASL_SCREENING的Prompt增加排除标准保存草稿

  3. 调试: Dr. Wang点击顶部的"开启调试模式"

  4. 验证: Dr. Wang切换到ASL业务页面上传几篇之前筛错的文献
    → 系统后端检测到Dr. Wang在Debug列表中加载DRAFT版Prompt

  5. 确认: 发现结果正确了

  6. 发布: Dr. Wang回到管理页点击"发布"

  7. 结束: Dr. Wang关闭调试模式


📚 相关文档

  • 02-通用能力层_07-运营与机构管理端PRD_v2.1.md - 总体需求
  • 02-通用能力层_03-Prompt管理系统与灰度预览设计方案.md - 详细设计
  • 00-权限与角色体系梳理报告_v1.0.md - 架构梳理

🚀 准备开始开发了吗?