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
This commit is contained in:
Developer
2026-04-23 17:19:11 +08:00
commit 0a9588abb7
492 changed files with 112453 additions and 0 deletions
@@ -0,0 +1,505 @@
# Talent Assessment Management System - Design Document
**Date**: 2026-03-16
**Author**: Sisyphus AI Agent
**Status**: Draft for Review
## Executive Summary
Enhance the existing talent assessment system with comprehensive management functionality allowing administrators to configure assessment generation through keywords, question counts, and style requirements. The system will extract relevant content from knowledge bases and generate customized assessments based on these configurations.
---
## 1. Architecture Overview
### Current System Flow
```
User selects knowledge base → System generates 3-5 questions → User answers → AI grades → Report generated
```
### Enhanced System Flow
```
User selects template/inline config → System filters content by keywords → Generates N questions with specified style → User answers → AI grades → Report generated
```
### Key Components
#### Backend (NestJS)
- **AssessmentConfig Entity**: Store reusable assessment templates
- **Enhanced Question Generator**: Accept config parameters for customization
- **Content Filter Service**: Filter knowledge base content by keywords
- **Config Management API**: CRUD operations for assessment templates
#### Frontend (React)
- **Template Management Page**: Create/edit assessment templates
- **Enhanced Assessment Start**: Support template selection + inline config
- **Configuration UI**: Keywords input, question count slider, style presets
---
## 2. Database Schema Design
### New Entity: AssessmentConfig
```typescript
@Entity('assessment_configs')
export class AssessmentConfig {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column({ nullable: true })
description: string;
@Column({ name: 'tenant_id', nullable: true })
tenantId: string;
@Column({ type: 'simple-json' })
configuration: AssessmentConfigSettings;
@Column({ default: true })
isActive: boolean;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}
```
### Configuration Settings Interface
```typescript
interface AssessmentConfigSettings {
// Keywords for content filtering and AI focus
keywords: string[];
// Question generation parameters
questionCount: number; // 1-20
difficultyDistribution: {
standard: number; // 0-100%
advanced: number; // 0-100%
specialist: number; // 0-100%
};
// Style requirements
style: {
tone: 'formal' | 'conversational' | 'technical' | 'business';
questionTypes: ('multiple-choice' | 'open-ended' | 'scenario-based' | 'technical')[];
assessmentGoals: ('knowledge-check' | 'problem-solving' | 'critical-thinking' | 'application')[];
};
// Content filtering
contentFilter: {
minContentLength: number; // Minimum characters for content to be considered
maxContextChunks: number; // Max chunks to include in context
};
}
```
### Modified Session Entity
Add reference to assessment config:
```typescript
@Entity('assessment_sessions')
export class AssessmentSession {
// ... existing fields ...
@Column({ name: 'config_id', nullable: true })
configId: string | null;
@ManyToOne(() => AssessmentConfig, { nullable: true })
@JoinColumn({ name: 'config_id' })
config: AssessmentConfig;
// Inline configuration (when no template used)
@Column({ type: 'simple-json', nullable: true, name: 'inline_config' })
inlineConfig: AssessmentConfigSettings | null;
}
```
---
## 3. Backend Implementation
### 3.1 New Service: AssessmentConfigService
```typescript
@Injectable()
export class AssessmentConfigService {
async createConfig(tenantId: string, settings: AssessmentConfigSettings): Promise<AssessmentConfig>
async getConfigs(tenantId: string): Promise<AssessmentConfig[]>
async getConfig(id: string, tenantId: string): Promise<AssessmentConfig>
async updateConfig(id: string, tenantId: string, settings: Partial<AssessmentConfigSettings>): Promise<AssessmentConfig>
async deleteConfig(id: string, tenantId: string): Promise<void>
async getActiveConfigs(tenantId: string): Promise<AssessmentConfig[]>
}
```
### 3.2 Enhanced Content Filter Service
```typescript
@Injectable()
export class ContentFilterService {
async filterByKeywords(
content: string,
keywords: string[],
method: 'exact' | 'semantic' | 'hybrid' = 'hybrid'
): Promise<string> {
// Extract relevant sections based on keywords
// Use semantic similarity for broader matching
// Return filtered content for question generation
}
}
```
### 3.3 Enhanced Question Generator Node
Modify `generator.node.ts` to accept configuration:
```typescript
interface GeneratorConfig {
keywords?: string[];
questionCount?: number;
difficultyDistribution?: AssessmentConfigSettings['difficultyDistribution'];
style?: AssessmentConfigSettings['style'];
}
export const questionGeneratorNode = async (
state: EvaluationState,
config?: RunnableConfig & { generatorConfig?: GeneratorConfig }
): Promise<Partial<EvaluationState>> {
// 1. Filter knowledge base content by keywords if provided
// 2. Generate questions based on configuration
// 3. Enforce question count and difficulty distribution
// 4. Apply style requirements to question generation
}
```
### 3.4 API Endpoints
#### Config Management
```
POST /api/v1/assessment/configs - Create assessment config
GET /api/v1/assessment/configs - List configs
GET /api/v1/assessment/configs/:id - Get config details
PUT /api/v1/assessment/configs/:id - Update config
DELETE /api/v1/assessment/configs/:id - Delete config
```
#### Enhanced Session Start
```typescript
// Existing: POST /assessment/start
// New parameters supported:
interface StartSessionRequest {
knowledgeBaseId: string;
language?: string;
configId?: string; // Use template
inlineConfig?: AssessmentConfigSettings; // Or use inline config
}
```
---
## 4. Frontend Implementation
### 4.1 New Page: AssessmentTemplatePage
**Location**: `web/src/pages/workspace/AssessmentTemplatePage.tsx`
**Features**:
- List existing templates with quick actions (edit, clone, delete)
- Create new template wizard
- Template preview with configuration summary
- Status toggle (active/inactive)
### 4.2 Enhanced Assessment Start Component
**Location**: `web/components/views/AssessmentView.tsx`
**New UI Elements**:
- Template selection dropdown
- "Use custom settings" toggle for inline config
- Configuration panel with:
- Keywords input (tags)
- Question count slider (1-20)
- Difficulty distribution pie chart/editor
- Style preset buttons
- Advanced settings collapsible section
### 4.3 Configuration UI Components
```typescript
// KeywordsInput.tsx
- Tag-based input for keywords
- Suggestions from knowledge base content
- Visual feedback for keyword matching
// QuestionCountSlider.tsx
- Slider from 1-20 questions
- Smart defaults based on content size
// DifficultyDistribution.tsx
- Interactive pie chart
- Drag to adjust percentages
- Real-time validation (must sum to 100%)
// StylePresets.tsx
- Pre-defined style combinations
- Custom style builder
```
---
## 5. Data Flow & Processing
### 5.1 Content Filtering Pipeline
```
1. Load knowledge base content
2. Apply keyword filtering (semantic similarity)
3. Chunk content into manageable segments
4. Rank segments by relevance to keywords
5. Select top N segments for context
6. Pass filtered content to question generator
```
### 5.2 Question Generation Pipeline
```
1. Receive configuration + filtered content
2. Analyze content for key concepts
3. Generate questions matching:
- Specified count
- Difficulty distribution
- Question types
- Style requirements
4. Validate question quality
5. Return structured question set
```
---
## 6. Security & Validation
### 6.1 Input Validation
```typescript
// Keywords validation
@ValidateNested()
@ArrayMaxSize(50)
keywords: string[];
// Question count validation
@IsInt()
@Min(1)
@Max(20)
questionCount: number;
// Difficulty distribution validation
@ValidateNested()
@IsNotEmpty()
difficultyDistribution: {
@IsInt()
@Min(0)
@Max(100)
standard: number;
// ... similar for advanced, specialist
};
// Validate sum equals 100
@ValidatorConstraint({ name: 'difficultySum', async: false })
export class DifficultySumConstraint implements ValidatorConstraintInterface {
validate(value: any) {
return (value.standard + value.advanced + value.specialist) === 100;
}
}
```
### 6.2 Access Control
- **Tenant Isolation**: Configs scoped to tenant
- **Role-Based Access**: Only admins can manage templates
- **Ownership Tracking**: Track who created/modified each config
---
## 7. Error Handling
### 7.1 Common Error Scenarios
| Error | Cause | Resolution |
|-------|-------|------------|
| `INSUFFICIENT_CONTENT` | Filtered content too short | Relax keyword constraints or select broader keywords |
| `INVALID_CONFIG` | Config validation failed | Return validation errors with specific field issues |
| `CONFIG_NOT_FOUND` | Template ID doesn't exist | Return 404 with config ID |
| `KEYWORD_TOO_SPECIFIC` | No content matches keywords | Suggest broader keywords or use all content |
### 7.2 Error Response Format
```json
{
"error": {
"code": "INSUFFICIENT_CONTENT",
"message": "Filtered content is too short for question generation",
"details": {
"minLength": 1000,
"actualLength": 250,
"suggestedKeywords": ["technology", "software"]
}
}
}
```
---
## 8. Testing Strategy
### 8.1 Unit Tests
**Backend**:
- `AssessmentConfigService` - CRUD operations
- `ContentFilterService` - Keyword filtering logic
- `questionGeneratorNode` - Question generation with config
**Frontend**:
- Configuration UI components
- Template management page
- Integration with existing assessment flow
### 8.2 Integration Tests
- End-to-end assessment creation with templates
- Content filtering accuracy validation
- Question generation quality assessment
### 8.3 Performance Tests
- Large knowledge base filtering
- Multiple concurrent template usage
- API response times under load
---
## 9. Migration Plan
### Phase 1: Database Schema (1 day)
1. Create `assessment_configs` table
2. Add `config_id` and `inline_config` to `assessment_sessions`
3. Create indexes for performance
### Phase 2: Backend API (2 days)
1. Implement `AssessmentConfigService`
2. Create API endpoints
3. Enhance question generator node
4. Add content filtering service
### Phase 3: Frontend UI (2 days)
1. Create template management page
2. Enhance assessment start component
3. Add configuration UI components
4. Integrate with existing flows
### Phase 4: Testing & Polish (1 day)
1. Comprehensive testing
2. Bug fixes
3. Performance optimization
4. Documentation
---
## 10. Success Metrics
### 10.1 Functional Metrics
- ✅ Templates can be created/edited/deleted
- ✅ Question count configurable (1-20)
- ✅ Keywords filter content effectively
- ✅ Style requirements applied to questions
- ✅ Backward compatibility maintained
### 10.2 Quality Metrics
- Question relevance score > 80% (user feedback)
- Content filtering accuracy > 90%
- API response time < 500ms
- Frontend load time < 2s
### 10.3 User Experience
- Template creation time < 2 minutes
- Assessment start with config < 10 seconds
- Configuration UI intuitive (measured by user testing)
---
## 11. Risks & Mitigations
| Risk | Impact | Mitigation |
|------|--------|------------|
| Keyword filtering too restrictive | Low quality questions | Implement semantic matching + fallback |
| Config complexity overwhelms users | Poor adoption | Progressive disclosure + presets |
| Performance degradation with large KB | Slow generation | Content chunking + caching |
| Breaking existing assessments | System disruption | Feature flag + gradual rollout |
---
## 12. Future Enhancements
1. **AI-powered keyword suggestions** based on content analysis
2. **Template sharing** across tenants (with permissions)
3. **Assessment analytics** - track which configs produce best results
4. **Multi-language templates** - store configs in multiple languages
5. **Integration with HR systems** - export assessment results
---
## Appendix A: Configuration Examples
### Example 1: Technical Interview Template
```json
{
"name": "Senior Developer Interview",
"keywords": ["system design", "algorithms", "database", "API", "security"],
"questionCount": 8,
"difficultyDistribution": {
"standard": 25,
"advanced": 50,
"specialist": 25
},
"style": {
"tone": "technical",
"questionTypes": ["technical", "scenario-based"],
"assessmentGoals": ["problem-solving", "critical-thinking"]
}
}
```
### Example 2: Knowledge Check Template
```json
{
"name": "Weekly Training Quiz",
"keywords": [],
"questionCount": 5,
"difficultyDistribution": {
"standard": 70,
"advanced": 30,
"specialist": 0
},
"style": {
"tone": "formal",
"questionTypes": ["multiple-choice", "open-ended"],
"assessmentGoals": ["knowledge-check"]
}
}
```
---
**Document Status**: Ready for review
**Next Steps**:
1. Review this design document
2. Approve or request changes
3. Create implementation plan using writing-plans skill
@@ -0,0 +1,456 @@
# Feishu WebSocket Integration - Design Document
**Date**: 2026-03-17
**Author**: Sisyphus AI Agent
**Status**: Draft for Review
## Executive Summary
Add WebSocket long-connection support for Feishu bot integration, enabling internal network deployment without requiring public domain or internet-facing endpoints. The system will support both existing webhook mode and new WebSocket mode, allowing users to choose their preferred connection method.
---
## 1. Architecture Overview
### Current Architecture (Webhook Mode)
```
Feishu Cloud → Public Domain → NAT/Firewall → Internal Server
└→ POST /api/feishu/webhook/:appId
```
**Limitations:**
- Requires public domain with SSL certificate
- Requires NAT/firewall port forwarding or reverse proxy
- Not suitable for pure internal network deployment
### New Architecture (WebSocket Mode)
```
Feishu Cloud ←──────── WebSocket (wss://open.feishu.cn) ──────── Internal Server
Feishu Cloud → Webhook (optional backup) → Internal Server
```
**Advantages:**
- No public domain required
- No NAT/firewall configuration needed
- Direct connection from internal network to Feishu cloud
- Real-time message delivery (milliseconds vs minutes)
- Connection复用,资源效率更高
### Architecture Diagram
```
┌─────────────────────────────────────────────────────────────┐
│ Feishu Open Platform │
│ (WebSocket Event Subscription) │
└───────────────────────┬─────────────────────────────────────┘
┌─────────────┴─────────────┐
│ │
┌─────▼──────┐ ┌──────▼─────┐
│ Bot A │ │ Bot B │
│ ws://.../A │ │ ws://.../B │
└─────┬──────┘ └──────┬─────┘
│ │
┌─────▼──────────────────────────▼──────┐
│ AuraK Server │
│ ┌──────────────────────────────────┐ │
│ │ FeishuModule │ │
│ │ ┌────────────────────────────┐ │ │
│ │ │ FeishuWsManager │ │ │
│ │ │ - per-bot connections │ │ │
│ │ │ - auto-reconnect │ │ │
│ │ │ - message routing │ │ │
│ │ └────────────────────────────┘ │ │
│ │ ┌────────────────────────────┐ │ │
│ │ │ FeishuService │ │ │
│ │ │ - existing logic │ │ │
│ │ │ - new ws connect/disconnect│ │ │
│ │ └────────────────────────────┘ │ │
│ │ ┌────────────────────────────┐ │ │
│ │ │ FeishuController │ │ │
│ │ │ - webhook endpoints │ │ │
│ │ │ - ws management APIs │ │ │
│ │ └────────────────────────────┘ │ │
│ └──────────────────────────────────┘ │
└──────────────────────────────────────────┘
```
---
## 2. Implementation Plan
### 2.1 New Components
#### 2.1.1 FeishuWsManager
**Purpose**: Manage WebSocket connections for each bot
**Responsibilities:**
- Establish and maintain WebSocket connections
- Handle connection lifecycle (connect, disconnect, reconnect)
- Route incoming messages to appropriate bot handlers
- Manage connection state per bot
**Location**: `server/src/feishu/feishu-ws.manager.ts`
**Key Methods:**
```typescript
class FeishuWsManager {
// Start WebSocket connection for a bot
async connect(bot: FeishuBot): Promise<void>
// Stop WebSocket connection for a bot
async disconnect(botId: string): Promise<void>
// Get connection status
getStatus(botId: string): ConnectionStatus
// Get all active connections
getAllConnections(): Map<string, ConnectionStatus>
}
```
#### 2.1.2 ConnectionStatus Type
```typescript
enum ConnectionState {
DISCONNECTED = 'disconnected',
CONNECTING = 'connecting',
CONNECTED = 'connected',
ERROR = 'error'
}
interface ConnectionStatus {
botId: string
state: ConnectionState
connectedAt?: Date
lastHeartbeat?: Date
error?: string
}
```
### 2.2 Modified Components
#### 2.2.1 FeishuService
**New Methods:**
```typescript
class FeishuService {
// Start WebSocket connection for a bot
async startWsConnection(botId: string): Promise<void>
// Stop WebSocket connection for a bot
async stopWsConnection(botId: string): Promise<void>
// Get connection status
async getWsStatus(botId: string): Promise<ConnectionStatus>
// List all connection statuses
async getAllWsStatuses(): Promise<ConnectionStatus[]>
}
```
#### 2.2.2 FeishuController
**New Endpoints:**
```typescript
// POST /feishu/bots/:id/ws/connect - Start WebSocket connection
// POST /feishu/bots/:id/ws/disconnect - Stop WebSocket connection
// GET /feishu/bots/:id/ws/status - Get connection status
// GET /feishu/ws/status - Get all connection statuses
```
**Modified Endpoints:**
- Keep existing webhook endpoints unchanged
- Add WebSocket status indicator in bot list response
#### 2.2.3 FeishuBot Entity
**New Fields:**
```typescript
@Entity('feishu_bots')
export class FeishuBot {
// ... existing fields ...
@Column({ default: false })
useWebSocket: boolean
@Column({ nullable: true })
wsConnectionState: string
}
```
### 2.3 Feishu SDK Integration
**Package**: `@larksuiteoapi/node-sdk`
**Installation:**
```bash
cd server && yarn add @larksuiteoapi/node-sdk
```
**Configuration:**
```typescript
import { EventDispatcher, Conf } from '@larksuiteoapi/node-sdk'
const client = new EventDispatcher({
appId: bot.appId,
appSecret: bot.appSecret,
verificationToken: bot.verificationToken,
}, {
logger: console
})
```
### 2.4 Event Handling
**Flow for WebSocket Mode:**
```
Feishu Cloud ──WebSocket──> FeishuWsManager.on('message')
Parse event type
┌───────────────┼───────────────┐
│ │ │
im.message. im.message. other
receive_v1 p2p_msg_received
│ │
▼ ▼
FeishuService.processChatMessage()
Send response via
FeishuService.sendTextMessage()
```
### 2.5 Configuration Changes
**Feishu Open Platform:**
Users need to configure in Feishu developer console:
1. Go to "Event Subscription" (事件与回调)
2. Select "Use long connection to receive events" (使用长连接接收事件)
3. Add event: `im.message.receive_v1`
4. **Important**: Must start local WebSocket client first before saving
---
## 3. Data Flow
### WebSocket Message Flow
```
1. User triggers connect API
2. FeishuController.connect(botId)
3. FeishuService.startWsConnection(botId)
4. FeishuWsManager.connect(bot)
5. SDK establishes WebSocket to open.feishu.cn
6. Connection established, events flow:
├─> on('message') ──> _processEvent() ──> _handleMessage()
│ │
│ ▼
│ FeishuService.processChatMessage()
│ │
│ ▼
│ FeishuService.sendTextMessage() (via SDK)
├─> on('error') ──> log error ──> trigger reconnect
└─> on('close') ──> trigger auto-reconnect
```
---
## 4. Error Handling
### Connection Errors
| Error Type | Handling |
|------------|----------|
| Network timeout | Retry with exponential backoff (max 5 attempts) |
| Invalid credentials | Mark bot as error state, notify user |
| Token expired | Refresh token, reconnect |
| Feishu server error | Wait 30s, retry |
### Auto-Reconnect Strategy
```
Initial delay: 1 second
Max delay: 60 seconds
Backoff multiplier: 2x
Max attempts: 5
Reset on successful connection
```
---
## 5. API Design
### 5.1 Connect WebSocket
```
POST /api/feishu/bots/:id/ws/connect
Response 200:
{
"success": true,
"botId": "bot_xxx",
"status": "connecting"
}
Response 400:
{
"success": false,
"error": "Bot not found or disabled"
}
```
### 5.2 Disconnect WebSocket
```
POST /api/feishu/bots/:id/ws/disconnect
Response 200:
{
"success": true,
"botId": "bot_xxx",
"status": "disconnected"
}
```
### 5.3 Get Connection Status
```
GET /api/feishu/bots/:id/ws/status
Response 200:
{
"botId": "bot_xxx",
"state": "connected",
"connectedAt": "2026-03-17T10:00:00Z",
"lastHeartbeat": "2026-03-17T10:05:00Z"
}
```
### 5.4 Get All Statuses
```
GET /api/feishu/ws/status
Response 200:
{
"connections": [
{
"botId": "bot_xxx",
"state": "connected",
"connectedAt": "2026-03-17T10:00:00Z"
},
{
"botId": "bot_yyy",
"state": "disconnected"
}
]
}
```
---
## 6. Security Considerations
1. **Credential Storage**: App ID and App Secret stored encrypted in database
2. **Connection Validation**: Verify bot belongs to authenticated user before connect
3. **Rate Limiting**: Implement per-bot message rate limiting
4. **Connection Limits**: Max 10 concurrent WebSocket connections per server instance
---
## 7. Testing Strategy
### Unit Tests
- FeishuWsManager connection lifecycle
- Message routing logic
- Error handling and reconnection
### Integration Tests
- Full WebSocket connection flow
- Message send/receive cycle
- Reconnection after network failure
### Manual Testing
- Local development without ngrok
- Verify webhook still works alongside WebSocket
---
## 8. Backward Compatibility
- **Existing webhook endpoints**: Unchanged, continue to work
- **Bot configuration**: Existing bots keep webhook mode by default
- **Migration path**: Users can switch to WebSocket anytime via API
- **Dual mode**: Both modes can run simultaneously for different bots
---
## 9. Migration Guide
### For Existing Users
1. Update AuraK to new version (with WebSocket support)
2. Install Feishu SDK: `yarn add @larksuiteoapi/node-sdk`
3. In Feishu Developer Console:
- Start local WebSocket server
- Change event subscription to "Use long connection"
4. Call `POST /api/feishu/bots/:id/ws/connect` to activate
---
## 10. Limitations
1. **Outbound Network Required**: Server must be able to reach `open.feishu.cn` via WebSocket
2. **Single Connection Per Bot**: Each bot needs its own WebSocket connection
3. **Feishu SDK Required**: Must install official SDK, cannot use raw WebSocket
4. **Private Feishu**: Does not support Feishu private deployment (自建飞书)
---
## 11. File Changes Summary
### New Files
- `server/src/feishu/feishu-ws.manager.ts` - WebSocket connection manager
- `server/src/feishu/dto/ws-status.dto.ts` - WebSocket status DTOs
### Modified Files
- `server/src/feishu/feishu.service.ts` - Add WS methods
- `server/src/feishu/feishu.controller.ts` - Add WS endpoints
- `server/src/feishu/entities/feishu-bot.entity.ts` - Add WS fields
- `server/src/feishu/feishu.module.ts` - Register new manager
### Dependencies
- Add: `@larksuiteoapi/node-sdk`
---
## 12. Success Criteria
- [ ] Server can establish WebSocket connection to Feishu
- [ ] Messages received via WebSocket are processed correctly
- [ ] Responses sent back to Feishu via SDK
- [ ] Auto-reconnect works after network interruption
- [ ] Webhook mode continues to work unchanged
- [ ] Both modes can coexist for different bots
- [ ] Internal network deployment works without public domain