Files
aurak/docs/plans/2026-04-18-l1-talent-assessment-implementation-plan.md
T
Developer 0a9588abb7 feat: implement QuestionBank CRUD with pagination and template query
- Add pagination support to findAll (page, limit query params)
- Add findByTemplateId method to service
- Add GET /by-template/:templateId endpoint to controller
- Service already includes CRUD for QuestionBank and QuestionBankItem
2026-04-23 17:19:11 +08:00

490 lines
11 KiB
Markdown
Raw 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.
# L1人才育成评估系统实施计划
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 实现L1人才育成评估系统,支持五门课程考核、多知识组关联、加权计分、证书生成
**Architecture:** 基于现有AuraK评估系统(LangGraph状态机)扩展,新增模板多知识组支持、维度计分、证书功能
**Tech Stack:** NestJS + TypeORM + LangGraph + React
---
## Phase 1: 模板扩展(P0
### Task 1.1: 扩展 AssessmentTemplate 实体
**Files:**
- Modify: `server/src/assessment/entities/assessment-template.entity.ts:1-80`
**Step 1: Add new columns**
```typescript
// Add after existing columns (line ~79)
@Column({ type: 'simple-json', name: 'linked_group_ids', nullable: true })
linkedGroupIds: string[];
@Column({ type: 'simple-json', name: 'weight_config', nullable: true })
weightConfig: {
prompt: number;
other: number;
};
@Column({ type: 'simple-json', name: 'difficulty_config', nullable: true })
difficultyConfig: {
standard: number;
advanced: number;
specialist: number;
};
@Column({ type: 'int', name: 'question_count_min', default: 8 })
questionCountMin: number;
@Column({ type: 'int', name: 'question_count_max', default: 10 })
questionCountMax: number;
@Column({ type: 'int', name: 'passing_score', default: 90 })
passingScore: number;
```
**Step 2: Commit**
```bash
git add server/src/assessment/entities/assessment-template.entity.ts
git commit -m "feat: extend AssessmentTemplate with multi-group and weight config"
```
---
### Task 1.2: 创建数据库迁移
**Files:**
- Create: `server/src/migrations/XXXXXX-add-template-extensions.sql`
**Step 1: Write migration**
```sql
ALTER TABLE assessment_templates
ADD COLUMN linked_group_ids TEXT,
ADD COLUMN weight_config TEXT,
ADD COLUMN difficulty_config TEXT,
ADD COLUMN question_count_min INTEGER DEFAULT 8,
ADD COLUMN question_count_max INTEGER DEFAULT 10,
ADD COLUMN passing_score INTEGER DEFAULT 90;
```
**Step 2: Test migration**
```bash
cd server && npx typeorm query "SELECT linked_group_ids, weight_config FROM assessment_templates LIMIT 1"
```
**Step 3: Commit**
```bash
git add server/src/migrations/
git commit -m "db: add template extension columns"
```
---
### Task 1.3: 更新 TemplateService CRUD
**Files:**
- Modify: `server/src/assessment/services/template.service.ts`
**Step 1: Add linkedGroupIds handling**
```typescript
// In create() method, add:
if (createTemplateDto.linkedGroupIds) {
template.linkedGroupIds = createTemplateDto.linkedGroupIds;
}
if (createTemplateDto.weightConfig) {
template.weightConfig = createTemplateDto.weightConfig;
}
// ... other fields
```
**Step 2: Verify compilation**
```bash
cd server && npx tsc --noEmit
```
**Step 3: Commit**
```bash
git add server/src/assessment/services/template.service.ts
git commit -m "feat: support linkedGroupIds in TemplateService"
```
---
## Phase 2: 评估流程适配(P0
### Task 2.1: 修改 QuestionGenerator 支持多知识组
**Files:**
- Modify: `server/src/assessment/assessment.service.ts:266-368` (startSession method)
**Step 1: Support multi-group content retrieval**
```typescript
// In startSession(), replace single content retrieval with multi-group:
private async getMultiGroupContent(
groupIds: string[],
userId: string,
tenantId: string,
): Promise<string> {
const contents: string[] = [];
for (const groupId of groupIds) {
const files = await this.groupService.getGroupFiles(groupId, userId, tenantId);
const content = files.map(f => f.content).join('\n\n---\n\n');
contents.push(content);
}
return contents.join('\n\n');
}
```
**Step 2: Pass content with dimension tag**
```typescript
// In getSessionContent, add dimension tag:
// === Document: [工作能力] ===
// ...content...
```
**Step 3: Commit**
```bash
git add server/src/assessment/assessment.service.ts
git commit -m "feat: support multi-group content retrieval"
```
---
### Task 2.2: Generator 输出维度信息
**Files:**
- Modify: `server/src/assessment/graph/nodes/generator.node.ts:176-182`
**Step 1: Add dimension field**
```typescript
const mappedNewQuestions = newQuestions.map((q: any) => ({
id: (existingQuestions.length + 1).toString(),
questionText: q.question_text,
keyPoints: q.key_points,
difficulty: q.difficulty,
basis: q.basis,
dimension: q.dimension || this.inferDimension(knowledgeBaseContent), // NEW FIELD
}));
private inferDimension(content: string): string {
// Detect dimension from content tags
if (content.includes('[提示词]')) return 'prompt';
if (content.includes('[LLM]')) return 'llm';
// ... etc
}
```
**Step 2: Commit**
```bash
git add server/src/assessment/graph/nodes/generator.node.ts
git commit -m "feat: generator outputs dimension field"
```
---
## Phase 3: 评分逻辑(P0
### Task 3.1: DimensionScores 计算
**Files:**
- Modify: `server/src/assessment/assessment.service.ts:600-630` (score calculation)
**Step 1: Calculate dimension scores**
```typescript
// Replace simple weighted score with dimension-aware calculation:
const calculateDimensionScores = (questions: any[], scores: Record<string, number>) => {
const dimensionScores: Record<string, number> = {
prompt: 0, llm: 0, ide: 0, devPattern: 0, workCapability: 0
};
const dimensionCounts: Record<string, number> = { prompt: 0, llm: 0, ide: 0, devPattern: 0, workCapability: 0 };
questions.forEach((q, idx) => {
const dim = q.dimension || 'workCapability';
dimensionScores[dim] += scores[q.id || idx.toString()] || 0;
dimensionCounts[dim]++;
});
// Average per dimension
Object.keys(dimensionScores).forEach(d => {
dimensionScores[d] = dimensionCounts[d] > 0
? dimensionScores[d] / dimensionCounts[d]
: 0;
});
return dimensionScores;
};
```
**Step 2: Commit**
```bash
git add server/src/assessment/assessment.service.ts
git commit -m "feat: calculate dimension scores"
```
---
### Task 3.2: 追问策略调整
**Files:**
- Modify: `server/src/assessment/graph/nodes/grader.node.ts:207`
**Step 1: Increase follow-up limit**
```typescript
// Current: currentFollowUpCount >= 1
// Change to:
if (currentFollowUpCount >= 2 || result.score >= 8 || saysIDontKnow) {
shouldFollowUp = false;
}
```
**Step 2: Commit**
```bash
git add server/src/assessment/graph/nodes/grader.node.ts
git commit -m "feat: increase follow-up limit to 2"
```
---
## Phase 4: 报告生成(P1
### Task 4.1: 扩展 Session 存储 dimension 数据
**Files:**
- Modify: `server/src/assessment/entities/assessment-session.entity.ts`
**Step 1: Add dimension fields**
```typescript
@Column({ type: 'simple-json', name: 'dimension_scores', nullable: true })
dimensionScores: Record<string, number>;
@Column({ type: 'simple-json', name: 'radar_data', nullable: true })
radarData: Record<string, number>;
```
**Step 2: Commit**
```bash
git add server/src/assessment/entities/assessment-session.entity.ts
git commit -m "feat: add dimension scores to session entity"
```
---
### Task 4.2: Analyzer 生成结构化报告
**Files:**
- Modify: `server/src/assessment/graph/nodes/analyzer.node.ts`
**Step 1: Generate dimension-aware report**
```typescript
// Modify system prompt to include:
const dimensionSummary = Object.entries(dimensionScores)
.map(([dim, score]) => `${dim}: ${score}/10`)
.join('\n');
const reportPrompt = `...
维度得分:
${dimensionSummary}
请在报告中包含:
1. 各维度得分分析
2. 薄弱环节识别
3. 针对性改进建议
`;
```
**Step 2: Commit**
```bash
git add server/src/assessment/graph/nodes/analyzer.node.ts
git commit -m "feat: generate structured report with dimension analysis"
```
---
## Phase 5: 证书功能(P1
### Task 5.1: 创建证书表
**Files:**
- Create: `server/src/assessment/entities/assessment-certificate.entity.ts`
**Step 1: Define entity**
```typescript
@Entity('assessment_certificates')
export class AssessmentCertificate {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ name: 'user_id' })
userId: string;
@Column({ name: 'session_id' })
sessionId: string;
@Column({ name: 'template_id' })
templateId: string;
@Column()
level: string;
@Column({ type: 'float', name: 'total_score' })
totalScore: number;
@Column({ name: 'qr_code', nullable: true })
qrCode: string;
@CreateDateColumn({ name: 'issued_at' })
issuedAt: Date;
}
```
**Step 2: Commit**
```bash
git add server/src/assessment/entities/assessment-certificate.entity.ts
git commit -m "feat: create certificate entity"
```
---
### Task 5.2: 证书生成API
**Files:**
- Modify: `server/src/assessment/assessment.controller.ts`
**Step 1: Add certificate endpoints**
```typescript
@Get('certificate/:sessionId')
async getCertificate(
@Param('sessionId') sessionId: string,
@Req() req,
): Promise<AssessmentCertificate> {
// Generate or return existing certificate
}
@Get('certificate/:sessionId/download')
async downloadCertificate(
@Param('sessionId') sessionId: string,
): Promise<StreamableFile> {
// Generate PDF with jsPDF
}
```
**Step 2: Commit**
```bash
git add server/src/assessment/assessment.controller.ts
git commit -m "feat: add certificate endpoints"
```
---
## Phase 6: 前端集成(P2
### Task 6.1: 模板选择页面
**Files:**
- Modify: `web/components/views/AssessmentView.tsx`
**Step 1: Add template selection**
```typescript
// Add state:
const [templates, setTemplates] = useState<AssessmentTemplate[]>([]);
// Load templates on mount:
useEffect(() => {
const loadTemplates = async () => {
const res = await assessmentService.getTemplates();
setTemplates(res.data);
};
loadTemplates();
}, []);
```
**Step 2: Commit**
```bash
git add web/components/views/AssessmentView.tsx
git commit -m "feat: add template selection to frontend"
```
---
### Task 6.2: 报告页面的雷达图
**Files:**
- Create: `web/components/RadarChart.tsx`
**Step 1: Create component**
```typescript
export const RadarChart = ({ data }) => {
// Use recharts or echarts for radar
// Data: { prompt: 9.6, llm: 9.0, ide: 7.0, devPattern: 5.0, workCapability: 5.0 }
};
```
**Step 2: Commit**
```bash
git add web/components/RadarChart.tsx
git commit -m "feat: add radar chart component"
```
---
## 实施顺序
1. Task 1.1 → 1.3 (模板扩展)
2. Task 2.1 → 2.2 (评估流程)
3. Task 3.1 → 3.2 (评分逻辑)
4. Task 4.1 → 4.2 (报告)
5. Task 5.1 → 5.2 (证书)
6. Task 6.1 → 6.2 (前端)
**每个Task约需1-2小时**
---
## 依赖说明
- Phase 1 (模板) → Phase 2 → Phase 3 → Phase 4 → Phase 5
- 前端(Phase 6) 可在后端基本完成后并行开发
- 测试贯穿每个Task
---
## 验收标准
- [ ] 模板支持多知识组关联
- [ ] 题目带dimension字段
- [ ] 报告含dimensionScores和radarData
- [ ] 可生成书PDF
- [ ] 前端显示雷达图
- [ ] E2E测试通过