# 测试指南:剧本上传自动创建子项目 **功能**: 剧本上传时自动创建独立的子项目工作空间 **实施日期**: 2026-02-06 **关联 RFC**: [RFC 141](../rfcs/141-screenplay-auto-create-subproject.md) --- ## 测试前准备 ### 1. 环境要求 ```bash # 确保服务运行 docker-compose ps # 预期输出: # server Running # postgres Running # redis Running # celery Running ``` ### 2. 获取测试数据 ```bash # 获取 Token TOKEN="your-jwt-token" # 获取父项目 ID(必须有 editor 权限) PARENT_PROJECT_ID="019c3456-7890-7abc-def0-000000000000" ``` --- ## 测试场景 ### 场景 1:自动创建子项目(默认行为) #### 测试步骤 ```bash # 上传 PDF 文件(异步解析) curl -X POST http://localhost:6170/api/v1/screenplays/file \ -H "Authorization: Bearer $TOKEN" \ -F "project_id=$PARENT_PROJECT_ID" \ -F "name=测试剧本-自动子项目" \ -F "file=@test-screenplay.pdf" ``` #### 预期响应 ```json { "code": 201, "message": "文件上传成功,正在解析...", "data": { "screenplayId": "019c3456-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "name": "测试剧本-自动子项目", "type": "file", "projectId": "019c3456-yyyy-yyyy-yyyy-yyyyyyyyyyyy", // ← 子项目 ID "fileUrl": "screenplays/source/2026/02/06/xxx.pdf", "parsingStatus": "parsing", "taskId": "celery-task-xxx", "subproject": { // ← 子项目信息 "projectId": "019c3456-yyyy-yyyy-yyyy-yyyyyyyyyyyy", "name": "测试剧本-自动子项目", "parentProjectId": "019c3456-7890-7abc-def0-000000000000", "screenplayId": "019c3456-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "type": 1, "description": "基于剧本《测试剧本-自动子项目》的制作项目", "folderId": "...", "createdAt": "2026-02-06T..." } } } ``` #### 验证数据库 ```sql -- 1. 验证子项目创建 SELECT id, name, parent_project_id, screenplay_id, description FROM projects WHERE name = '测试剧本-自动子项目'; -- 预期结果: -- parent_project_id = <父项目ID> -- screenplay_id = <剧本ID> -- 2. 验证剧本关联 SELECT screenplay_id, name, project_id FROM screenplays WHERE name = '测试剧本-自动子项目'; -- 预期结果: -- project_id = <子项目ID>(而非父项目ID) ``` --- ### 场景 2:禁用自动创建子项目 #### 测试步骤 ```bash # 上传 TXT 文件(同步解析),禁用自动创建 curl -X POST http://localhost:6170/api/v1/screenplays/file \ -H "Authorization: Bearer $TOKEN" \ -F "project_id=$PARENT_PROJECT_ID" \ -F "name=测试剧本-无子项目" \ -F "file=@test-screenplay.txt" \ -F "auto_create_subproject=false" ``` #### 预期响应 ```json { "code": 201, "message": "文件上传成功", "data": { "screenplayId": "019c3456-zzzz-zzzz-zzzz-zzzzzzzzzzzz", "name": "测试剧本-无子项目", "type": "file", "projectId": "019c3456-7890-7abc-def0-000000000000", // ← 父项目 ID "parsingStatus": "completed", "content": "...", "subproject": null // ← 无子项目 } } ``` #### 验证数据库 ```sql -- 验证剧本直接归属父项目 SELECT screenplay_id, name, project_id FROM screenplays WHERE name = '测试剧本-无子项目'; -- 预期结果: -- project_id = <父项目ID>(而非子项目ID) -- 验证没有创建子项目 SELECT COUNT(*) FROM projects WHERE name = '测试剧本-无子项目'; -- 预期结果:0 ``` --- ### 场景 3:协作项目权限继承 #### 测试步骤 ```bash # 1. 创建协作项目(type=2) COLLAB_PROJECT_ID="..." # 2. 添加成员到协作项目 # (通过项目管理 API) # 3. 上传剧本,自动创建子项目 curl -X POST http://localhost:6170/api/v1/screenplays/file \ -H "Authorization: Bearer $TOKEN" \ -F "project_id=$COLLAB_PROJECT_ID" \ -F "name=协作剧本" \ -F "file=@test.pdf" ``` #### 验证权限继承 ```sql -- 1. 获取父项目成员 SELECT user_id, role FROM project_members WHERE project_id = '<协作项目ID>'; -- 2. 验证子项目成员 SELECT user_id, role FROM project_members WHERE project_id = '<子项目ID>'; -- 预期:子项目成员列表与父项目一致 ``` --- ### 场景 4:事务回滚测试 #### 测试步骤 ```bash # 故意传入无效的父项目 ID curl -X POST http://localhost:6170/api/v1/screenplays/file \ -H "Authorization: Bearer $TOKEN" \ -F "project_id=invalid-uuid" \ -F "name=测试事务" \ -F "file=@test.pdf" ``` #### 预期行为 - ❌ 返回错误响应(400 或 404) - ✅ 数据库中没有创建任何记录(剧本、子项目、附件) - ✅ MinIO 中没有上传文件 --- ## 性能测试 ### 响应时间测试 ```bash # 测试 10 次上传,计算平均响应时间 for i in {1..10}; do time curl -X POST http://localhost:6170/api/v1/screenplays/file \ -H "Authorization: Bearer $TOKEN" \ -F "project_id=$PARENT_PROJECT_ID" \ -F "name=性能测试-$i" \ -F "file=@test.pdf" \ > /dev/null 2>&1 done ``` #### 预期性能 - **同步解析(TXT)**: < 300ms - **异步解析(PDF)**: < 500ms - **增量开销**: +50-100ms(相比不创建子项目) --- ## 常见问题排查 ### 问题 1:响应中 subproject 为 null **可能原因**: 1. 设置了 `auto_create_subproject=false` 2. Service 层抛出异常但被捕获 **排查步骤**: ```bash # 检查服务器日志 docker-compose logs server | grep "剧本创建" # 预期日志: # "子项目创建成功 | 子项目ID: ..." # "剧本创建成功 | 剧本ID: ... | 子项目ID: ..." ``` ### 问题 2:数据库中子项目的 screenplay_id 为 NULL **可能原因**: - 更新子项目的步骤失败 **排查步骤**: ```sql -- 检查子项目状态 SELECT id, name, screenplay_id, parent_project_id FROM projects WHERE parent_project_id IS NOT NULL ORDER BY created_at DESC LIMIT 10; ``` ### 问题 3:权限错误 **错误信息**: "没有权限在此项目中创建子项目" **解决方案**: - 确保用户在父项目中拥有 `editor` 权限 - 检查 `project_members` 表 --- ## 回滚方案 如需临时禁用自动创建子项目: ### 方法 1:修改 API 默认值 ```python # server/app/api/v1/screenplays.py auto_create_subproject: bool = Form(False) # ← 改为 False ``` ### 方法 2:前端传参 ```javascript // 在所有上传请求中添加 formData.append('auto_create_subproject', 'false'); ``` --- ## 相关文档 - [RFC 141: 剧本上传自动创建子项目](../rfcs/141-screenplay-auto-create-subproject.md) - [Changelog](../changelogs/2026-02-06-screenplay-auto-create-subproject.md) - [需求文档:子项目架构](../../requirements/backend/04-services/project/subproject-architecture.md)