Files
label_backend/specs/001-label-backend-spec/tasks.md

27 KiB
Raw Blame History

任务清单label_backend 知识图谱智能标注平台

输入: /specs/001-label-backend-spec/ 全部设计文档
前置条件: plan.md | spec.md | research.md | data-model.md | contracts/ | quickstart.md

格式说明

  • [P]: 可并行执行(不同文件,无未完成任务的依赖)
  • [USn]: 对应 spec.md 中的用户故事编号
  • 每条任务包含精确的文件路径

Phase 1: 项目初始化

目标: 创建 Maven 项目骨架、基础配置和 Docker 环境

  • T001 创建 Maven 项目骨架(com.label GroupIdlabel-backend ArtifactIdJava 17 编译目标)
  • T002 配置 pom.xmlSpring Boot 3、Apache Shiro 1.13.x、MyBatis Plus 3.5.x、Spring Data Redis、AWS S3 SDK v2、Testcontainers、Lombok
  • T003 [P] 创建 sql/init.sql(按依赖顺序建全部 11 张表sys_company → sys_user → source_data → annotation_task → annotation_result → training_dataset → export_batch → sys_config → sys_operation_log → annotation_task_history → video_process_job含所有索引和初始配置数据
  • T004 [P] 创建 docker-compose.ymlpostgres、redis、rustfs、backend、ai-service、frontend 六个服务,含健康检查)和后端 Dockerfileeclipse-temurin:17-jre-alpine
  • T005 创建 src/main/resources/application.yml数据源、Redis、RustFS、AI 服务 base-url、Shiro 相关配置项)

检查点: Maven 编译通过(mvn compileDocker Compose up -d 全部服务健康


Phase 2: 公共基础设施(阻塞性前置条件)

目标: 所有业务模块依赖的公共组件。必须全部完成后用户故事阶段才能开始

⚠️ 重要: 此阶段未完成前任何用户故事均不可开始实现

  • T006 创建 Result<T>ResultCodePageResult<T>src/main/java/com/label/common/result/(统一响应格式:{"code":"SUCCESS","data":{...}}
  • T007 [P] 创建 BusinessException(含 codemessagehttpStatus)和 GlobalExceptionHandler@RestControllerAdvice)— src/main/java/com/label/common/exception/
  • T008 [P] 创建 CompanyContextThreadLocalset/get/clear 三个方法clear 必须在 finally 块调用)— src/main/java/com/label/common/context/CompanyContext.java
  • T009 创建 RedisKeyManager(三个静态方法:tokenKeyuserPermKeytaskClaimKey)和 RedisServicesrc/main/java/com/label/common/redis/
  • T010 创建 MyBatis Plus 配置类 MybatisPlusConfig,注册 TenantLineInnerInterceptor(从 CompanyContext 获取 companyId 自动注入 WHERE 子句;sys_companysys_config 加入忽略表列表)— src/main/java/com/label/common/config/MybatisPlusConfig.java
  • T011 创建 StateValidatorassertTransition 泛型方法,违规时抛出 BusinessException("INVALID_STATE_TRANSITION",...))— src/main/java/com/label/common/statemachine/StateValidator.java
  • T012 [P] 创建 SourceStatus 枚举PENDING/PREPROCESSING/EXTRACTING/QA_REVIEW/APPROVED含 TRANSITIONS Mapsrc/main/java/com/label/common/statemachine/SourceStatus.java
  • T013 [P] 创建 TaskStatus 枚举UNCLAIMED/IN_PROGRESS/SUBMITTED/APPROVED/REJECTED含 TRANSITIONS Map含 IN_PROGRESS→IN_PROGRESS 用于 ADMIN 强制转移)— src/main/java/com/label/common/statemachine/TaskStatus.java
  • T014 [P] 创建 DatasetStatus 枚举PENDING_REVIEW/APPROVED/REJECTED含 TRANSITIONS Mapsrc/main/java/com/label/common/statemachine/DatasetStatus.java
  • T015 [P] 创建 VideoJobStatus 枚举PENDING/RUNNING/SUCCESS/FAILED/RETRYING含 TRANSITIONS Map注释说明 FAILED→PENDING 由 ADMIN 手动触发)— src/main/java/com/label/common/statemachine/VideoJobStatus.java
  • T016 创建 @OperationLog 注解(typetargetType 两个属性,@Around 级别)— src/main/java/com/label/common/aop/OperationLog.java
  • T017 创建 AuditAspect@Around("@annotation(operationLog)"),在 finally 块以独立操作写入 sys_operation_log;审计写入失败只记录 error 日志,禁止抛出异常回滚业务)— src/main/java/com/label/common/aop/AuditAspect.java
  • T018 [P] 创建 RustFsClientAWS S3 SDK v2 封装endpoint 指向 RustFS实现 uploaddownloaddeletegetPresignedUrl)— src/main/java/com/label/common/storage/RustFsClient.java
  • T019 [P] 创建 AiServiceClientRestClient 封装8 个端点:extractTextextractImageextractFramesvideoToTextgenTextQagenImageQastartFinetunegetFinetuneStatus)— src/main/java/com/label/common/ai/AiServiceClient.java
  • T020 创建 Shiro 三件套:TokenFilter(解析 Authorization: Bearer {uuid},查 Redis token:{uuid},注入 CompanyContext,请求结束 finally 清理 ThreadLocalUserRealm(先查 Redis user:perm:{userId} TTL 5min未命中查 PGaddInheritedRoles)、ShiroConfig(过滤器链:/api/auth/loginanon/api/**tokenFilter)— src/main/java/com/label/common/shiro/
  • T021 创建 AbstractIntegrationTestTestcontainers启动真实 PostgreSQL + Redis 容器,执行 sql/init.sql注入测试用的公司和用户数据src/test/java/com/label/AbstractIntegrationTest.java
  • T022 集成测试:ShiroFilterIntegrationTest(无 Token → 401有效 Token 但角色不足 → 403有效 Token 且角色满足 → 200src/test/java/com/label/integration/ShiroFilterIntegrationTest.java
  • T023 单元测试:StateMachineTest(验证所有枚举的合法转换通过;非法转换抛出 BusinessException("INVALID_STATE_TRANSITION"))— src/test/java/com/label/unit/StateMachineTest.java

检查点: 基础设施就绪,所有 Phase 3+ 的用户故事可并行开始


Phase 3: 用户故事 1 — 用户登录与身份认证(优先级: P1🎯 MVP

目标: 用户可以用用户名和密码登录,获得会话凭证,使用凭证访问受保护接口,退出后凭证立即失效

独立测试: 登录 → 获取 Token → 访问 /api/auth/me 返回用户信息 → 退出 → 再次访问返回 401

  • T024 [P] [US1] 创建 SysCompany 实体MyBatis Plus @TableName)和 SysCompanyMappersrc/main/java/com/label/module/user/entity/SysCompany.java + mapper/SysCompanyMapper.java
  • T025 [P] [US1] 创建 SysUser 实体(passwordHash 字段加 @JsonIgnore)和 SysUserMapper(含 selectByCompanyAndUsername 方法)— src/main/java/com/label/module/user/entity/SysUser.java + mapper/SysUserMapper.java
  • T026 [US1] 实现 AuthServicelogin()BCrypt 校验密码 → UUID v4 Token → Redis Hash 存储 userId/role/companyId/username → 设置 TTL = token_ttl_seconds 配置值);logout()(删除 Redis Token Keysrc/main/java/com/label/module/user/service/AuthService.java
  • T027 [US1] 实现 AuthControllerPOST /api/auth/loginanon,调用 AuthService.login())、POST /api/auth/logout(已登录)、GET /api/auth/me(返回当前用户信息);所有响应用 Result<T> 包装 — src/main/java/com/label/module/user/controller/AuthController.java
  • T028 [US1] 集成测试:正确密码登录返回 TokenToken 有效时 /api/auth/me 返回 200主动退出后再访问返回 401错误密码登录返回 401 — src/test/java/com/label/integration/AuthIntegrationTest.java

检查点: US1 独立可测试 — 登录/退出流程完整可用


Phase 4: 用户故事 2 — 原始资料上传(优先级: P1

目标: 上传员可以上传文本/图片/视频,查询自己的资料列表;管理员可查看全公司资料

独立测试: 上传文本文件 → 列表查到 → 详情含预签名 URL → 管理员可删除

  • T029 [P] [US2] 创建 SourceData 实体(含 parentSourceId 自引用字段)和 SourceDataMapper(含 updateStatus 方法)— src/main/java/com/label/module/source/entity/SourceData.java + mapper/SourceDataMapper.java
  • T030 [US2] 实现 SourceServiceupload()(先 insert 获取 ID → 构造路径 → 上传 RustFS → 更新 filePathlist()UPLOADER 按 uploaderId 过滤ADMIN 不过滤,强制分页);findById()(含 15 分钟预签名 URLdelete()(仅 PENDING 状态可删,同步删 RustFS 文件)— src/main/java/com/label/module/source/service/SourceService.java
  • T031 [US2] 实现 SourceControllerPOST /api/source/uploadGET /api/source/listGET /api/source/{id}DELETE /api/source/{id}@RequiresRoles 注解声明权限;所有响应 Result<T> 包装)— src/main/java/com/label/module/source/controller/SourceController.java
  • T032 [US2] 集成测试UPLOADER 上传文本/图片 → 列表仅返回自己的资料ADMIN 查看列表返回全部;上传视频 → source_data 状态为 PENDING视频预处理 Phase 9 覆盖);已进入流水线的资料删除返回 409 — src/test/java/com/label/integration/SourceIntegrationTest.java

检查点: US2 独立可测试 — 上传/查询/删除流程完整可用


Phase 5: 用户故事 3+4 — 提取阶段标注与审批(优先级: P1

目标: 标注员可以领取任务并发安全、AI 辅助预标注、编辑并提交;审批员可以通过(自动触发 QA 任务)或驳回(标注员可重领)

独立测试: 创建任务 → 标注员领取 → AI 预标注 → 提交 → 审批通过 → QA 任务自动出现在任务池

实体与数据层

  • T033 [P] [US3] 创建 AnnotationTask 实体 + AnnotationTaskMapper(含 claimTask(taskId, userId, companyId) 方法SQLUPDATE ... SET status='IN_PROGRESS', claimed_by=?, claimed_at=NOW() WHERE id=? AND status='UNCLAIMED' AND company_id=?,返回影响行数)— src/main/java/com/label/module/task/entity/AnnotationTask.java + mapper/AnnotationTaskMapper.java
  • T034 [P] [US3] 创建 AnnotationTaskHistory 实体 + TaskHistoryMappersrc/main/java/com/label/module/task/entity/AnnotationTaskHistory.java + mapper/TaskHistoryMapper.java
  • T035 [P] [US3] 创建 AnnotationResult 实体 + AnnotationResultMapper(含 updateResultJson 整体覆盖方法和 selectByTaskId 方法)— src/main/java/com/label/module/annotation/entity/AnnotationResult.java + mapper/AnnotationResultMapper.java

任务管理服务与控制器

  • T036 [US3] 实现 TaskClaimService.claim()(① Redis SET NX task:claim:{taskId} TTL 30s失败抛 TASK_CLAIMED;② DB claimTask() 影响行数为 0 时抛 TASK_CLAIMED;③ insertHistory(UNCLAIMED→IN_PROGRESS))和 unclaim()StateValidator + 清 Redis 锁 + 历史)和 reclaim()(校验 REJECTED + claimedBy = 当前用户 + REJECTED→IN_PROGRESS + 历史)— src/main/java/com/label/module/task/service/TaskClaimService.java
  • T037 [US3] 实现 TaskServicecreateTaskgetPool按角色过滤ANNOTATOR→UNCLAIMED/EXTRACTIONREVIEWER→SUBMITTEDgetMine(含 IN_PROGRESS/SUBMITTED/REJECTEDgetPendingReviewSUBMITTED分页getByIdreassignADMIN仅更新 claimedBy + 历史))— src/main/java/com/label/module/task/service/TaskService.java
  • T038 [US3] 实现 TaskController10 个端点:POST /api/tasksGET /api/tasks/poolPOST /api/tasks/{id}/claimPOST /api/tasks/{id}/unclaimGET /api/tasks/minePOST /api/tasks/{id}/reclaimGET /api/tasks/pending-reviewGET /api/tasks/{id}GET /api/tasksPUT /api/tasks/{id}/reassign)— src/main/java/com/label/module/task/controller/TaskController.java

提取标注服务与控制器

  • T039 [US3] 实现 ExtractionService.aiPreAnnotate()(调用 AiServiceClient.extractText/extractImage,写入 annotation_result)和 updateResult()(整体覆盖 result_json,校验 JSON 格式)— src/main/java/com/label/module/annotation/service/ExtractionService.java
  • T040 [US3] 实现 ExtractionService.submit()@TransactionalIN_PROGRESS→SUBMITTED + submitted_at + insertHistorysrc/main/java/com/label/module/annotation/service/ExtractionService.java
  • T041 [US4] 创建 ExtractionApprovedEvent(携带 taskIdsourceIdsourceTypecompanyId)— src/main/java/com/label/module/annotation/event/ExtractionApprovedEvent.java
  • T042 [US4] 实现 ExtractionService.approve()@Transactional:① 自审校验;② is_final=true;③ SUBMITTED→APPROVED + completedAt + 历史;④ publishEvent(ExtractionApprovedEvent)AI 调用禁止在此事务内执行)— src/main/java/com/label/module/annotation/service/ExtractionService.java
  • T043 [US4] 实现 ExtractionApprovedEventListener@TransactionalEventListener(AFTER_COMMIT) + @Transactional(REQUIRES_NEW):调用 AI 生成候选问答对 → 写 training_datasetPENDING_REVIEW→ 创建 QA_GENERATION 任务UNCLAIMEDsource_data 状态→ QA_REVIEWsrc/main/java/com/label/module/annotation/service/ExtractionApprovedEventListener.java
  • T044 [US4] 实现 ExtractionService.reject()@Transactional:① 自审校验;② StateValidator③ SUBMITTED→REJECTED + 历史)— src/main/java/com/label/module/annotation/service/ExtractionService.java
  • T045 [US4] 实现 ExtractionController5 个端点:GET /api/extraction/{taskId}PUT /api/extraction/{taskId}POST /api/extraction/{taskId}/submitPOST /api/extraction/{taskId}/approvePOST /api/extraction/{taskId}/reject)— src/main/java/com/label/module/annotation/controller/ExtractionController.java

集成测试

  • T046 [US3] 并发集成测试10 个线程同时争抢同一 UNCLAIMED 任务,验证恰好 1 人成功、其余均收到 TASK_CLAIMED 错误、DB 中 claimed_by 唯一 — src/test/java/com/label/integration/TaskClaimConcurrencyTest.java
  • T047 [US4] 集成测试:审批通过 → QA 任务自动出现在任务池;自审返回 SELF_REVIEW_FORBIDDEN 403驳回后标注员可重领并再次提交 — src/test/java/com/label/integration/ExtractionApprovalIntegrationTest.java

检查点: US3+US4 独立可测试 — 完整提取流水线领取→标注→提交→审批→QA任务自动创建可用


Phase 6: 用户故事 5 — 问答生成阶段标注与审批(优先级: P2

目标: 标注员领取 QA 任务、修改候选问答对并提交;审批员通过后训练样本入库,整条流水线完成

独立测试: 领取 QA 任务 → 修改问答对 → 提交 → 审批通过 → training_dataset 状态 APPROVEDsource_data 状态 APPROVED

  • T048 [P] [US5] 创建 TrainingDataset 实体 + TrainingDatasetMapper(含 approveByTaskIddeleteByTaskId 方法)— src/main/java/com/label/module/annotation/entity/TrainingDataset.java + mapper/TrainingDatasetMapper.java
  • T049 [US5] 实现 QaService.updateResult()(整体覆盖问答对 JSONBsubmit()@TransactionalIN_PROGRESS→SUBMITTED + 历史)— src/main/java/com/label/module/annotation/service/QaService.java
  • T050 [US5] 实现 QaService.approve()@Transactional:① validateAndGetTask 先于一切 DB 写入;② 自审校验;③ training_dataset → APPROVEDannotation_task → APPROVED + 历史;⑤ source_data → APPROVEDsrc/main/java/com/label/module/annotation/service/QaService.java
  • T051 [US5] 实现 QaService.reject()@Transactional:① 自审校验;② deleteByTaskId 清除候选问答对;③ SUBMITTED→REJECTED + 历史;④ source_data 保持 QA_REVIEW 不变)— src/main/java/com/label/module/annotation/service/QaService.java
  • T052 [US5] 实现 QaController5 个端点:GET /api/qa/{taskId}PUT /api/qa/{taskId}POST /api/qa/{taskId}/submitPOST /api/qa/{taskId}/approvePOST /api/qa/{taskId}/reject)— src/main/java/com/label/module/annotation/controller/QaController.java
  • T053 [US5] 集成测试QA 审批通过 → training_dataset.status = APPROVEDsource_data.status = APPROVEDQA 驳回 → 候选记录被删除,标注员可重领 — src/test/java/com/label/integration/QaApprovalIntegrationTest.java

检查点: US5 独立可测试 — 完整 QA 流水线可用training_dataset 产出验证通过


Phase 7: 用户故事 6 — 训练数据导出与微调提交(优先级: P2

目标: 管理员将已审批样本批量导出为 JSONL并可提交 GLM 微调任务

独立测试: 选取已审批样本 → 创建批次 → RustFS 中存在 JSONL 文件 → 提交微调 → 可查询状态

  • T054 [P] [US6] 创建 ExportBatch 实体 + ExportBatchMappersrc/main/java/com/label/module/export/entity/ExportBatch.java + mapper/ExportBatchMapper.java
  • T055 [US6] 实现 ExportService.createBatch()@Transactional:① 校验全部样本为 APPROVED② 生成 JSONL每行一个 glm_format_json);③ 上传 RustFS finetune-export/export/{batchUuid}.jsonl;④ 批量更新 export_batch_id/exported_at;⑤ 插入 export_batch 记录)— src/main/java/com/label/module/export/service/ExportService.java
  • T056 [US6] 实现 FinetuneServicetrigger()(调用 AiServiceClient.startFinetune(),更新 glm_job_idfinetune_status = RUNNING)和 getStatus()(调用 AiServiceClient.getFinetuneStatus())— src/main/java/com/label/module/export/service/FinetuneService.java
  • T057 [US6] 实现 ExportControllerGET /api/training/samplesPOST /api/export/batchPOST /api/export/{batchId}/finetuneGET /api/export/{batchId}/statusGET /api/export/list;全部 @RequiresRoles("ADMIN"))— src/main/java/com/label/module/export/controller/ExportController.java
  • T058 [US6] 集成测试:成功创建批次后 JSONL 文件存在于 RustFS包含非 APPROVED 样本时返回 INVALID_SAMPLES 400 — src/test/java/com/label/integration/ExportIntegrationTest.java

检查点: US6 独立可测试 — 导出批次创建和微调提交流程可用


Phase 8: 用户故事 7 — 用户与权限管理(优先级: P2

目标: 管理员可以创建用户、变更角色(立即生效)、禁用账号(立即失效)

独立测试: 创建标注员用户 → 验证其能领取任务 → 升为审批员 → 验证立即可以审批 → 禁用账号 → 已有 Token 立即失效

  • T059 [US7] 实现 UserServicecreateUser()BCrypt 哈希密码,强度因子 ≥ 10updateUser()updateRole()DB 写入后立即 redisTemplate.delete(userPermKey(userId))updateStatus()(禁用时删 Redis Token + 权限缓存)— src/main/java/com/label/module/user/service/UserService.java
  • T060 [US7] 实现 UserControllerGET /api/usersPOST /api/usersPUT /api/users/{id}PUT /api/users/{id}/statusPUT /api/users/{id}/role;全部 @RequiresRoles("ADMIN"))— src/main/java/com/label/module/user/controller/UserController.java
  • T061 [US7] 集成测试:变更角色后权限下一次请求立即生效(无需重新登录);禁用账号后现有 Token 下一次请求立即返回 401 — src/test/java/com/label/integration/UserManagementIntegrationTest.java

检查点: US7 独立可测试 — 用户管理和即时权限变更可用


Phase 9: 用户故事 8 — 视频处理与系统配置(优先级: P3

目标: 上传视频后触发异步预处理(帧提取/转文字AI 回调幂等处理;管理员可配置 Prompt 模板等系统参数

独立测试(视频): 上传视频 → 创建处理任务 → 模拟成功回调 → annotation_task 出现在任务池;重复成功回调 → 任务数量不增加
独立测试(配置): 为公司设置专属 Prompt → 验证该公司使用新值;其他公司使用全局默认

  • T062 [P] [US8] 创建 VideoProcessJob 实体 + VideoProcessJobMappersrc/main/java/com/label/module/video/entity/VideoProcessJob.java + mapper/VideoProcessJobMapper.java
  • T063 [P] [US8] 创建 SysConfig 实体 + SysConfigMapper(含 selectByCompanyAndKey(companyId, configKey) 方法,支持 companyId IS NULL 查询)— src/main/java/com/label/module/config/entity/SysConfig.java + mapper/SysConfigMapper.java
  • T064 [US8] 实现 VideoProcessServicecreateJob()@Transactionalsource_data.status → PREPROCESSING + 插入 job + 触发 AI 异步调用);handleCallback()@Transactional:幂等检查 status==SUCCESS 则 return成功 → SUCCESS + source_data.status → PENDING;失败 → 按 retry_count 决定 RETRYING 或 FAILEDreset()FAILED → PENDINGsrc/main/java/com/label/module/video/service/VideoProcessService.java
  • T065 [US8] 实现 VideoControllerPOST /api/video/processGET /api/video/jobs/{jobId}POST /api/video/jobs/{jobId}/resetPOST /api/video/callback内部接口IP 白名单或服务密钥保护))— src/main/java/com/label/module/video/controller/VideoController.java
  • T066 [US8] 实现 SysConfigService.get(configKey)(先按 (companyId, key) 查;未命中按 (NULL, key) 查全局默认)和 update(key, value)UPSERT公司级配置不存在则创建存在则覆盖src/main/java/com/label/module/config/service/SysConfigService.java
  • T067 [US8] 实现 SysConfigControllerGET /api/config(合并公司级 + 全局,标注 scopePUT /api/config/{key};均 @RequiresRoles("ADMIN"))— src/main/java/com/label/module/config/controller/SysConfigController.java
  • T068 [US8] 集成测试:同一 jobId 两次成功回调,annotation_task 记录数为 1幂等达最大重试次数后 status = FAILED — src/test/java/com/label/integration/VideoCallbackIdempotencyTest.java
  • T069 [US8] 集成测试:公司级配置覆盖同 Key 的全局默认;其他公司读取全局默认 — src/test/java/com/label/integration/SysConfigIntegrationTest.java

检查点: US8 独立可测试 — 视频处理幂等和配置管理可用


Phase 10: 收尾与横切关注点

目标: 多租户隔离验证、整体合规检查、快速启动验证

  • T070 集成测试:MultiTenantIsolationTest(公司 A 身份查询公司 B 的资料/任务 → 返回空列表或 404不泄露数据src/test/java/com/label/integration/MultiTenantIsolationTest.java
  • T071 [P] 代码审查:检查所有 Controller 方法返回值均为 Result<T>Result<PageResult<T>>,无裸 POJO 或裸 List 返回
  • T072 [P] 代码审查:检查所有列表查询方法均含分页参数(page/pageSize),无 selectAll() 或不分页的查询
  • T073 [P] 代码审查:检查 sys_operation_log 相关代码,确认应用层零处 UPDATE 或 DELETE
  • T074 [P] 代码审查:检查所有 @Transactional 方法内无 AiServiceClient 的同步 HTTP 调用(审批触发 AI 必须通过 @TransactionalEventListener
  • T075 运行 quickstart.md 端到端验证:docker compose up -d → 登录 → 上传文件 → 创建任务 → 领取 → 提交 → 审批通过 → 确认 QA 任务出现

依赖关系与执行顺序

阶段依赖

Phase 1初始化
    ↓
Phase 2基础设施[全部完成后解锁所有用户故事]
    ↓
Phase 3US1 认证)     ← 可与 Phase 4/5/6/7/8/9 并行
Phase 4US2 上传)     ← 依赖 Phase 2独立于其他用户故事
Phase 5US3+4 提取)   ← 依赖 Phase 2上传已有资料的集成测试依赖 US2
Phase 6US5 QA      ← 依赖 Phase 5 完成QA 任务由提取审批自动创建)
Phase 7US6 导出)     ← 依赖 Phase 6 完成(需要 APPROVED 的 training_dataset
Phase 8US7 用户管理)  ← 依赖 Phase 3UserService 在 AuthService 基础上扩展)
Phase 9US8 视频+配置) ← 依赖 Phase 2其余独立
    ↓
Phase 10收尾

用户故事间依赖

  • US1认证: 仅依赖 Phase 2完全独立
  • US2上传: 仅依赖 Phase 2完全独立
  • US3+4提取: 依赖 Phase 2集成测试中使用已上传资料需 US2
  • US5QA: 依赖 US3+4QA 任务来源于提取阶段审批通过的级联触发)
  • US6导出: 依赖 US5需要 APPROVED 状态的 training_dataset
  • US7用户管理: 依赖 US1UserService 扩展 AuthService 的用户实体)
  • US8视频+配置): 仅依赖 Phase 2

阶段内并行机会

  • Phase 2T007-T010、T012-T015、T018-T019 均可并行(独立文件)
  • Phase 3T024、T025 可并行(独立文件)
  • Phase 5T033、T034、T035 可并行(独立文件)
  • Phase 9T062、T063 可并行(独立文件)
  • Phase 10T071-T074 全部可并行(仅代码审查,无文件修改)

并行执行示例

Phase 2 基础设施并行

同时启动:
  任务: "创建 BusinessException、GlobalExceptionHandler — common/exception/"  [T007]
  任务: "创建 CompanyContextThreadLocal— common/context/"  [T008]
  任务: "创建 RustFsClient — common/storage/"  [T018]
  任务: "创建 AiServiceClient — common/ai/"  [T019]
  任务: "创建 SourceStatus 枚举"  [T012]
  任务: "创建 TaskStatus 枚举"  [T013]

Phase 5 提取阶段并行

同时启动(实体/Mapper
  任务: "创建 AnnotationTask 实体 + Mapper"  [T033]
  任务: "创建 AnnotationTaskHistory 实体 + Mapper"  [T034]
  任务: "创建 AnnotationResult 实体 + Mapper"  [T035]

实施策略

MVP 优先(仅用户故事 1

  1. 完成 Phase 1初始化
  2. 完成 Phase 2基础设施关键,阻塞所有故事
  3. 完成 Phase 3US1 认证)
  4. 停止并验证: 登录/退出/权限校验全流程可用
  5. 可以独立部署演示认证功能

增量交付

  1. Phase 1 + Phase 2 → 基础就绪
  2. Phase 3US1→ 验证 → 演示MVP
  3. Phase 4US2→ 验证 → 演示(上传功能)
  4. Phase 5US3+4→ 验证 → 演示(标注流程)
  5. Phase 6US5→ 验证 → 演示(完整双阶段流水线)
  6. Phase 7US6→ 验证 → 演示(训练数据产出)
  7. Phase 8+9 → 验证 → 演示(完整平台)
  8. Phase 10 → 收尾

多人协作策略

Phase 2 完成后:

  • 开发者 APhase 3US1 认证)+ Phase 8US7 用户管理)
  • 开发者 BPhase 4US2 上传)+ Phase 5US3+4 提取)
  • 开发者 CPhase 9US8 视频+配置)

Phase 5 完成后:

  • 开发者 A/B 合力Phase 6US5 QA→ Phase 7US6 导出)

说明

  • [P] 任务 = 不同文件,无依赖,可并行
  • [USn] 标签将任务映射到具体用户故事,便于追踪
  • 每个用户故事应独立可完成和可测试
  • 每完成一个阶段后提交 git commit
  • 在每个检查点停下来独立验证该用户故事
  • 避免:模糊任务、同文件并发冲突、破坏独立性的跨故事依赖