# AuraK — AI 工作指南 > 本文件指导 AI 助手(Claude Code 等)如何理解和使用此仓库。 > 项目:AuraK — 企业级多租户 AI 知识库与人才评价平台 --- ## 一、项目全景 ``` AuraK/ ├── web/ # React 19 + Vite 前端 (端口 13001) │ ├── components/ # UI 组件(含 views/ 目录下的主要页面) │ ├── contexts/ # AuthContext / LanguageContext / ConfirmContext │ ├── services/ # API 客户端(apiClient.ts + 各服务) │ ├── hooks/ # usePermissions 等自定义 Hook │ └── src/pages/ # 路由页面(薄壳,委托给 components/views) ├── server/ # NestJS 后端 (端口 3001) │ ├── src/auth/ # 认证(JWT/API Key)+ 权限(RBAC) │ │ └── permission/ # Permission/Role 实体 + Service + Guard │ ├── src/assessment/ # 考核评估子系统(最复杂) │ ├── src/tenant/ # 多租户 + 租户成员管理 │ └── src/user/ # 用户 CRUD ├── docs/plans/ # 设计文档和计划 ├── test-*.mjs # Playwright 测试脚本(项目根目录) └── docker-compose.yml # 基础设施(Elasticsearch, Tika, LibreOffice) ``` ### 核心技术栈 | 层 | 技术 | |---|---| | 前端 | React 19, TypeScript, Vite 6, Tailwind CSS v4, Framer Motion, Lucide icons | | 后端 | NestJS 11, TypeORM, SQLite (better-sqlite3), LangChain/LangGraph | | 搜索 | Elasticsearch 9(向量+全文混合检索)| | 认证 | JWT + API Key 双机制 | | 部署 | Docker Compose(Nginx 反向代理)| --- ## 二、系统架构 ### 2.1 前端路由 | 路径 | 组件 | 说明 | |---|---|---| | `/login` | LoginPage | 公开 | | `/` | OverviewPage | 工作台首页 | | `/chat` | ChatPage | AI 对话 | | `/assessment` | AssessmentPage | 考核评估 | | `/assessment-stats` | AssessmentStatsView | 评估统计 | | `/question-banks` | QuestionBankView | 题库管理 | | `/settings` | SettingsPage | 系统设置 | ### 2.2 后端模块 app.module.ts 注册了 27 个模块,核心模块: - **AuthModule** — 认证(JWT/API Key 双策略) - **PermissionModule** — RBAC 权限(Role/RolePermission 实体 + PermissionService + PermissionsGuard) - **UserModule** — 用户 CRUD - **TenantModule** — 多租户(全局模块) - **AssessmentModule** — 考核评估(最复杂,含会话/出题/评分/证书) - **AdminModule / SuperAdminModule** — 管理端 API - **KnowledgeBaseModule** — 知识库索引和检索 - **ModelConfigModule** — AI 模型配置 ### 2.3 认证流程 ``` 密码登录: POST /api/auth/login (username, password) → LocalAuthGuard → JwtService.sign(payload) → { access_token, user } 获取 API Key: GET /api/users/api-key (Authorization: Bearer ) → 返回 kb_xxxxxxxx...(存前端 localStorage) 后续所有请求: Headers: { x-api-key: , x-tenant-id: } 全局守卫: CombinedAuthGuard(APP_GUARD 注册) → 先尝试 API Key 认证,失败则回退 JWT → @Public() 装饰器跳过认证 ``` --- ## 三、权限系统(RBAC)核心 ### 3.1 三层角色 | 角色 | 权限数 | 能做什么 | |---|---|---| | **SUPER_ADMIN** | 26 项 | 全部权限:用户/租户/知识库/考核/模型/插件/设置 | | **TENANT_ADMIN** | 21 项 | 管理本租户用户和资源;不能跨租户/删用户/改系统设置 | | **USER** | 5 项 | kb:view/create/edit, assess:view, plugin:view | ### 3.2 权限常量定义 位于 `server/src/auth/permission/permission.constants.ts` ```typescript // 用户管理: user:view / user:create / user:edit / user:delete / user:role / user:password // 租户管理: tenant:view / tenant:create / tenant:edit / tenant:delete / tenant:members // 知识库: kb:view / kb:create / kb:edit / kb:delete / kb:publish // 考核: assess:view / assess:manage / assess:template / assess:bank // 模型: model:view / model:config // 插件: plugin:view / plugin:manage // 设置: settings:view / settings:system ``` ### 3.3 权限守卫流水线 ``` CombinedAuthGuard (认证) → 已有,全局注册 → RolesGuard (角色门控) → @Roles(SUPER_ADMIN, TENANT_ADMIN) → PermissionsGuard (权限门控) → @Permission('user:view') ``` **系统角色保护**: 系统角色(isSystem=true)的权限不可通过 API 修改。 ### 3.4 权限解析链路 ``` PermissionService.getUserPermissions(userId, tenantId) → 1. 如果 user.isAdmin === true,返回全部 SUPER_ADMIN 权限 → 2. 查找 TenantMember(userId, tenantId) → 3. TenantMember.role → Role.baseRole → RolePermission.permissionKey ``` --- ## 四、考核评估系统 ### 4.1 数据模型 ``` AssessmentTemplate (模板) └── question_count, dimensions[{name, label, weight}], passingScore └── QuestionBank (题库,一对一关联模板) └── QuestionBankItem (题目) ├── questionType: SHORT_ANSWER / MULTIPLE_CHOICE / TRUE_FALSE └── dimension: PROMPT / LLM / IDE / DEV_PATTERN / WORK_CAPABILITY AssessmentSession (会话) ├── questions_json (缓存的题目列表) ├── messages (对话历史) ├── scores / dimensionScores └── finalReport (AI 生成的报告) AssessmentCertificate (证书) └── level: Novice / Proficient / Advanced / Expert ``` ### 4.2 出题算法 `selectQuestions()` 在 `question-bank.service.ts`: ```typescript // 按维度权重公平分配(floor + remainder,保证总和 = count) // 20题模板: PROMPT(30%)→6题, LLM(30%)→6题, IDE(20%)→4题, DEV_PATTERN(20%)→4题 ``` ### 4.3 模板配置(数据库 `assessment_templates` 表) ```typescript // dimensions 字段是 JSON 数组,前端「测评模板」页面可编辑 dimensions = [ { name: "PROMPT", label: "Prompt Engineering", weight: 30 }, { name: "LLM", label: "LLM Knowledge", weight: 30 }, { name: "IDE", label: "IDE Proficiency", weight: 20 }, { name: "DEV_PATTERN", label: "Dev Patterns", weight: 20 }, ] ``` --- ## 五、测试脚本 所有 Playwright 测试位于项目根目录: | 脚本 | 用途 | 运行命令 | |---|---|---| | `test-systematic.mjs` | **142 项系统性测试**(身份/CRUD/权限/边界/UI) | `node test-systematic.mjs` | | `test-e2e-full.mjs` | 94 项全角色 E2E 测试 | `node test-e2e-full.mjs` | | `test-user-lifecycle.mjs` | 42 项用户生命周期测试 | `node test-user-lifecycle.mjs` | | `test-multiround.mjs` | 考核多轮对话测试 | `node test-multiround.mjs` | | `test-permission-flow.mjs` | 三层角色权限验证 | `node test-permission-flow.mjs` | | `test-question-distribution.mjs` | 出题分布验证 | `node test-question-distribution.mjs` | | `exam-organizer.mjs` | 考试组织者场景(创建考生+考核+查看结果) | `node exam-organizer.mjs` | --- ## 六、开发指南 ### 6.1 启动项目 ```bash # 后端 cd server && node dist/main.js # 生产模式(需要先 nest build) cd server && yarn start:dev # 开发模式(热加载) # 前端 cd web && npx vite --port 13001 # 开发模式 cd web && npx vite build # 编译 # 基础设施(需要 Docker) docker-compose up -d elasticsearch tika libreoffice ``` ### 6.2 运行测试 ```bash cd /d/AuraK && node test-systematic.mjs # 142 项全面测试 ``` ### 6.3 重启服务 ```bash taskkill //F //IM node.exe 2>/dev/null # 杀所有 Node 进程 cd /d/AuraK/server && node dist/main.js & # 启动后端 cd /d/AuraK/web && npx vite --port 13001 & # 启动前端 ``` ### 6.4 数据库管理 ```bash # SQLite 文件路径 server/data/metadata.db # 直接查询 cd /d/AuraK && node -e " const sqlite3 = require('better-sqlite3'); const db = new sqlite3('server/data/metadata.db'); db.prepare('SELECT * FROM users').all(); db.close(); " ``` ### 6.5 常见问题 - **端口占用**: `netstat -ano | grep 3001` → `taskkill //F //PID ` - **后端启动失败**: 确保从 `server/` 目录启动以加载 .env - **Windows 杀进程**: 用 `taskkill //F //PID`,`kill` 不可靠 - **Dist 目录修改**: `server/dist/` 下的 .js 直接修改即可生效(无需 nest build) --- ## 七、代码规范 ### 7.1 TypeScript 模式 - **实体定义**: TypeORM `@Entity` + `@Column` + 枚举类型 - **控制器**: `@Controller` + `@UseGuards(CombinedAuthGuard)` + `@Permission()` - **服务**: `@Injectable` 类,方法名用动词开头 - **前端组件**: React FC + TypeScript interface props ### 7.2 权限装饰器使用 ```typescript // 后端 API — 在控制器方法上标注所需权限 @Post() @UseGuards(PermissionsGuard) @Permission('user:create') async createUser(@Request() req, @Body() body: CreateUserDto) { ... } // 前端 — 用 PermissionGate 组件或 usePermissions hook const { hasPermission } = usePermissions(); {hasPermission('user:view') && } ``` ### 7.3 通用 React 约定 - 使用 `cn()` 工具函数(tailwind-merge)合并 className - 图标用 `lucide-react` - 动画用 `framer-motion` - API 调用用 `apiClient` 或原生 `fetch` - 模态框用 `createPortal` + `AnimatePresence` --- ## 八、Playwright 测试指南 ### 8.1 测试模式 ```javascript import { chromium } from 'playwright'; const browser = await chromium.launch({ headless: true }); const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); // 模拟 API 调用 const r = await fetch(`${API}/api/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }); ``` ### 8.2 React 受控输入框操作(关键)⚠️ React 的受控 input/textarea 依赖 native setter 触发 `onChange`。**不要用 `type()` 或 `fill()`**,应使用: ```javascript await page.evaluate((text) => { const ta = document.querySelector('textarea'); if (!ta) return; const setter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value')?.set; setter?.call(ta, text); ta.dispatchEvent(new Event('input', { bubbles: true })); }, '要输入的文字'); ``` ### 8.3 等待按钮可用 ```javascript await page.waitForFunction(() => { const btn = document.querySelector('button:has(svg.lucide-send)'); return btn && !btn.disabled; }, { timeout: 10000 }); ``` ### 8.4 等待 spinner 消失 ```javascript await page.waitForFunction(() => !document.querySelector('.animate-spin'), { timeout: 60000 }); ``` ### 8.5 检测考核题型 ```javascript const state = await page.evaluate(() => { // 选择题选项按钮 const optionBtns = Array.from(document.querySelectorAll('button.w-full.text-left.px-5.py-4')) .filter(b => !b.textContent?.includes('确认答案')); // 简答题 textarea const ta = document.querySelector('textarea'); return { choiceCount: optionBtns.length, hasTextarea: ta?.offsetParent !== null }; }); ``` --- ## 九、部署配置 ### 端口 | 服务 | 端口 | |---|---| | 前端(开发) | 13001 | | 前端(生产/Nginx) | 80/443 | | 后端 API | 3001 | | Elasticsearch | 9200 | | Apache Tika | 9998 | | LibreOffice | 8100 | ### 环境变量 `server/.env` 关键配置: ``` PORT=3001 DATABASE_PATH=./data/metadata.db ELASTICSEARCH_HOST=http://127.0.0.1:9200 JWT_SECRET=your-secret ``` --- ## 十、快速参考命令 ```bash # 启动 cd /d/AuraK/server && node dist/main.js & cd /d/AuraK/web && npx vite --port 13001 & # 后端编译 cd /d/AuraK/server && npx nest build # 运行测试 cd /d/AuraK && node test-systematic.mjs # 数据库查询 cd /d/AuraK && node -e " const s=require('better-sqlite3'); const d=new s('server/data/metadata.db'); const r=d.prepare('...').all(); console.log(r); d.close();" # 清理端口 taskkill //F //IM node.exe 2>/dev/null # 前端编译 cd /d/AuraK/web && npx vite build ```