Files
PicAnalysis/.project/development-plan.md
wjl 1a0ebde95d feat: 初始化 PicAnalysis 项目
完整的前后端图片分析应用,包含:
- 后端:Express + Prisma + SQLite,101个单元测试全部通过
- 前端:React + TypeScript + Vite,47个单元测试,89.73%覆盖率
- E2E测试:Playwright 测试套件
- MCP集成:Playwright MCP配置完成并测试通过

功能模块:
- 用户认证(JWT)
- 文档管理(CRUD)
- 待办管理(三态工作流)
- 图片管理(上传、截图、OCR)

测试覆盖:
- 后端单元测试:101/101 
- 前端单元测试:47/47 
- E2E测试:通过 
- MCP Playwright测试:通过 

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 20:10:11 +08:00

1066 lines
26 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.
# TDD 开发计划 - 图片OCR与智能文档管理系统
## 项目信息
- **开始日期**: 2026-02-21
- **预计完成**: 2026-04-05 (6周)
- **团队规模**: 1-2人
- **开发方法**: TDD (测试驱动开发)
- **迭代方式**: 1周Sprint
---
## 开发原则
### TDD 核心原则
1. **测试先行**: 在写功能代码前先写测试
2. **小步迭代**: 每次只写一个测试和对应实现
3. **持续重构**: 保持代码的简洁和可维护
4. **快速反馈**: 测试必须快速运行
### Ralph Loop 原则
1. **持续反思**: 每个阶段都要问 @ralph
2. **质疑假设**: 不要理所当然,验证一切
3. **追求简洁**: 寻找最简单的解决方案
4. **学习改进**: 从每个实现中学习
### 代码质量标准
- 代码覆盖率: ≥ 80%
- 测试通过率: 100%
- ESLint: 0错误
- TypeScript: 0类型错误
---
## TDD 开发循环
```
┌─────────────────────────────────────┐
│ 1. 🔴 Red: 写一个失败的测试 │
│ @ralph 这个测试描述正确吗? │
│ @ralph 是否覆盖了核心场景? │
└──────────┬──────────────────────────┘
┌─────────────────────────────────────┐
│ 2. 🟢 Green: 写最小代码通过测试 │
│ @ralph 这是最简单的实现吗? │
│ @ralph 有不必要的复杂度吗? │
└──────────┬──────────────────────────┘
┌─────────────────────────────────────┐
│ 3. 🔵 Blue: 重构优化代码 │
│ @ralph 代码可以更简洁吗? │
│ @ralph 有重复代码吗? │
│ @ralph 命名是否清晰? │
└──────────┬──────────────────────────┘
┌─────────────────────────────────────┐
│ 4. 提交代码 │
│ @ralph 我完成了吗?还有遗漏吗? │
│ @ralph 需要添加文档吗? │
└──────────┬──────────────────────────┘
返回步骤 1 (下一个测试)
```
---
## Sprint 计划
### Sprint 1: 基础架构 (Days 1-5)
#### 任务 1.1: 项目初始化
**时间**: 0.5天
**依赖**: 无
**测试策略**:
- 单元测试: 构建配置正确
- 集成测试: 无
**Ralph 检查点**:
- 开始前: 我是否需要所有这些依赖?
- 实现中: 这个配置是否最小化?
- 完成后: 项目结构是否清晰?
**TDD 循环**:
```typescript
// 1. Red: 测试构建配置
describe('Build Config', () => {
it('should compile TypeScript', () => {
// 验证构建输出
});
it('should have correct dependencies', () => {
// 验证package.json
});
});
```
**验收标准**:
- [ ] 前端项目创建成功 (React + Vite)
- [ ] 后端项目创建成功 (Express + TypeScript)
- [ ] Prisma初始化完成
- [ ] 测试框架配置完成 (Jest + Vitest)
- [ ] Docker配置文件创建
- [ ] ESLint + Prettier配置
---
#### 任务 1.2: 数据库Schema设计
**时间**: 1天
**依赖**: 任务1.1
**测试策略**:
- 单元测试: Schema验证
- 集成测试: Migration成功
**Ralph 检查点**:
- 开始前: 数据模型是否完整?
- 实现中: 关系设计是否正确?
- 完成后: 是否考虑了索引优化?
**TDD 循环**:
```typescript
// 1. Red: 测试Schema
describe('Database Schema', () => {
it('should create user with correct fields', async () => {
const user = await prisma.user.create({
data: { username: 'test', email: 'test@test.com', password_hash: 'hash' }
});
expect(user).toHaveProperty('id');
expect(user).toHaveProperty('created_at');
});
it('should allow image without document', async () => {
const image = await prisma.image.create({
data: { user_id: userId, file_path: '/path', document_id: null }
});
expect(image.document_id).toBeNull();
});
it('should enforce unique username', async () => {
await expect(
prisma.user.create({
data: { username: 'duplicate', ... }
})
).rejects.toThrow();
});
});
```
**验收标准**:
- [ ] Prisma Schema定义完成
- [ ] Migration成功执行
- [ ] 所有实体关系正确
- [ ] 索引定义完成
- [ ] Seed脚本创建
---
#### 任务 1.3: 用户认证系统
**时间**: 1.5天
**依赖**: 任务1.2
**测试策略**:
- 单元测试: 密码加密、JWT生成/验证
- 集成测试: 完整注册登录流程
**Ralph 检查点**:
- 开始前: 安全性考虑是否充分?
- 实现中: 密码存储是否安全?
- 完成后: Token过期是否正确处理
**TDD 循环**:
```typescript
// 1. Red: 测试密码加密
describe('Password Service', () => {
it('should hash password with bcrypt', async () => {
const hash = await PasswordService.hash('password123');
expect(hash).not.toBe('password123');
expect(hash.length).toBe(60);
});
it('should verify correct password', async () => {
const hash = await PasswordService.hash('password123');
const isValid = await PasswordService.verify('password123', hash);
expect(isValid).toBe(true);
});
it('should reject wrong password', async () => {
const hash = await PasswordService.hash('password123');
const isValid = await PasswordService.verify('wrong', hash);
expect(isValid).toBe(false);
});
});
// 1. Red: 测试JWT
describe('Auth Service', () => {
it('should generate valid JWT token', () => {
const token = AuthService.generateToken({ user_id: '123' });
expect(token).toBeTruthy();
const decoded = jwt.verify(token, process.env.JWT_SECRET);
expect(decoded.user_id).toBe('123');
});
it('should verify valid token', () => {
const token = AuthService.generateToken({ user_id: '123' });
const payload = AuthService.verifyToken(token);
expect(payload.user_id).toBe('123');
});
it('should reject expired token', () => {
const expiredToken = '...';
expect(() => AuthService.verifyToken(expiredToken))
.toThrow('Token expired');
});
});
```
**验收标准**:
- [ ] 密码使用bcrypt加密
- [ ] JWT生成和验证正确
- [ ] 注册API完成
- [ ] 登录API完成
- [ ] 认证中间件完成
- [ ] 数据隔离验证通过
---
#### 任务 1.4: 基础API框架
**时间**: 1天
**依赖**: 任务1.3
**测试策略**:
- 单元测试: 路由注册
- 集成测试: API调用
**Ralph 检查点**:
- 开始前: API设计是否RESTful
- 实现中: 错误处理是否统一?
- 完成后: 响应格式是否一致?
**TDD 循环**:
```typescript
// 1. Red: 测试API响应格式
describe('API Response Format', () => {
it('should return success response', async () => {
const response = await request(app)
.post('/api/auth/register')
.send({ username: 'test', password: 'pass123' });
expect(response.status).toBe(201);
expect(response.body).toHaveProperty('success', true);
expect(response.body).toHaveProperty('data');
});
it('should return error response', async () => {
const response = await request(app)
.post('/api/auth/register')
.send({ username: '', password: '' });
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('success', false);
expect(response.body).toHaveProperty('error');
});
});
```
**验收标准**:
- [ ] 统一响应格式
- [ ] 错误处理中间件
- [ ] 请求验证中间件
- [ ] CORS配置
- [ ] 日志中间件
---
#### 任务 1.5: Docker配置
**时间**: 0.5天
**依赖**: 任务1.4
**测试策略**:
- 集成测试: 容器构建和运行
**Ralph 检查点**:
- 开始前: 需要多少容器?
- 实现中: 网络配置是否正确?
- 完成后: 数据卷是否持久化?
**验收标准**:
- [ ] Dockerfile创建 (前后端)
- [ ] docker-compose.yml配置
- [ ] 一键启动脚本
- [ ] 数据卷配置
---
### Sprint 2: 图片与OCR功能 (Days 6-12)
#### 任务 2.1: 图片上传功能
**时间**: 1天
**依赖**: Sprint 1
**测试策略**:
- 单元测试: 文件验证、大小限制
- 集成测试: 上传API
**Ralph 检查点**:
- 开始前: 安全性考虑(文件类型验证)?
- 实现中: 存储路径是否安全?
- 完成后: 大文件处理是否正确?
**TDD 循环**:
```typescript
// 1. Red: 测试文件验证
describe('Image Upload Service', () => {
it('should accept valid image formats', () => {
expect(ImageValidator.isValidFormat('image/jpeg')).toBe(true);
expect(ImageValidator.isValidFormat('image/png')).toBe(true);
});
it('should reject invalid formats', () => {
expect(ImageValidator.isValidFormat('application/pdf')).toBe(false);
expect(ImageValidator.isValidFormat('text/plain')).toBe(false);
});
it('should reject files larger than 10MB', () => {
const largeFile = { size: 11 * 1024 * 1024 };
expect(ImageValidator.isValidSize(largeFile)).toBe(false);
});
it('should accept files under 10MB', () => {
const file = { size: 5 * 1024 * 1024 };
expect(ImageValidator.isValidSize(file)).toBe(true);
});
});
```
**验收标准**:
- [ ] 支持JPG/PNG/WEBP
- [ ] 文件大小验证 (<10MB)
- [ ] 文件类型验证
- [ ] 存储到正确路径
- [ ] 返回图片URL
---
#### 任务 2.2: OCR集成
**时间**: 2天
**依赖**: 任务2.1
**测试策略**:
- 单元测试: 置信度判断、质量检测
- 集成测试: OCR流程
**Ralph 检查点**:
- 开始前: OCR provider选择
- 实现中: 失败处理是否完善?
- 完成后: 性能是否可接受?
**TDD 循环**:
```typescript
// 1. Red: 测试置信度判断
describe('OCR Service', () => {
it('should create document when confidence > threshold', () => {
const result = OCRService.shouldCreateDocument(0.8, 0.3);
expect(result).toBe(true);
});
it('should not create document when confidence < threshold', () => {
const result = OCRService.shouldCreateDocument(0.2, 0.3);
expect(result).toBe(false);
});
it('should handle threshold boundary', () => {
expect(OCRService.shouldCreateDocument(0.3, 0.3)).toBe(true);
expect(OCRService.shouldCreateDocument(0.29, 0.3)).toBe(false);
});
});
// 1. Red: 测试图片质量检测
describe('Image Quality Analyzer', () => {
it('should detect clear image', () => {
const result = QualityAnalyzer.analyze(clearImageBuffer);
expect(result.quality).toBe('good');
expect(result.score).toBeGreaterThan(0.7);
});
it('should detect blurry image', () => {
const result = QualityAnalyzer.analyze(blurryImageBuffer);
expect(result.quality).toBe('poor');
expect(result.score).toBeLessThan(0.3);
});
});
```
**验收标准**:
- [ ] OCR provider抽象层
- [ ] 本地OCR集成可选
- [ ] 云端OCR集成
- [ ] 置信度判断逻辑
- [ ] 失败时保存到待处理列表
- [ ] 异步处理队列
---
#### 任务 2.3: 待处理图片功能
**时间**: 1天
**依赖**: 任务2.2
**测试策略**:
- 单元测试: 查询逻辑
- 集成测试: API
**Ralph 检查点**:
- 开始前: 查询是否高效?
- 实现中: 是否考虑了分页?
**TDD 循环**:
```typescript
// 1. Red: 测试待处理图片查询
describe('Pending Images Service', () => {
it('should return images without document', async () => {
const images = await PendingImagesService.getByUserId(userId);
images.forEach(img => {
expect(img.document_id).toBeNull();
});
});
it('should return failed OCR images', async () => {
const images = await PendingImagesService.getByUserId(userId);
images.forEach(img => {
expect(['failed', 'pending']).toContain(img.processing_status);
});
});
});
```
**验收标准**:
- [ ] 待处理图片列表API
- [ ] 手动创建文档API
- [ ] 图片增强API
- [ ] 删除图片API
---
#### 任务 2.4: 文档管理
**时间**: 1.5天
**依赖**: 任务2.3
**测试策略**:
- 单元测试: CRUD操作
- 集成测试: 文档API
**Ralph 检查点**:
- 开始前: 数据验证是否充分?
- 实现中: 搜索功能是否高效?
**TDD 循环**:
```typescript
// 1. Red: 测试文档CRUD
describe('Document Service', () => {
it('should create document from OCR result', async () => {
const document = await DocumentService.createFromOCR({
ocr_result: 'test text',
image_id: 'img123',
user_id: 'user123'
});
expect(document.content).toBe('test text');
});
it('should search documents by title', async () => {
const results = await DocumentService.search('meeting');
results.forEach(doc => {
expect(doc.title.toLowerCase()).toContain('meeting');
});
});
});
```
**验收标准**:
- [ ] 文档CRUD API
- [ ] 文档搜索功能
- [ ] 文档-图片关联
- [ ] 文档列表分页
---
### Sprint 3: AI智能分析 (Days 13-19)
#### 任务 3.1: AI Provider抽象层
**时间**: 1天
**依赖**: Sprint 2
**测试策略**:
- 单元测试: Provider接口
**Ralph 检查点**:
- 开始前: 接口设计是否通用?
- 实现中: 错误处理是否统一?
**TDD 循环**:
```typescript
// 1. Red: 测试AI Provider接口
describe('AI Provider Interface', () => {
it('should implement analyze method', async () => {
const provider = new GLMProvider();
const result = await provider.analyze('test content');
expect(result).toHaveProperty('tags');
expect(result).toHaveProperty('category');
});
it('should handle API errors gracefully', async () => {
const provider = new GLMProvider();
// Mock API failure
jest.spyOn(provider, 'callAPI').mockRejectedValue(new Error('API Error'));
await expect(provider.analyze('test')).rejects.toThrow();
});
});
```
**验收标准**:
- [ ] AI Provider接口定义
- [ ] GLM集成
- [ ] MiniMax集成
- [ ] DeepSeek集成
- [ ] 统一错误处理
---
#### 任务 3.2: 智能标签生成
**时间**: 1.5天
**依赖**: 任务3.1
**测试策略**:
- 单元测试: 标签提取、新标签创建
- 集成测试: 标签API
**Ralph 检查点**:
- 开始前: 标签数量是否合适?
- 实现中: 新标签验证是否充分?
**TDD 循环**:
```typescript
// 1. Red: 测试标签生成
describe('Tag Generation Service', () => {
it('should extract relevant tags', async () => {
const result = await AIService.generateTags('会议记录:讨论项目进度和下一步计划');
expect(result.tags).toContain('会议');
expect(result.tags).toContain('项目');
});
it('should create new tag when needed', async () => {
const existingTags = ['工作', '个人'];
const result = await AIService.generateTags('发票报销:午餐费用', { existingTags });
expect(result.new_tags).toContain('发票');
});
it('should limit tag count to 5', async () => {
const result = await AIService.generateTags('long text...');
expect(result.tags.length).toBeLessThanOrEqual(5);
});
});
```
**验收标准**:
- [ ] AI生成标签
- [ ] 新标签创建
- [ ] 标签使用统计
- [ ] 常用标签优先展示
---
#### 任务 3.3: 智能分类与类型
**时间**: 1.5天
**依赖**: 任务3.2
**测试策略**:
- 单元测试: 分类推荐
- 集成测试: 分类API
**Ralph 检查点**:
- 开始前: 分类逻辑是否准确?
- 实现中: 新分类命名是否合理?
**TDD 循环**:
```typescript
// 1. Red: 测试分类推荐
describe('Category Suggestion Service', () => {
it('should match existing category', async () => {
const categories = ['会议记录', '学习笔记'];
const result = await AIService.suggestCategory('今天开会讨论了项目进度', { categories });
expect(result.category).toBe('会议记录');
expect(result.is_new).toBe(false);
});
it('should create new category when no match', async () => {
const categories = ['会议记录'];
const result = await AIService.suggestCategory('发票号123456 金额100元', { categories });
expect(result.is_new).toBe(true);
expect(result.category).toBe('发票');
expect(result.suggested_icon).toBeTruthy();
});
});
```
**验收标准**:
- [ ] 匹配现有分类
- [ ] 创建新分类
- [ ] 推荐图标
- [ ] 分类使用统计
---
#### 任务 3.4: AI分析API
**时间**: 1天
**依赖**: 任务3.3
**测试策略**:
- 集成测试: 完整分析流程
**Ralph 检查点**:
- 开始前: API响应时间是否可接受
- 实现中: 降级处理是否完善?
**验收标准**:
- [ ] 分析API
- [ ] 异步处理
- [ ] 轮询状态API
- [ ] 失败降级处理
---
### Sprint 4: 待办管理 (Days 20-26)
#### 任务 4.1: 待办CRUD
**时间**: 1天
**依赖**: Sprint 3
**测试策略**:
- 单元测试: CRUD操作
- 集成测试: 待办API
**TDD 循环**:
```typescript
// 1. Red: 测试待办创建
describe('Todo Service', () => {
it('should create todo from document', async () => {
const todo = await TodoService.createFromDocument({
document_id: 'doc123',
user_id: 'user123',
title: '完成报告'
});
expect(todo.status).toBe('pending');
expect(todo.document_id).toBe('doc123');
});
});
```
**验收标准**:
- [ ] 待办CRUD API
- [ ] 优先级设置
- [ ] 截止日期设置
- [ ] 分类关联
---
#### 任务 4.2: 三状态流转
**时间**: 1.5天
**依赖**: 任务4.1
**测试策略**:
- 单元测试: 状态验证
- 集成测试: 状态流转API
**TDD 循环**:
```typescript
// 1. Red: 测试状态流转
describe('Todo Status Transition', () => {
it('should allow pending to completed', () => {
const result = TodoService.validateTransition('pending', 'completed');
expect(result).toBe(true);
});
it('should allow completed to confirmed', () => {
const result = TodoService.validateTransition('completed', 'confirmed');
expect(result).toBe(true);
});
it('should not allow confirmed to pending', () => {
const result = TodoService.validateTransition('confirmed', 'pending');
expect(result).toBe(false);
});
it('should update timestamps', async () => {
const todo = await TodoService.updateStatus(todoId, 'completed');
expect(todo.completed_at).toBeTruthy();
});
});
```
**验收标准**:
- [ ] 状态验证逻辑
- [ ] 时间戳自动更新
- [ ] 状态流转API
- [ ] 批量操作API
---
#### 任务 4.3: 待办列表与筛选
**时间**: 1天
**依赖**: 任务4.2
**测试策略**:
- 单元测试: 排序逻辑
- 集成测试: 列表API
**TDD 循环**:
```typescript
// 1. Red: 测试待办排序
describe('Todo Sorting', () => {
it('should sort by priority then due date', () => {
const todos = [
{ priority: 'high', due_date: '2024-01-15' },
{ priority: 'high', due_date: '2024-01-10' },
{ priority: 'medium', due_date: '2024-01-10' }
];
const sorted = TodoService.sort(todos);
expect(sorted[0].priority).toBe('high');
expect(sorted[0].due_date).toBe('2024-01-10');
});
});
```
**验收标准**:
- [ ] 三状态列表查询
- [ ] 多条件筛选
- [ ] 排序功能
- [ ] 分页支持
---
### Sprint 5: 前端开发 (Days 27-33)
#### 任务 5.1: 基础布局与路由
**时间**: 1天
**依赖**: Sprint 4
**测试策略**:
- 组件测试: 路由渲染
**验收标准**:
- [ ] 主布局组件
- [ ] 路由配置
- [ ] 导航组件
- [ ] 认证路由守卫
---
#### 任务 5.2: 认证页面
**时间**: 1天
**依赖**: 任务5.1
**测试策略**:
- 组件测试: 表单验证
**TDD 循环**:
```typescript
// 1. Red: 测试登录表单
describe('LoginForm', () => {
it('should show error for empty fields', () => {
render(<LoginForm />);
fireEvent.click(screen.getByText('登录'));
expect(screen.getByText('请输入用户名')).toBeTruthy();
});
it('should call API on valid input', async () => {
const mockLogin = jest.fn();
render(<LoginForm onLogin={mockLogin} />);
// fill form and submit
await waitFor(() => expect(mockLogin).toHaveBeenCalled());
});
});
```
**验收标准**:
- [ ] 登录表单
- [ ] 注册表单
- [ ] 表单验证
- [ ] 错误提示
---
#### 任务 5.3: 图片上传组件
**时间**: 1.5天
**依赖**: 任务5.2
**测试策略**:
- 组件测试: 拖拽、选择、预览
**TDD 循环**:
```typescript
// 1. Red: 测试图片上传
describe('ImageUpload', () => {
it('should accept drag and drop', () => {
const onUpload = jest.fn();
render(<ImageUpload onUpload={onUpload} />);
const dropZone = screen.getByTestId('drop-zone');
fireEvent.drop(dropZone, {
dataTransfer: { files: [new File([''], 'test.png', { type: 'image/png' })] }
});
await waitFor(() => expect(onUpload).toHaveBeenCalled());
});
});
```
**验收标准**:
- [ ] 拖拽上传
- [ ] 文件选择
- [ ] 图片预览
- [ ] 进度显示
- [ ] 错误处理
---
#### 任务 5.4: OCR结果编辑器
**时间**: 1天
**依赖**: 任务5.3
**测试策略**:
- 组件测试: 文本编辑
**验收标准**:
- [ ] 文本编辑区域
- [ ] 图片预览
- [ ] 保存按钮
- [ ] AI分析按钮
---
#### 任务 5.5: 文档管理页面
**时间**: 1.5天
**依赖**: 任务5.4
**测试策略**:
- 组件测试: 列表、搜索、详情
**验收标准**:
- [ ] 文档列表
- [ ] 搜索功能
- [ ] 文档详情
- [ ] 编辑功能
- [ ] 删除功能
---
#### 任务 5.6: 待办管理页面
**时间**: 1.5天
**依赖**: 任务5.5
**测试策略**:
- 组件测试: 三状态列表、批量操作
**TDD 循环**:
```typescript
// 1. Red: 测试待办状态切换
describe('TodoList', () => {
it('should show pending todos by default', () => {
const todos = [{ id: 1, status: 'pending', title: 'Test' }];
render(<TodoList todos={todos} />);
expect(screen.getByText('Test')).toBeTruthy();
});
it('should move todo to completed on click', async () => {
const onComplete = jest.fn();
const todos = [{ id: 1, status: 'pending', title: 'Test' }];
render(<TodoList todos={todos} onComplete={onComplete} />);
fireEvent.click(screen.getByText('完成'));
await waitFor(() => expect(onComplete).toHaveBeenCalledWith(1));
});
});
```
**验收标准**:
- [ ] 三状态Tab
- [ ] 待办卡片
- [ ] 状态切换
- [ ] 批量操作
- [ ] 筛选排序
---
### Sprint 6: 完善与优化 (Days 34-40)
#### 任务 6.1: 配置管理页面
**时间**: 1天
**依赖**: Sprint 5
**验收标准**:
- [ ] OCR提供商配置
- [ ] AI提供商配置
- [ ] 配置测试功能
---
#### 任务 6.2: 待处理图片页面
**时间**: 1天
**依赖**: Sprint 5
**验收标准**:
- [ ] 待处理图片列表
- [ ] 手动创建对话框
- [ ] 图片增强功能
---
#### 任务 6.3: 性能优化
**时间**: 1.5天
**依赖**: 所有Sprint
**验收标准**:
- [ ] 前端代码分割
- [ ] 图片懒加载
- [ ] API响应缓存
- [ ] 数据库查询优化
---
#### 任务 6.4: 测试完善
**时间**: 1天
**依赖**: 所有Sprint
**验收标准**:
- [ ] E2E测试补充
- [ ] 覆盖率达到80%+
- [ ] 所有测试通过
---
#### 任务 6.5: 文档与部署
**时间**: 1.5天
**依赖**: 所有Sprint
**验收标准**:
- [ ] API文档
- [ ] 部署文档
- [ ] Docker镜像构建
- [ ] 一键部署验证
---
## 测试矩阵
| Sprint | 单元测试 | 集成测试 | E2E测试 | 覆盖率目标 |
|--------|---------|---------|---------|-----------|
| Sprint 1 | 20 | 5 | 0 | 80% |
| Sprint 2 | 35 | 10 | 3 | 80% |
| Sprint 3 | 40 | 8 | 2 | 80% |
| Sprint 4 | 30 | 8 | 4 | 85% |
| Sprint 5 | 25 | 5 | 8 | 75% |
| Sprint 6 | 7 | 0 | 2 | 80% |
| **总计** | **157** | **36** | **19** | **80%** |
---
## 技术栈
### 测试框架
- **后端单元**: Jest
- **后端集成**: Supertest
- **前端单元**: Vitest
- **前端组件**: Testing Library
- **E2E**: Playwright
### 代码质量工具
- **Linter**: ESLint
- **Formatter**: Prettier
- **Type Check**: TypeScript
- **Coverage**: c8 / istanbul
---
## 每日流程
### 开发开始
```bash
# 1. 拉取最新代码
git pull
# 2. 运行所有测试确保通过
npm test
# 3. 查看任务列表
# @ralph 我今天要做什么?
```
### TDD 开发循环
```bash
# 1. 🔴 Red: 写失败的测试
# 创建测试文件,描述期望行为
# 2. 🟢 Green: 写最小代码通过
# 实现功能,不考虑代码质量
# 3. 🔵 Blue: 重构优化
# 清理代码,提取抽象
# 4. 提交代码
git add .
git commit -m "feat: description"
```
### 开发结束
```bash
# 1. 运行所有测试
npm test
# 2. 检查覆盖率
npm run test:coverage
# 3. 提交代码
git push
# 4. @ralph 今天我学到了什么?
```
---
## Ralph Loop 检查清单
### 实现前
- @ralph 我是否完全理解了要实现的功能?
- @ralph 有什么边界情况我没考虑到?
- @ralph 这个设计是否遵循 SOLID 原则?
- @ralph 是否有更简单的实现方式?
### 实现中
- @ralph 这段代码是否容易理解?
- @ralph 变量/函数名是否清晰?
- @ralph 是否有重复代码?
- @ralph 这段代码性能如何?
### 实现后
- @ralph 所有测试都通过了吗?
- @ralph 代码可以更简洁吗?
- @ralph 是否需要添加文档?
- @ralph 我从这次实现中学到了什么?
---
## 风险和缓解
| 风险 | 影响 | 概率 | 缓解措施 |
|------|------|------|----------|
| AI API不稳定 | 测试失败 | 中 | 使用Mock减少真实调用 |
| OCR耗时 | 测试慢 | 高 | 使用预设结果 |
| 时间估算偏差 | 延期 | 中 | 预留20%缓冲时间 |
| 需求变更 | 返工 | 低 | 快速反馈,小步迭代 |
---
## 成功指标
### 质量指标
- 代码覆盖率: ≥ 80%
- 测试通过率: 100%
- TypeScript错误: 0
- ESLint错误: 0
### 流程指标
- 每日提交次数: ≥ 5
- 代码审查时间: < 24小时
- Bug修复时间: < 4小时
---
## 下一步
开发计划已制定完成。下一步:
1. **查看Sprint详细计划** - 每个Sprint的具体任务
2. **生成测试骨架** - 创建测试文件模板
3. **开始开发** - 执行第一个TDD循环
```bash
# 查看Sprint 1详细计划
cat .project/sprints/sprint-1.md
# 开始开发
cd backend && npm test
```