Эх сурвалжийг харах

-dev:已配置开发生产配置隔离

LuoChinWen 3 долоо хоног өмнө
parent
commit
8baec51a13

+ 885 - 0
.kiro/specs/task-assignment-template/design.md

@@ -0,0 +1,885 @@
+# Design Document: 任务分配与模板管理
+
+## Overview
+
+本设计文档描述了标注平台的任务分配与模板管理功能的技术实现方案。该功能将完善现有平台的工作流程,实现从管理员(数据源)→ 任务派发 → 人员标注任务分配 → 数据收集 → 数据导出的完整闭环。
+
+主要包含两大模块:
+- **任务分配系统**:支持管理员将任务分配给特定标注人员,标注人员只能看到分配给自己的任务
+- **模板管理系统**:提供类似 LabelStudio 的模板选择界面和自定义 XML 配置编辑器
+
+技术栈:
+- **前端**: React + TypeScript + Jotai + @humansignal/ui + Monaco Editor
+- **后端**: Python FastAPI + SQLite/MySQL
+- **编辑器**: Monaco Editor (XML 语法高亮) + @humansignal/editor (预览)
+
+## Architecture
+
+### System Architecture
+
+```mermaid
+graph TB
+    subgraph "Frontend (web/apps/lq_label)"
+        A[React App] --> B[Layout Component]
+        B --> C[User Management View]
+        B --> D[Task Assignment View]
+        B --> E[Template Manager View]
+        B --> F[Config Editor View]
+        B --> G[Export View]
+        
+        E --> H[Template Gallery]
+        E --> I[Template Preview]
+        
+        F --> J[Monaco Editor]
+        F --> K[Visual Builder]
+        F --> L[Live Preview]
+        
+        A --> M[Jotai State Management]
+    end
+    
+    subgraph "Backend (backend/)"
+        N[FastAPI Server] --> O[User API]
+        N --> P[Task Assignment API]
+        N --> Q[Template API]
+        N --> R[Export API]
+        N --> S[Statistics API]
+        
+        O --> T[Database]
+        P --> T
+        Q --> T
+        R --> T
+        S --> T
+    end
+    
+    A -->|HTTP/REST| N
+```
+
+### Task Assignment Flow
+
+```mermaid
+sequenceDiagram
+    participant Admin as 管理员
+    participant Frontend as 前端
+    participant Backend as 后端
+    participant DB as 数据库
+    
+    Admin->>Frontend: 选择任务
+    Admin->>Frontend: 点击分配按钮
+    Frontend->>Backend: GET /api/users?role=annotator
+    Backend->>DB: 查询标注人员列表
+    DB-->>Backend: 返回用户列表
+    Backend-->>Frontend: 返回用户列表
+    Frontend->>Admin: 显示用户选择对话框
+    Admin->>Frontend: 选择用户并确认
+    Frontend->>Backend: PUT /api/tasks/{id}/assign
+    Backend->>DB: 更新任务分配
+    DB-->>Backend: 确认更新
+    Backend-->>Frontend: 返回更新后的任务
+    Frontend->>Admin: 显示分配成功
+```
+
+### Template Selection Flow
+
+```mermaid
+sequenceDiagram
+    participant Admin as 管理员
+    participant Frontend as 前端
+    participant Editor as 编辑器
+    
+    Admin->>Frontend: 创建项目
+    Frontend->>Admin: 显示模板选择界面
+    Admin->>Frontend: 选择模板类别
+    Frontend->>Admin: 显示模板列表
+    Admin->>Frontend: 选择具体模板
+    Frontend->>Editor: 加载模板配置
+    Editor->>Admin: 显示预览效果
+    Admin->>Frontend: 确认使用模板
+    Frontend->>Frontend: 填充配置到项目表单
+```
+
+## Components and Interfaces
+
+### Frontend Components
+
+#### 1. UserManagementView
+**Location**: `web/apps/lq_label/src/views/user-management-view/`
+
+**Responsibility**: 用户管理界面,显示用户列表和任务统计
+
+**Interface**:
+```typescript
+interface UserManagementViewProps {}
+
+interface UserWithStats {
+  id: string;
+  username: string;
+  email: string;
+  role: 'admin' | 'annotator' | 'viewer';
+  created_at: string;
+  task_stats: {
+    assigned_count: number;
+    completed_count: number;
+    annotation_count: number;
+    completion_rate: number;
+  };
+}
+```
+
+**Features**:
+- 用户列表展示(使用 DataTable)
+- 角色筛选
+- 用户搜索
+- 任务统计显示
+
+#### 2. TaskAssignmentDialog
+**Location**: `web/apps/lq_label/src/components/task-assignment-dialog/`
+
+**Responsibility**: 任务分配对话框
+
+**Interface**:
+```typescript
+interface TaskAssignmentDialogProps {
+  open: boolean;
+  taskIds: string[];
+  onClose: () => void;
+  onAssign: (userId: string) => Promise<void>;
+}
+
+interface AssignableUser {
+  id: string;
+  username: string;
+  email: string;
+  current_task_count: number;
+}
+```
+
+**Features**:
+- 用户选择列表
+- 当前工作量显示
+- 批量分配支持
+- 平均分配选项
+
+#### 3. TemplateGallery
+**Location**: `web/apps/lq_label/src/components/template-gallery/`
+
+**Responsibility**: 模板选择画廊
+
+**Interface**:
+```typescript
+interface TemplateGalleryProps {
+  onSelect: (template: Template) => void;
+  selectedId?: string;
+}
+
+interface Template {
+  id: string;
+  name: string;
+  category: TemplateCategory;
+  description: string;
+  config: string;
+  preview_image?: string;
+  tags: string[];
+}
+
+type TemplateCategory = 
+  | 'image_classification'
+  | 'object_detection'
+  | 'image_segmentation'
+  | 'text_classification'
+  | 'ner'
+  | 'text_labeling'
+  | 'audio_transcription'
+  | 'video_annotation';
+```
+
+**Features**:
+- 分类筛选
+- 模板搜索
+- 模板预览卡片
+- 选中状态显示
+
+#### 4. ConfigEditor
+**Location**: `web/apps/lq_label/src/components/config-editor/`
+
+**Responsibility**: 标注配置编辑器(代码模式 + 可视化模式)
+
+**Interface**:
+```typescript
+interface ConfigEditorProps {
+  value: string;
+  onChange: (value: string) => void;
+  mode: 'code' | 'visual';
+  onModeChange: (mode: 'code' | 'visual') => void;
+  previewData?: Record<string, any>;
+}
+
+interface ValidationResult {
+  valid: boolean;
+  errors: Array<{
+    line: number;
+    column: number;
+    message: string;
+  }>;
+}
+```
+
+**Features**:
+- Monaco Editor 集成(XML 语法高亮)
+- 实时语法验证
+- 错误提示
+- 模式切换
+
+#### 5. VisualConfigBuilder
+**Location**: `web/apps/lq_label/src/components/visual-config-builder/`
+
+**Responsibility**: 可视化配置构建器
+
+**Interface**:
+```typescript
+interface VisualConfigBuilderProps {
+  value: string;
+  onChange: (value: string) => void;
+}
+
+interface ConfigComponent {
+  type: string;
+  name: string;
+  icon: React.ReactNode;
+  category: 'data' | 'annotation' | 'layout';
+  defaultProps: Record<string, any>;
+}
+```
+
+**Features**:
+- 组件面板
+- 拖拽构建
+- 属性编辑面板
+- 组件树视图
+
+#### 6. ConfigPreview
+**Location**: `web/apps/lq_label/src/components/config-preview/`
+
+**Responsibility**: 配置预览面板
+
+**Interface**:
+```typescript
+interface ConfigPreviewProps {
+  config: string;
+  data?: Record<string, any>;
+  onError?: (error: string) => void;
+}
+```
+
+**Features**:
+- LabelStudio 编辑器集成
+- 示例数据支持
+- 错误显示
+- 全屏模式
+
+#### 7. DataExportDialog
+**Location**: `web/apps/lq_label/src/components/data-export-dialog/`
+
+**Responsibility**: 数据导出对话框
+
+**Interface**:
+```typescript
+interface DataExportDialogProps {
+  open: boolean;
+  projectId: string;
+  onClose: () => void;
+}
+
+type ExportFormat = 'json' | 'csv' | 'coco' | 'yolo';
+
+interface ExportOptions {
+  format: ExportFormat;
+  status_filter?: 'all' | 'completed' | 'pending' | 'in_progress';
+  include_metadata: boolean;
+}
+```
+
+**Features**:
+- 格式选择
+- 状态筛选
+- 进度显示
+- 下载触发
+
+#### 8. ProjectStatisticsPanel
+**Location**: `web/apps/lq_label/src/components/project-statistics-panel/`
+
+**Responsibility**: 项目统计面板
+
+**Interface**:
+```typescript
+interface ProjectStatisticsPanelProps {
+  projectId: string;
+}
+
+interface ProjectStatistics {
+  total_tasks: number;
+  completed_tasks: number;
+  in_progress_tasks: number;
+  pending_tasks: number;
+  total_items: number;
+  annotated_items: number;
+  completion_rate: number;
+  user_stats: UserTaskStats[];
+}
+
+interface UserTaskStats {
+  user_id: string;
+  username: string;
+  assigned_tasks: number;
+  completed_tasks: number;
+  annotation_count: number;
+  completion_rate: number;
+}
+```
+
+**Features**:
+- 项目级统计
+- 人员级统计
+- 进度条可视化
+- 实时更新
+
+### Backend API Endpoints
+
+#### User API Extensions
+**Router**: `backend/routers/user.py`
+
+**New Endpoints**:
+```python
+GET    /api/users                    # List all users (admin only)
+GET    /api/users/{id}               # Get user by ID
+GET    /api/users/{id}/stats         # Get user task statistics
+GET    /api/users/annotators         # List annotators for assignment
+```
+
+**Models**:
+```python
+class UserResponse(BaseModel):
+    id: str
+    username: str
+    email: str
+    role: str
+    created_at: datetime
+
+class UserWithStatsResponse(UserResponse):
+    task_stats: TaskStats
+
+class TaskStats(BaseModel):
+    assigned_count: int
+    completed_count: int
+    annotation_count: int
+    completion_rate: float
+```
+
+#### Task Assignment API
+**Router**: `backend/routers/task.py` (扩展)
+
+**New Endpoints**:
+```python
+PUT    /api/tasks/{id}/assign        # Assign task to user
+POST   /api/tasks/batch-assign       # Batch assign tasks
+GET    /api/tasks/my-tasks           # Get current user's tasks
+```
+
+**Models**:
+```python
+class TaskAssignRequest(BaseModel):
+    user_id: str
+
+class BatchAssignRequest(BaseModel):
+    task_ids: List[str]
+    user_ids: List[str]
+    mode: str = 'round_robin'  # 'round_robin' | 'equal'
+```
+
+#### Template API
+**Router**: `backend/routers/template.py`
+
+**Endpoints**:
+```python
+GET    /api/templates                # List all templates
+GET    /api/templates/{id}           # Get template by ID
+GET    /api/templates/categories     # List template categories
+POST   /api/templates/validate       # Validate XML config
+```
+
+**Models**:
+```python
+class TemplateResponse(BaseModel):
+    id: str
+    name: str
+    category: str
+    description: str
+    config: str
+    preview_image: Optional[str]
+    tags: List[str]
+
+class ConfigValidationRequest(BaseModel):
+    config: str
+
+class ConfigValidationResponse(BaseModel):
+    valid: bool
+    errors: List[ValidationError]
+```
+
+#### Export API
+**Router**: `backend/routers/export.py`
+
+**Endpoints**:
+```python
+POST   /api/projects/{id}/export     # Export project annotations
+GET    /api/exports/{id}/status      # Get export job status
+GET    /api/exports/{id}/download    # Download export file
+```
+
+**Models**:
+```python
+class ExportRequest(BaseModel):
+    format: str  # 'json' | 'csv' | 'coco' | 'yolo'
+    status_filter: Optional[str]
+    include_metadata: bool = True
+
+class ExportResponse(BaseModel):
+    export_id: str
+    status: str
+    download_url: Optional[str]
+```
+
+#### Statistics API
+**Router**: `backend/routers/statistics.py`
+
+**Endpoints**:
+```python
+GET    /api/projects/{id}/statistics # Get project statistics
+GET    /api/statistics/overview      # Get overall platform statistics
+```
+
+**Models**:
+```python
+class ProjectStatisticsResponse(BaseModel):
+    total_tasks: int
+    completed_tasks: int
+    in_progress_tasks: int
+    pending_tasks: int
+    total_items: int
+    annotated_items: int
+    completion_rate: float
+    user_stats: List[UserTaskStats]
+```
+
+## Data Models
+
+### Database Schema Extensions
+
+```sql
+-- 预设模板表 (可选,也可以使用静态配置)
+CREATE TABLE templates (
+    id TEXT PRIMARY KEY,
+    name TEXT NOT NULL,
+    category TEXT NOT NULL,
+    description TEXT,
+    config TEXT NOT NULL,
+    preview_image TEXT,
+    tags TEXT,  -- JSON array
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 导出任务表
+CREATE TABLE export_jobs (
+    id TEXT PRIMARY KEY,
+    project_id TEXT NOT NULL,
+    format TEXT NOT NULL,
+    status TEXT DEFAULT 'pending',  -- pending, processing, completed, failed
+    file_path TEXT,
+    error_message TEXT,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    completed_at TIMESTAMP,
+    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
+);
+
+-- 任务分配历史表 (可选,用于追踪分配记录)
+CREATE TABLE task_assignments (
+    id TEXT PRIMARY KEY,
+    task_id TEXT NOT NULL,
+    assigned_to TEXT NOT NULL,
+    assigned_by TEXT NOT NULL,
+    assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
+    FOREIGN KEY (assigned_to) REFERENCES users(id),
+    FOREIGN KEY (assigned_by) REFERENCES users(id)
+);
+```
+
+### State Management (Jotai Atoms)
+
+**Location**: `web/apps/lq_label/src/atoms/`
+
+```typescript
+// userAtoms.ts
+export const usersAtom = atom<UserWithStats[]>([]);
+export const annotatorsAtom = atom<AssignableUser[]>([]);
+export const userLoadingAtom = atom<boolean>(false);
+
+// templateAtoms.ts
+export const templatesAtom = atom<Template[]>([]);
+export const selectedTemplateAtom = atom<Template | null>(null);
+export const templateCategoriesAtom = atom<TemplateCategory[]>([]);
+
+// configEditorAtoms.ts
+export const configValueAtom = atom<string>('');
+export const configValidationAtom = atom<ValidationResult | null>(null);
+export const editorModeAtom = atom<'code' | 'visual'>('code');
+
+// statisticsAtoms.ts
+export const projectStatisticsAtom = atom<ProjectStatistics | null>(null);
+export const statisticsLoadingAtom = atom<boolean>(false);
+
+// exportAtoms.ts
+export const exportJobAtom = atom<ExportJob | null>(null);
+export const exportProgressAtom = atom<number>(0);
+```
+
+### Predefined Templates
+
+模板将以静态配置的形式存储在前端:
+
+```typescript
+// templates/index.ts
+export const PREDEFINED_TEMPLATES: Template[] = [
+  {
+    id: 'image_classification_basic',
+    name: '图像分类 - 基础',
+    category: 'image_classification',
+    description: '简单的图像分类任务,支持单选分类',
+    config: `<View>
+  <Image name="image" value="$image"/>
+  <Choices name="choice" toName="image">
+    <Choice value="类别1"/>
+    <Choice value="类别2"/>
+    <Choice value="类别3"/>
+  </Choices>
+</View>`,
+    tags: ['图像', '分类', '单选'],
+  },
+  {
+    id: 'object_detection_bbox',
+    name: '目标检测 - 边界框',
+    category: 'object_detection',
+    description: '使用矩形框标注图像中的目标',
+    config: `<View>
+  <Image name="image" value="$image"/>
+  <RectangleLabels name="label" toName="image">
+    <Label value="目标1"/>
+    <Label value="目标2"/>
+  </RectangleLabels>
+</View>`,
+    tags: ['图像', '检测', '边界框'],
+  },
+  // ... 更多模板
+];
+```
+
+</text>
+</invoke>
+
+
+## Correctness Properties
+
+*A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
+
+### Property 1: 用户列表筛选正确性
+*For any* 角色筛选值或搜索关键词,返回的用户列表中的所有用户都应该满足筛选条件:
+- 如果按角色筛选,所有用户的 role 字段都应该等于筛选值
+- 如果按关键词搜索,所有用户的 username 或 email 都应该包含该关键词
+
+**Validates: Requirements 1.2, 1.3**
+
+### Property 2: 任务分配正确性
+*For any* 任务和用户的分配操作:
+- 分配后任务的 assigned_to 字段应该等于选择的用户 ID
+- 分配记录应该包含正确的分配时间和分配人信息
+
+**Validates: Requirements 2.3, 2.4**
+
+### Property 3: 批量分配平均性
+*For any* 任务列表和用户列表的批量分配操作(平均分配模式),分配后每个用户分配的任务数量差异不应超过 1。
+
+**Validates: Requirements 2.6**
+
+### Property 4: 标注人员任务可见性
+*For any* 标注人员用户,其任务列表中的所有任务的 assigned_to 字段都应该等于该用户的 ID。任何状态筛选都应该在此基础上进行。
+
+**Validates: Requirements 3.1, 3.2**
+
+### Property 5: 任务状态自动更新
+*For any* 任务,当其所有数据项都被标注后,任务状态应该自动更新为 'completed'。
+
+**Validates: Requirements 3.6**
+
+### Property 6: 模板选择填充
+*For any* 选择的模板,确认选择后项目配置字段的值应该等于模板的 config 值。模板搜索结果中的每个模板的名称或描述都应该包含搜索关键词。
+
+**Validates: Requirements 4.4, 4.5**
+
+### Property 7: XML 配置验证
+*For any* XML 配置字符串,验证结果应该正确反映其语法有效性:
+- 有效的 XML 应该返回 valid: true
+- 无效的 XML 应该返回 valid: false 并包含错误位置信息
+
+**Validates: Requirements 5.3, 5.4**
+
+### Property 8: 配置编辑器同步 (Round-trip)
+*For any* 有效的标注配置:
+- 在代码模式和可视化模式之间切换后,配置内容应该保持语义等价
+- 导出配置后再导入应该得到语义等价的配置
+
+**Validates: Requirements 5.6, 5.8**
+
+### Property 9: 可视化编辑器 XML 生成
+*For any* 组件拖拽或属性修改操作,生成的 XML 代码应该正确反映该操作:
+- 拖拽组件后,XML 应该包含该组件的标签
+- 修改属性后,XML 中对应的属性值应该更新
+
+**Validates: Requirements 6.3, 6.6**
+
+### Property 10: 配置预览错误处理
+*For any* 无效的标注配置,预览面板应该显示错误信息而不是崩溃或显示空白。
+
+**Validates: Requirements 7.5**
+
+### Property 11: 数据导出完整性
+*For any* 导出请求:
+- 导出的数据应该只包含匹配状态筛选条件的任务
+- 导出文件应该包含完整的任务元数据和标注结果
+- 导出格式应该符合所选格式的规范(JSON/CSV/COCO/YOLO)
+
+**Validates: Requirements 8.3, 8.4, 8.5**
+
+### Property 12: 统计数据准确性
+*For any* 项目或用户:
+- 项目统计应该准确反映实际的任务数量和状态分布
+- 用户统计应该准确反映该用户的任务分配和完成情况
+- 进度百分比应该等于 (已标注数 / 总数) * 100
+- 标注操作后统计数据应该立即更新
+
+**Validates: Requirements 9.2, 9.3, 9.6, 9.7**
+
+## Error Handling
+
+### Frontend Error Handling
+
+1. **API 请求错误**
+   - 使用 try-catch 包装所有 API 调用
+   - 显示用户友好的错误消息
+   - 记录错误到控制台
+
+2. **配置验证错误**
+   - 实时显示 XML 语法错误
+   - 高亮错误位置
+   - 提供修复建议
+
+3. **导出错误**
+   - 显示导出失败原因
+   - 支持重试
+   - 提供错误日志下载
+
+4. **编辑器错误**
+   - Monaco Editor 加载失败时显示降级方案
+   - LabelStudio 预览失败时显示错误信息
+
+### Backend Error Handling
+
+1. **权限错误**
+   - 非管理员访问用户管理返回 403
+   - 标注人员访问非分配任务返回 403
+
+2. **数据验证错误**
+   - 无效的 XML 配置返回 400
+   - 无效的导出格式返回 400
+
+3. **资源不存在**
+   - 用户/任务/项目不存在返回 404
+
+4. **导出错误**
+   - 导出失败记录错误日志
+   - 返回失败状态和错误信息
+
+## Testing Strategy
+
+### Unit Testing
+
+**Frontend**:
+- 测试组件渲染和交互
+- 测试状态管理逻辑
+- 测试 XML 验证函数
+- 测试统计计算函数
+
+**Backend**:
+- 测试 API 端点
+- 测试数据库操作
+- 测试导出格式转换
+- 测试权限检查
+
+### Property-Based Testing
+
+**配置**:
+- 前端使用 fast-check
+- 后端使用 Hypothesis
+- 每个属性测试至少运行 100 次迭代
+- 使用 **Feature: task-assignment-template, Property N: {property_text}** 格式标记测试
+
+**重点属性测试**:
+- Property 1: 用户列表筛选
+- Property 3: 批量分配平均性
+- Property 4: 标注人员任务可见性
+- Property 7: XML 配置验证
+- Property 8: 配置编辑器同步
+- Property 11: 数据导出完整性
+- Property 12: 统计数据准确性
+
+### Integration Testing
+
+- 测试完整的任务分配流程
+- 测试模板选择到项目创建流程
+- 测试配置编辑到预览流程
+- 测试数据导出流程
+
+## Implementation Notes
+
+### Monaco Editor Integration
+
+```typescript
+// 安装依赖
+// npm install @monaco-editor/react
+
+import Editor from '@monaco-editor/react';
+
+const ConfigCodeEditor: React.FC<Props> = ({ value, onChange }) => {
+  return (
+    <Editor
+      height="400px"
+      language="xml"
+      value={value}
+      onChange={(value) => onChange(value || '')}
+      options={{
+        minimap: { enabled: false },
+        lineNumbers: 'on',
+        wordWrap: 'on',
+        automaticLayout: true,
+      }}
+    />
+  );
+};
+```
+
+### XML Validation
+
+```typescript
+// 使用 DOMParser 进行 XML 验证
+function validateXML(xml: string): ValidationResult {
+  const parser = new DOMParser();
+  const doc = parser.parseFromString(xml, 'application/xml');
+  const parseError = doc.querySelector('parsererror');
+  
+  if (parseError) {
+    return {
+      valid: false,
+      errors: [{
+        line: 1,
+        column: 1,
+        message: parseError.textContent || 'XML 解析错误',
+      }],
+    };
+  }
+  
+  return { valid: true, errors: [] };
+}
+```
+
+### Export Format Converters
+
+```python
+# backend/services/export_service.py
+
+def export_to_json(annotations: List[Annotation]) -> str:
+    return json.dumps([a.to_dict() for a in annotations], indent=2)
+
+def export_to_csv(annotations: List[Annotation]) -> str:
+    # 使用 pandas 或 csv 模块
+    pass
+
+def export_to_coco(annotations: List[Annotation]) -> str:
+    # COCO 格式转换
+    pass
+
+def export_to_yolo(annotations: List[Annotation]) -> str:
+    # YOLO 格式转换
+    pass
+```
+
+### Statistics Calculation
+
+```python
+# backend/services/statistics_service.py
+
+def calculate_project_statistics(project_id: str) -> ProjectStatistics:
+    with get_db_connection() as conn:
+        cursor = conn.cursor()
+        
+        # 任务统计
+        cursor.execute("""
+            SELECT 
+                COUNT(*) as total,
+                SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
+                SUM(CASE WHEN status = 'in_progress' THEN 1 ELSE 0 END) as in_progress,
+                SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending
+            FROM tasks WHERE project_id = ?
+        """, (project_id,))
+        
+        # 标注统计
+        cursor.execute("""
+            SELECT COUNT(*) as total_annotations
+            FROM annotations a
+            JOIN tasks t ON a.task_id = t.id
+            WHERE t.project_id = ?
+        """, (project_id,))
+        
+        # 用户统计
+        cursor.execute("""
+            SELECT 
+                u.id, u.username,
+                COUNT(DISTINCT t.id) as assigned_tasks,
+                SUM(CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END) as completed_tasks,
+                COUNT(a.id) as annotation_count
+            FROM users u
+            LEFT JOIN tasks t ON t.assigned_to = u.id AND t.project_id = ?
+            LEFT JOIN annotations a ON a.task_id = t.id AND a.user_id = u.id
+            WHERE u.role = 'annotator'
+            GROUP BY u.id, u.username
+        """, (project_id,))
+        
+        # 返回统计结果
+        pass
+```
+
+## Deployment Considerations
+
+### Frontend
+
+- Monaco Editor 需要额外的 webpack 配置
+- 确保 @humansignal/editor 正确集成
+- 配置 CSS 前缀处理
+
+### Backend
+
+- 导出大文件时考虑使用异步任务队列
+- 统计查询可能需要缓存优化
+- 考虑添加导出文件的定期清理
+
+### Database
+
+- 添加必要的索引优化查询性能
+- 考虑统计数据的物化视图

+ 167 - 0
.kiro/specs/task-assignment-template/requirements.md

@@ -0,0 +1,167 @@
+# Requirements Document
+
+## Introduction
+
+本文档定义了标注平台的任务分配与模板管理功能需求。该功能将完善现有平台的工作流程,实现从管理员(数据源)→ 任务派发 → 人员标注任务分配 → 数据收集 → 数据导出的完整闭环。主要包含两大模块:
+
+1. **人员分配管理**:支持管理员将任务分配给特定标注人员,标注人员只能看到分配给自己的任务
+2. **标注模板管理**:提供类似 LabelStudio 的模板选择界面和自定义 XML 配置编辑器
+
+## Glossary
+
+- **Task_Assignment_System**: 任务分配系统,负责将标注任务分配给特定用户
+- **Template_Manager**: 模板管理器,提供预设模板和自定义配置功能
+- **Annotator**: 标注人员,负责执行具体的标注工作
+- **Admin**: 管理员,负责创建项目、分配任务和管理用户
+- **Label_Config**: 标注配置,使用 XML 格式定义标注界面和工具
+- **Template**: 预设模板,包含常用的标注配置(如图像分类、文本标注等)
+- **Config_Editor**: 配置编辑器,支持可视化编辑和代码编辑两种模式
+- **Assignment_Batch**: 批量分配,支持一次性将多个任务分配给多个用户
+- **User_Workload**: 用户工作量,统计用户的任务分配和完成情况
+- **Data_Export**: 数据导出,将标注结果导出为标准格式
+
+## Requirements
+
+### Requirement 1: 用户管理与角色权限
+
+**User Story:** 作为管理员,我想要管理系统用户和查看用户列表,以便我可以将任务分配给合适的标注人员。
+
+#### Acceptance Criteria
+
+1. WHEN 管理员访问用户管理页面 THEN THE Task_Assignment_System SHALL 显示所有用户列表,包括用户名、邮箱、角色和创建时间
+2. WHEN 管理员筛选用户角色 THEN THE Task_Assignment_System SHALL 只显示匹配角色的用户
+3. WHEN 管理员搜索用户 THEN THE Task_Assignment_System SHALL 支持按用户名或邮箱模糊搜索
+4. THE Task_Assignment_System SHALL 显示每个用户的任务统计(已分配任务数、已完成任务数)
+5. WHEN 管理员查看用户详情 THEN THE Task_Assignment_System SHALL 显示该用户的所有任务列表和完成进度
+
+### Requirement 2: 任务分配功能
+
+**User Story:** 作为管理员,我想要将任务分配给特定的标注人员,以便合理分配工作量。
+
+#### Acceptance Criteria
+
+1. WHEN 管理员在任务列表选择任务 THEN THE Task_Assignment_System SHALL 显示分配按钮
+2. WHEN 管理员点击分配按钮 THEN THE Task_Assignment_System SHALL 显示用户选择对话框,列出所有标注人员
+3. WHEN 管理员选择用户并确认分配 THEN THE Task_Assignment_System SHALL 更新任务的 assigned_to 字段
+4. WHEN 任务被分配 THEN THE Task_Assignment_System SHALL 记录分配时间和分配人
+5. THE Task_Assignment_System SHALL 支持批量选择多个任务进行分配
+6. WHEN 管理员批量分配任务 THEN THE Task_Assignment_System SHALL 支持平均分配给多个用户
+7. IF 任务已有分配人员 THEN THE Task_Assignment_System SHALL 显示当前分配人员并允许重新分配
+
+### Requirement 3: 标注人员任务视图
+
+**User Story:** 作为标注人员,我想要只看到分配给我的任务,以便专注于自己的工作。
+
+#### Acceptance Criteria
+
+1. WHEN 标注人员访问任务列表 THEN THE Task_Assignment_System SHALL 只显示分配给该用户的任务
+2. WHEN 标注人员筛选任务状态 THEN THE Task_Assignment_System SHALL 在已分配任务范围内筛选
+3. THE Task_Assignment_System SHALL 显示任务的优先级和截止时间(如果设置)
+4. WHEN 标注人员点击任务 THEN THE Task_Assignment_System SHALL 打开标注界面
+5. THE Task_Assignment_System SHALL 在任务列表显示每个任务的完成进度
+6. WHEN 标注人员完成任务 THEN THE Task_Assignment_System SHALL 自动更新任务状态
+
+### Requirement 4: 预设模板库
+
+**User Story:** 作为管理员,我想要从预设模板中选择标注配置,以便快速创建项目。
+
+#### Acceptance Criteria
+
+1. WHEN 管理员创建项目时 THEN THE Template_Manager SHALL 显示模板选择界面
+2. THE Template_Manager SHALL 提供以下预设模板类别:
+   - 图像分类(Image Classification)
+   - 目标检测(Object Detection)
+   - 图像分割(Image Segmentation)
+   - 文本分类(Text Classification)
+   - 命名实体识别(Named Entity Recognition)
+   - 文本标注(Text Labeling)
+   - 音频转写(Audio Transcription)
+   - 视频标注(Video Annotation)
+3. WHEN 管理员选择模板 THEN THE Template_Manager SHALL 显示模板预览和说明
+4. WHEN 管理员确认选择模板 THEN THE Template_Manager SHALL 将模板配置填充到项目配置字段
+5. THE Template_Manager SHALL 支持模板搜索和筛选功能
+6. WHEN 管理员选择模板后 THEN THE Template_Manager SHALL 允许进一步自定义配置
+
+### Requirement 5: 自定义配置编辑器
+
+**User Story:** 作为管理员,我想要自定义标注配置,以便满足特定的标注需求。
+
+#### Acceptance Criteria
+
+1. THE Config_Editor SHALL 提供代码编辑模式,支持 XML 语法高亮
+2. THE Config_Editor SHALL 提供可视化编辑模式,通过拖拽组件构建配置
+3. WHEN 用户编辑配置 THEN THE Config_Editor SHALL 实时验证 XML 语法
+4. IF XML 语法错误 THEN THE Config_Editor SHALL 显示错误位置和错误信息
+5. THE Config_Editor SHALL 提供实时预览功能,显示标注界面效果
+6. WHEN 用户切换编辑模式 THEN THE Config_Editor SHALL 保持配置内容同步
+7. THE Config_Editor SHALL 提供常用标签的快捷插入功能
+8. THE Config_Editor SHALL 支持配置的导入和导出
+
+### Requirement 6: 可视化配置构建器
+
+**User Story:** 作为管理员,我想要通过可视化界面构建标注配置,以便无需编写 XML 代码。
+
+#### Acceptance Criteria
+
+1. THE Config_Editor SHALL 提供组件面板,包含所有可用的标注组件
+2. THE Config_Editor SHALL 支持以下组件类型:
+   - 数据源组件:Image, Text, Audio, Video, HyperText
+   - 标注工具:Choices, Labels, Rectangle, Polygon, Brush, KeyPoint
+   - 布局组件:View, Header, Style
+3. WHEN 用户拖拽组件到画布 THEN THE Config_Editor SHALL 自动生成对应的 XML 代码
+4. WHEN 用户选择组件 THEN THE Config_Editor SHALL 显示属性面板,允许编辑组件属性
+5. THE Config_Editor SHALL 支持组件的复制、删除和重新排序
+6. WHEN 用户修改组件属性 THEN THE Config_Editor SHALL 实时更新 XML 代码和预览
+
+### Requirement 7: 配置预览功能
+
+**User Story:** 作为管理员,我想要预览标注配置的效果,以便在保存前确认配置正确。
+
+#### Acceptance Criteria
+
+1. THE Config_Editor SHALL 提供预览面板,显示标注界面效果
+2. WHEN 配置更新 THEN THE Config_Editor SHALL 自动刷新预览
+3. THE Config_Editor SHALL 支持使用示例数据进行预览
+4. WHEN 用户提供自定义预览数据 THEN THE Config_Editor SHALL 使用该数据渲染预览
+5. IF 配置无效 THEN THE Config_Editor SHALL 在预览面板显示错误信息
+6. THE Config_Editor SHALL 支持预览面板的全屏模式
+
+### Requirement 8: 数据导出功能
+
+**User Story:** 作为管理员,我想要导出标注结果,以便用于模型训练或其他用途。
+
+#### Acceptance Criteria
+
+1. WHEN 管理员在项目详情页点击导出 THEN THE Data_Export SHALL 显示导出选项对话框
+2. THE Data_Export SHALL 支持以下导出格式:
+   - JSON(原始格式)
+   - CSV(表格格式)
+   - COCO(目标检测格式)
+   - YOLO(YOLO 格式)
+3. WHEN 管理员选择导出格式并确认 THEN THE Data_Export SHALL 生成并下载导出文件
+4. THE Data_Export SHALL 支持筛选导出范围(全部、已完成、指定状态)
+5. THE Data_Export SHALL 在导出文件中包含任务元数据和标注结果
+6. WHEN 导出大量数据 THEN THE Data_Export SHALL 显示进度指示器
+
+### Requirement 9: 标注进度与完成度统计
+
+**User Story:** 作为管理员,我想要查看标注工作的进度和完成度统计,以便监控项目进度和人员工作量。
+
+#### Acceptance Criteria
+
+1. THE Task_Assignment_System SHALL 在项目详情页显示统计面板
+2. THE Task_Assignment_System SHALL 统计以下项目级指标:
+   - 总任务数、已完成数、进行中数、待处理数
+   - 项目整体完成进度百分比
+   - 总标注数据条数、已标注条数、未标注条数
+3. THE Task_Assignment_System SHALL 统计以下人员级指标:
+   - 各标注人员的任务分配数和完成数
+   - 各标注人员的标注数据条数
+   - 各标注人员的完成率
+4. WHEN 管理员查看任务详情 THEN THE Task_Assignment_System SHALL 显示该任务的标注进度(已标注/总数)
+5. THE Task_Assignment_System SHALL 提供进度条可视化展示完成度
+6. WHEN 标注人员完成一条数据标注 THEN THE Task_Assignment_System SHALL 实时更新进度统计
+7. THE Task_Assignment_System SHALL 在任务列表显示每个任务的完成进度百分比
+
+</content>
+</invoke>

+ 327 - 0
.kiro/specs/task-assignment-template/tasks.md

@@ -0,0 +1,327 @@
+# Implementation Plan: 任务分配与模板管理
+
+## Overview
+
+本实现计划将任务分配与模板管理功能分解为可执行的开发任务。任务按照从后端 API 到前端组件的顺序组织,确保每一步都可以独立测试和验证。
+
+## Tasks
+
+- [ ] 1. 后端 - 用户管理 API 扩展
+  - [ ] 1.1 创建用户列表和统计 API
+    - 创建 `backend/routers/user.py` 路由文件
+    - 实现 GET /api/users 端点(管理员权限)
+    - 实现 GET /api/users/{id}/stats 端点
+    - 实现 GET /api/users/annotators 端点(获取可分配用户)
+    - 添加用户任务统计查询逻辑
+    - _Requirements: 1.1, 1.2, 1.3, 1.4_
+
+  - [ ]* 1.2 编写 Property 1 的属性测试
+    - **Property 1: 用户列表筛选正确性**
+    - **Validates: Requirements 1.2, 1.3**
+    - 测试角色筛选和关键词搜索的正确性
+
+- [ ] 2. 后端 - 任务分配 API
+  - [ ] 2.1 扩展任务路由支持分配功能
+    - 在 `backend/routers/task.py` 添加分配端点
+    - 实现 PUT /api/tasks/{id}/assign 端点
+    - 实现 POST /api/tasks/batch-assign 端点
+    - 实现 GET /api/tasks/my-tasks 端点(当前用户任务)
+    - 添加分配记录到数据库
+    - _Requirements: 2.3, 2.4, 2.5, 2.6, 3.1_
+
+  - [ ]* 2.2 编写 Property 2 的属性测试
+    - **Property 2: 任务分配正确性**
+    - **Validates: Requirements 2.3, 2.4**
+    - 测试分配后 assigned_to 字段正确更新
+
+  - [ ]* 2.3 编写 Property 3 的属性测试
+    - **Property 3: 批量分配平均性**
+    - **Validates: Requirements 2.6**
+    - 测试平均分配模式下任务分配的均匀性
+
+  - [ ]* 2.4 编写 Property 4 的属性测试
+    - **Property 4: 标注人员任务可见性**
+    - **Validates: Requirements 3.1, 3.2**
+    - 测试标注人员只能看到分配给自己的任务
+
+- [ ] 3. 后端 - 模板和配置验证 API
+  - [ ] 3.1 创建模板 API
+    - 创建 `backend/routers/template.py` 路由文件
+    - 实现 GET /api/templates 端点
+    - 实现 GET /api/templates/{id} 端点
+    - 实现 GET /api/templates/categories 端点
+    - 实现 POST /api/templates/validate 端点(XML 验证)
+    - 创建预设模板数据
+    - _Requirements: 4.1, 4.2, 4.3, 5.3, 5.4_
+
+  - [ ]* 3.2 编写 Property 7 的属性测试
+    - **Property 7: XML 配置验证**
+    - **Validates: Requirements 5.3, 5.4**
+    - 测试 XML 验证的正确性
+
+- [ ] 4. 后端 - 统计 API
+  - [ ] 4.1 创建统计 API
+    - 创建 `backend/routers/statistics.py` 路由文件
+    - 实现 GET /api/projects/{id}/statistics 端点
+    - 实现项目级统计计算逻辑
+    - 实现用户级统计计算逻辑
+    - _Requirements: 9.1, 9.2, 9.3, 9.7_
+
+  - [ ]* 4.2 编写 Property 12 的属性测试
+    - **Property 12: 统计数据准确性**
+    - **Validates: Requirements 9.2, 9.3, 9.6, 9.7**
+    - 测试统计数据的准确性
+
+- [ ] 5. 后端 - 数据导出 API
+  - [ ] 5.1 创建导出 API
+    - 创建 `backend/routers/export.py` 路由文件
+    - 创建 `backend/services/export_service.py` 服务文件
+    - 实现 POST /api/projects/{id}/export 端点
+    - 实现 JSON 格式导出
+    - 实现 CSV 格式导出
+    - 实现 COCO 格式导出
+    - 实现 YOLO 格式导出
+    - 创建 export_jobs 数据表
+    - _Requirements: 8.1, 8.2, 8.3, 8.4, 8.5_
+
+  - [ ]* 5.2 编写 Property 11 的属性测试
+    - **Property 11: 数据导出完整性**
+    - **Validates: Requirements 8.3, 8.4, 8.5**
+    - 测试导出数据的完整性和格式正确性
+
+- [ ] 6. Checkpoint - 后端 API 完成
+  - 确保所有 API 端点正常工作
+  - 确保所有测试通过
+  - 询问用户是否有问题
+
+- [ ] 7. 前端 - 状态管理扩展
+  - 创建 `atoms/user-management-atoms.ts`
+  - 创建 `atoms/template-atoms.ts`
+  - 创建 `atoms/config-editor-atoms.ts`
+  - 创建 `atoms/statistics-atoms.ts`
+  - 创建 `atoms/export-atoms.ts`
+  - _Requirements: 4.3_
+
+- [ ] 8. 前端 - API 服务扩展
+  - 在 `services/api.ts` 添加用户管理 API 函数
+  - 添加任务分配 API 函数
+  - 添加模板 API 函数
+  - 添加统计 API 函数
+  - 添加导出 API 函数
+  - _Requirements: 10.1_
+
+- [ ] 9. 前端 - 用户管理界面
+  - [ ] 9.1 创建 UserManagementView 组件
+    - 创建 `views/user-management-view/` 目录
+    - 实现用户列表展示(DataTable)
+    - 实现角色筛选功能
+    - 实现用户搜索功能
+    - 实现任务统计显示
+    - _Requirements: 1.1, 1.2, 1.3, 1.4_
+
+  - [ ] 9.2 添加用户管理路由
+    - 在 App.tsx 添加 /users 路由
+    - 在侧边栏添加用户管理菜单项(仅管理员可见)
+    - _Requirements: 1.1_
+
+- [ ] 10. 前端 - 任务分配功能
+  - [ ] 10.1 创建 TaskAssignmentDialog 组件
+    - 创建 `components/task-assignment-dialog/` 目录
+    - 实现用户选择列表
+    - 实现当前工作量显示
+    - 实现单个任务分配
+    - 实现批量分配功能
+    - 实现平均分配选项
+    - _Requirements: 2.1, 2.2, 2.3, 2.5, 2.6, 2.7_
+
+  - [ ] 10.2 更新任务列表视图
+    - 在 TaskListView 添加任务选择功能
+    - 添加分配按钮
+    - 显示当前分配人员
+    - 集成 TaskAssignmentDialog
+    - _Requirements: 2.1, 2.7_
+
+  - [ ] 10.3 创建标注人员任务视图
+    - 更新 TaskListView 支持标注人员模式
+    - 只显示分配给当前用户的任务
+    - 显示任务完成进度
+    - _Requirements: 3.1, 3.2, 3.5_
+
+- [ ] 11. Checkpoint - 任务分配功能完成
+  - 确保任务分配功能正常工作
+  - 确保标注人员只能看到自己的任务
+  - 询问用户是否有问题
+
+- [ ] 12. 前端 - 模板选择功能
+  - [ ] 12.1 创建 TemplateGallery 组件
+    - 创建 `components/template-gallery/` 目录
+    - 实现模板分类筛选
+    - 实现模板搜索
+    - 实现模板卡片展示
+    - 实现模板预览
+    - 实现模板选择
+    - _Requirements: 4.1, 4.2, 4.3, 4.5_
+
+  - [ ] 12.2 创建预设模板数据
+    - 创建 `templates/index.ts` 文件
+    - 添加图像分类模板
+    - 添加目标检测模板
+    - 添加图像分割模板
+    - 添加文本分类模板
+    - 添加命名实体识别模板
+    - 添加文本标注模板
+    - 添加音频转写模板
+    - 添加视频标注模板
+    - _Requirements: 4.2_
+
+  - [ ] 12.3 集成模板选择到项目创建
+    - 更新 ProjectForm 组件
+    - 添加模板选择步骤
+    - 实现模板配置填充
+    - 支持自定义修改
+    - _Requirements: 4.4, 4.6_
+
+  - [ ]* 12.4 编写 Property 6 的属性测试
+    - **Property 6: 模板选择填充**
+    - **Validates: Requirements 4.4, 4.5**
+    - 测试模板选择后配置正确填充
+
+- [ ] 13. 前端 - 配置编辑器
+  - [ ] 13.1 安装 Monaco Editor
+    - 安装 @monaco-editor/react 依赖
+    - 配置 webpack 支持 Monaco Editor
+    - _Requirements: 5.1_
+
+  - [ ] 13.2 创建 ConfigEditor 组件
+    - 创建 `components/config-editor/` 目录
+    - 实现代码编辑模式(Monaco Editor)
+    - 实现 XML 语法高亮
+    - 实现实时语法验证
+    - 实现错误提示显示
+    - 实现模式切换功能
+    - _Requirements: 5.1, 5.3, 5.4, 5.6_
+
+  - [ ]* 13.3 编写 Property 8 的属性测试
+    - **Property 8: 配置编辑器同步 (Round-trip)**
+    - **Validates: Requirements 5.6, 5.8**
+    - 测试模式切换后配置内容同步
+
+- [ ] 14. 前端 - 可视化配置构建器
+  - [ ] 14.1 创建 VisualConfigBuilder 组件
+    - 创建 `components/visual-config-builder/` 目录
+    - 实现组件面板
+    - 实现拖拽功能
+    - 实现组件树视图
+    - 实现属性编辑面板
+    - 实现 XML 代码生成
+    - _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5, 6.6_
+
+  - [ ]* 14.2 编写 Property 9 的属性测试
+    - **Property 9: 可视化编辑器 XML 生成**
+    - **Validates: Requirements 6.3, 6.6**
+    - 测试组件操作后 XML 正确生成
+
+- [ ] 15. 前端 - 配置预览功能
+  - [ ] 15.1 创建 ConfigPreview 组件
+    - 创建 `components/config-preview/` 目录
+    - 集成 @humansignal/editor 预览
+    - 实现示例数据支持
+    - 实现自定义预览数据
+    - 实现错误显示
+    - 实现全屏模式
+    - _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6_
+
+  - [ ]* 15.2 编写 Property 10 的属性测试
+    - **Property 10: 配置预览错误处理**
+    - **Validates: Requirements 7.5**
+    - 测试无效配置的错误处理
+
+- [ ] 16. Checkpoint - 模板和编辑器功能完成
+  - 确保模板选择功能正常工作
+  - 确保配置编辑器功能正常工作
+  - 确保预览功能正常工作
+  - 询问用户是否有问题
+
+- [ ] 17. 前端 - 数据导出功能
+  - [ ] 17.1 创建 DataExportDialog 组件
+    - 创建 `components/data-export-dialog/` 目录
+    - 实现格式选择
+    - 实现状态筛选
+    - 实现导出进度显示
+    - 实现文件下载
+    - _Requirements: 8.1, 8.2, 8.3, 8.4, 8.6_
+
+  - [ ] 17.2 集成导出功能到项目详情
+    - 在 ProjectDetailView 添加导出按钮
+    - 集成 DataExportDialog
+    - _Requirements: 8.1_
+
+- [ ] 18. 前端 - 统计面板
+  - [ ] 18.1 创建 ProjectStatisticsPanel 组件
+    - 创建 `components/project-statistics-panel/` 目录
+    - 实现项目级统计显示
+    - 实现人员级统计显示
+    - 实现进度条可视化
+    - 实现实时更新
+    - _Requirements: 9.1, 9.2, 9.3, 9.4, 9.5, 9.7_
+
+  - [ ] 18.2 集成统计面板到项目详情
+    - 在 ProjectDetailView 添加统计面板
+    - 实现统计数据加载
+    - _Requirements: 9.1_
+
+  - [ ] 18.3 更新任务列表显示进度
+    - 在 TaskListView 显示任务完成进度
+    - 实现进度条组件
+    - _Requirements: 3.5, 9.7_
+
+- [ ] 19. 前端 - 任务状态自动更新
+  - [ ] 19.1 实现任务完成状态自动更新
+    - 在标注保存后检查任务完成状态
+    - 自动更新任务状态为 completed
+    - 更新统计数据
+    - _Requirements: 3.6, 9.6_
+
+  - [ ]* 19.2 编写 Property 5 的属性测试
+    - **Property 5: 任务状态自动更新**
+    - **Validates: Requirements 3.6**
+    - 测试任务完成后状态自动更新
+
+- [ ] 20. Checkpoint - 所有功能完成
+  - 确保所有功能正常工作
+  - 确保所有测试通过
+  - 询问用户是否有问题
+
+- [ ] 21. 集成测试和优化
+  - [ ] 21.1 完整流程测试
+    - 测试管理员创建项目(使用模板)
+    - 测试管理员创建任务
+    - 测试管理员分配任务
+    - 测试标注人员查看任务
+    - 测试标注人员完成标注
+    - 测试管理员查看统计
+    - 测试管理员导出数据
+    - _Requirements: All_
+
+  - [ ] 21.2 性能优化
+    - 优化统计查询性能
+    - 优化大量任务的分配性能
+    - 优化导出大量数据的性能
+    - _Requirements: All_
+
+- [ ] 22. Final Checkpoint - 完整功能验证
+  - 确保所有功能正常工作
+  - 确保所有测试通过
+  - 进行代码审查
+  - 询问用户是否满意
+
+## Notes
+
+- 标记 `*` 的任务为可选测试任务,可以跳过以加快 MVP 开发
+- 每个任务都引用了具体的需求编号以便追溯
+- Checkpoint 任务确保增量验证
+- 属性测试验证通用正确性属性
+- 单元测试验证具体示例和边缘情况
+- 前端和后端任务可以并行开发
+- Monaco Editor 需要额外的 webpack 配置
+- 可视化配置构建器是较复杂的功能,可以在 MVP 后迭代完善

+ 41 - 0
backend/config.dev.yaml

@@ -0,0 +1,41 @@
+# 开发环境配置
+
+# JWT 配置
+jwt:
+  secret_key: "dev-secret-key-for-local-development"
+  algorithm: "HS256"
+  access_token_expire_minutes: 60
+  refresh_token_expire_days: 7
+
+# OAuth 2.0 单点登录配置
+oauth:
+  enabled: true
+  base_url: "http://192.168.92.61:8000"
+  client_id: "sRyfcQwNVoFimigzuuZxhqd36fPkVN5G"
+  client_secret: "96RuKb4obAn9bQ9i5NtINiKBMvF_9uuCR7eNzD9dWQMbOWZaV3P593-8yLOqzWRd"
+  redirect_uri: "http://localhost:4200/auth/callback"
+  scope: "profile email"
+  
+  # OAuth 端点
+  authorize_endpoint: "/oauth/login"
+  token_endpoint: "/oauth/token"
+  userinfo_endpoint: "/oauth/userinfo"
+  revoke_endpoint: "/oauth/revoke"
+
+# 数据库配置
+database:
+  type: "mysql"
+  path: "annotation_platform.db"
+  
+  mysql:
+    host: "192.168.92.61"
+    port: 13306
+    user: "root"
+    password: "Lq123456!"
+    database: "lq_label_dev"
+
+# 服务器配置
+server:
+  host: "0.0.0.0"
+  port: 8003
+  reload: true

+ 14 - 15
backend/config.docker.yaml → backend/config.prod.yaml

@@ -1,10 +1,8 @@
-# Docker 环境配置文件模板
-# 复制此文件为 config.yaml 并修改配置
+# 生产环境配置
 
 # JWT 配置
 jwt:
-  # 生产环境请使用强随机密钥
-  # 生成方式: python -c "import secrets; print(secrets.token_urlsafe(32))"
+  # 生产环境请使用强随机密钥: python -c "import secrets; print(secrets.token_urlsafe(32))"
   secret_key: "CHANGE_THIS_TO_A_SECURE_RANDOM_KEY"
   algorithm: "HS256"
   access_token_expire_minutes: 15
@@ -12,12 +10,14 @@ jwt:
 
 # OAuth 2.0 单点登录配置
 oauth:
-  enabled: false
-  base_url: ""
-  client_id: ""
-  client_secret: ""
-  redirect_uri: ""
+  enabled: true
+  base_url: "http://192.168.92.61:8000"
+  client_id: "sRyfcQwNVoFimigzuuZxhqd36fPkVN5G"
+  client_secret: "96RuKb4obAn9bQ9i5NtINiKBMvF_9uuCR7eNzD9dWQMbOWZaV3P593-8yLOqzWRd"
+  redirect_uri: "http://192.168.92.61:9003/auth/callback"
   scope: "profile email"
+  
+  # OAuth 端点
   authorize_endpoint: "/oauth/login"
   token_endpoint: "/oauth/token"
   userinfo_endpoint: "/oauth/userinfo"
@@ -25,19 +25,18 @@ oauth:
 
 # 数据库配置
 database:
-  type: "mysql"  # sqlite 或 mysql
-  path: "/app/data/annotation_platform.db"  # SQLite 路径
+  type: "mysql"
+  path: "/app/data/annotation_platform.db"
   
-  # MySQL 配置
   mysql:
     host: "192.168.92.61"
     port: 13306
     user: "root"
-    password: "lq123"
+    password: "Lq123456!"
     database: "annotation_platform"
 
 # 服务器配置
 server:
   host: "0.0.0.0"
-  port: 8003
-  reload: false  # 生产环境关闭热重载
+  port: 8000
+  reload: false

+ 37 - 5
backend/config.py

@@ -1,6 +1,7 @@
 """
 Application configuration module.
 Manages JWT and OAuth settings from YAML configuration file.
+Supports dev/prod environments via APP_ENV environment variable.
 """
 import os
 import secrets
@@ -12,12 +13,38 @@ from typing import Dict, Any
 logger = logging.getLogger(__name__)
 
 
+def get_config_path() -> Path:
+    """
+    根据 APP_ENV 环境变量获取配置文件路径
+    APP_ENV=prod -> config.prod.yaml
+    APP_ENV=dev -> config.dev.yaml
+    默认 -> config.yaml (兼容旧配置)
+    """
+    app_env = os.getenv("APP_ENV", "").lower()
+    base_path = Path(__file__).parent
+    
+    if app_env == "prod":
+        config_file = base_path / "config.prod.yaml"
+        logger.info("使用生产环境配置: config.prod.yaml")
+    elif app_env == "dev":
+        config_file = base_path / "config.dev.yaml"
+        logger.info("使用开发环境配置: config.dev.yaml")
+    else:
+        # 兼容旧的 config.yaml
+        print("默认使用开发环境")
+        config_file = base_path / "config.dev.yaml"
+        if app_env:
+            logger.warning(f"未知的 APP_ENV 值: {app_env},使用默认 config.yaml")
+    
+    return config_file
+
+
 class Settings:
     """Application settings loaded from config.yaml."""
     
     def __init__(self):
         """Load configuration from YAML file."""
-        config_path = Path(__file__).parent / "config.yaml"
+        config_path = get_config_path()
         
         if not config_path.exists():
             raise FileNotFoundError(f"配置文件不存在: {config_path}")
@@ -25,6 +52,9 @@ class Settings:
         with open(config_path, 'r', encoding='utf-8') as f:
             config = yaml.safe_load(f)
         
+        # 记录当前环境
+        self.APP_ENV = os.getenv("APP_ENV", "default")
+        
         # JWT Settings
         jwt_config = config.get('jwt', {})
         self.JWT_SECRET_KEY = jwt_config.get('secret_key', secrets.token_urlsafe(32))
@@ -63,12 +93,14 @@ class Settings:
         # Server Settings
         server_config = config.get('server', {})
         self.SERVER_HOST = server_config.get('host', '0.0.0.0')
-        self.SERVER_PORT = server_config.get('port', 8003)
+        self.SERVER_PORT = server_config.get('port', 8000)
         self.SERVER_RELOAD = server_config.get('reload', True)
         
-        # Warn if using default JWT secret
-        if self.JWT_SECRET_KEY == 'your-secret-key-here':
-            logger.warning("使用默认 JWT_SECRET_KEY,生产环境请修改 config.yaml!")
+        # Warn if using default JWT secret in production
+        if self.APP_ENV == "prod" and self.JWT_SECRET_KEY in ['your-secret-key-here', 'CHANGE_THIS_TO_A_SECURE_RANDOM_KEY']:
+            logger.warning("生产环境使用默认 JWT_SECRET_KEY,请立即修改 config.prod.yaml!")
+        elif self.JWT_SECRET_KEY == 'your-secret-key-here':
+            logger.warning("使用默认 JWT_SECRET_KEY,生产环境请修改配置文件!")
 
 
 # Create settings instance

+ 1 - 0
backend/docker-compose.yml

@@ -15,6 +15,7 @@ services:
       # 挂载配置文件(可选,方便修改配置)
       - ./config.yaml:/app/config.yaml:ro
     environment:
+      - APP_ENV=prod
       - DATABASE_PATH=/app/data/annotation_platform.db
     restart: unless-stopped
     healthcheck:

+ 2 - 11
lq_label.conf

@@ -25,7 +25,7 @@ server {
 
     # API 代理到后端
     location /api/ {
-        proxy_pass http://127.0.0.1:8003/api/;
+        proxy_pass http://lq-label-backend:8000/api/;
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@@ -35,16 +35,7 @@ server {
         proxy_read_timeout 30s;
     }
 
-    # OAuth 代理
-    location /auth/ {
-        proxy_pass http://127.0.0.1:8003/auth/;
-        proxy_set_header Host $host;
-        proxy_set_header X-Real-IP $remote_addr;
-        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-        proxy_set_header X-Forwarded-Proto $scheme;
-    }
-
-    # SPA 路由支持
+    # SPA 路由支持(包括 /auth/callback 等前端路由)
     location / {
         try_files $uri $uri/ /index.html;
     }

+ 12 - 0
web/apps/lq_label/webpack.config.js

@@ -16,6 +16,18 @@ module.exports = composePlugins(
     // svgr: false
   }),
   (config) => {
+    // 开发环境代理配置
+    if (config.devServer) {
+      config.devServer.proxy = [
+        {
+          context: ['/api'],
+          target: 'http://localhost:8003',
+          secure: false,
+          changeOrigin: true,
+        },
+      ];
+    }
+
     // Enable WebAssembly support
     config.experiments = {
       ...config.experiments,