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

319 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# **Prompt管理系统快速参考**
> **版本:** v1.0
> **优先级:** P0核心通用能力
> **状态:** 待开发
---
## 📌 核心概念
### 什么是Prompt管理系统
一个允许**专业人员在生产环境安全调试AI Prompt**的灰度预览系统。
### 为什么需要它?
-**痛点1** 测试环境无法模拟真实医学数据20篇文献、真实病历
-**痛点2** 每次调整Prompt需要改代码→部署→等待5分钟
-**痛点3** 临床专家无法参与调试(他们不会写代码)
-**解决:** 生产环境灰度预览 + 调试者角色 + DRAFT/ACTIVE版本隔离
---
## 🗂️ 数据库Schema
### 位置:`capability_schema`
```prisma
// --- 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 |
### 新增角色
```typescript
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 | **开关调试模式** |
### 业务模块集成
```typescript
// 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);
}
}
```
---
## 🎨 前端组件
### 全局调试开关
```tsx
// 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
```typescript
// 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` - 架构梳理
---
**🚀 准备开始开发了吗?**