# Project Code Analysis Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add project-bound code analysis that reads the current generated project source, calls the existing AI task service, saves history, and supports continue generation. **Architecture:** Reuse the existing EasyCode front workbench, preview source service, AI async task table, and generation history table. Add a small backend code-analysis layer that builds a safe source summary from preview output and exposes semantic endpoints; add a Vue page that starts tasks, polls status, shows history, and renders/export reports. **Tech Stack:** Spring Boot, MyBatis XML, existing DeepSeek AI service integration, Vue 3, Element Plus, node:test source assertions. --- ## File Map - `ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/GenerateCodeAnalysisRequest.java`: request fields for fresh and continue generation. - `ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/CodeAnalysisResponse.java`: AI result payload and source snapshot metadata. - `ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/CodeAnalysisSourceSummary.java`: safe code snapshot summary used by UI and prompt. - `ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/CodeAnalysisHistoryResponse.java`: history item wrapper with parsed response. - `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/ProjectCodeAnalysisService.java`: collect preview source, filter files, build prompt context, list and load history. - `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/IAiGenerateService.java`: add `generateCodeAnalysis`. - `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerateServiceImpl.java`: build code-analysis prompt and parse AI response. - `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerationTaskServiceImpl.java`: allow `code_analysis`. - `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerationTaskWorker.java`: execute `code_analysis` tasks. - `ruoyi-generator/src/main/resources/mapper/front/FrontProjectGenerationMapper.xml`: add user/project scoped generation lookup. - `ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/front/FrontProjectGenerationMapper.java`: expose lookup method. - `ruoyi-admin/src/main/java/com/ruoyi/web/controller/front/FrontProjectController.java`: add code-analysis semantic endpoints. - `easycode-web/src/api/project.js`: add code-analysis API wrappers. - `easycode-web/src/router/index.js`: add `/project/:projectId/code-analysis`. - `easycode-web/src/views/CodeAnalysisView.vue`: page UI, history, task polling, continue generation, report export. - `easycode-web/src/views/codeAnalysisView.test.mjs`: front-end source assertions. - `easycode-web/src/views/ProjectListView.vue`, `PreviewView.vue`, `GenerateView.vue`: add project-level entry buttons. - Relevant backend tests under `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/` and `ruoyi-admin/src/test/java/com/ruoyi/web/controller/front/`. --- ### Task 1: Backend DTOs and Source Summary Service **Files:** - Create: `ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/GenerateCodeAnalysisRequest.java` - Create: `ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/CodeAnalysisResponse.java` - Create: `ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/CodeAnalysisSourceSummary.java` - Create: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/ProjectCodeAnalysisService.java` - Test: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/ProjectCodeAnalysisServiceTest.java` - [ ] **Step 1: Write failing source summary tests** Create `ProjectCodeAnalysisServiceTest.java` with tests that use a fake `IFrontProjectPreviewService` returning nested nodes and file contents. Include these behaviors: ```java @Test public void shouldCollectAllowedPreviewFilesAndSkipBuildArtifacts() { ProjectCodeAnalysisService service = newServiceWithPreview( node("backend:src/main/java/com/example/UserController.java", "UserController.java", "file"), node("backend:target/classes/App.class", "App.class", "file"), node("frontend:node_modules/vue/index.js", "index.js", "file")); CodeAnalysisSourceSummary summary = service.buildSourceSummary(1L, 10L); assertEquals(1, summary.getAnalyzedFileCount()); assertTrue(summary.getIncludedFiles().get(0).getPath().contains("UserController.java")); assertTrue(summary.getSkippedFiles().stream().anyMatch(file -> file.getReason().contains("构建产物"))); } @Test public void shouldTrimLargeFilesAndKeepSummaryUsable() { String large = repeat("public void method() {}\n", 7000); ProjectCodeAnalysisService service = newServiceWithContent("backend:src/main/java/App.java", large); CodeAnalysisSourceSummary summary = service.buildSourceSummary(1L, 10L); assertEquals(1, summary.getAnalyzedFileCount()); assertTrue(summary.getIncludedFiles().get(0).getContent().length() < large.length()); assertTrue(summary.getWarnings().stream().anyMatch(value -> value.contains("超过 100KB"))); } ``` - [ ] **Step 2: Run tests and verify RED** Run: `mvn -pl ruoyi-generator -Dtest=ProjectCodeAnalysisServiceTest test` Expected: compile fails because `ProjectCodeAnalysisService` and DTO classes do not exist. - [ ] **Step 3: Add DTOs** Implement DTOs with JavaBean getters/setters: ```java public class GenerateCodeAnalysisRequest { private String mode; private Long previousGenerationId; private String previousMarkdown; private String extraRequirements; // getters and setters } ``` `CodeAnalysisResponse` fields: `title`, `markdown`, `sections`, `sourceSnapshot`, `warnings`. `CodeAnalysisSourceSummary` fields: `projectId`, `fileCount`, `analyzedFileCount`, `skippedFileCount`, `charCount`, `estimatedTokens`, `includedFiles`, `skippedFiles`, `warnings`, `promptContext`. Add nested static classes `SourceFile` and `SkippedFile`. - [ ] **Step 4: Implement minimal source summary service** `ProjectCodeAnalysisService.buildSourceSummary(userId, projectId)` should: - call `frontProjectPreviewService.getStructure` for `backend`, `frontend`, `admin_frontend`, `sql`; - walk `children`; - include only configured code extensions; - skip `node_modules`, `target`, `dist`, `.git`, `.idea`; - create `PreviewFileRequest` with `templateType`, `nodeId`, `tableId`, `category`; - read `content` from `frontProjectPreviewService.getFileContent`; - trim content above `100 * 1024` characters; - build `promptContext` from file path headings and content. - [ ] **Step 5: Run tests and verify GREEN** Run: `mvn -pl ruoyi-generator -Dtest=ProjectCodeAnalysisServiceTest test` Expected: tests pass. - [ ] **Step 6: Commit** ```bash git add ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/GenerateCodeAnalysisRequest.java \ ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/CodeAnalysisResponse.java \ ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/CodeAnalysisSourceSummary.java \ ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/ProjectCodeAnalysisService.java \ ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/ProjectCodeAnalysisServiceTest.java git commit -m "feat: collect project source for code analysis" ``` --- ### Task 2: AI Task Type and Generation **Files:** - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/IAiGenerateService.java` - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerateServiceImpl.java` - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerationTaskServiceImpl.java` - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerationTaskWorker.java` - Test: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiGenerationTaskServiceImplTest.java` - Test: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiGenerationTaskWorkerTest.java` - Test: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiGenerateServiceImplTest.java` - [ ] **Step 1: Write failing task acceptance tests** Add assertions that `code_analysis` is accepted: ```java @Test public void createTaskShouldAcceptCodeAnalysisType() { AiGenerationTaskCreateRequest request = new AiGenerationTaskCreateRequest(); request.setGenerateType("code_analysis"); AiGenerationTaskStatusResponse response = service.createTask(1L, 100L, request); assertEquals("code_analysis", response.getGenerateType()); assertEquals("QUEUED", response.getStatus()); } ``` Add worker test verifying dispatch calls `generateCodeAnalysis`: ```java @Test public void workerShouldExecuteCodeAnalysisTask() { AiGenerationTask task = queuedTask("code_analysis"); mapper.insertAiGenerationTask(task); worker.processTask(task.getTaskId()); assertTrue(aiGenerateService.codeAnalysisCalled); assertEquals("SUCCEEDED", mapper.selectAiGenerationTaskById(task.getTaskId()).getStatus()); } ``` - [ ] **Step 2: Run tests and verify RED** Run: `mvn -pl ruoyi-generator -Dtest=AiGenerationTaskServiceImplTest,AiGenerationTaskWorkerTest test` Expected: unsupported generate type or missing interface method. - [ ] **Step 3: Add interface and task dispatch** Add to `IAiGenerateService`: ```java CodeAnalysisResponse generateCodeAnalysis(Long userId, Long projectId, GenerateCodeAnalysisRequest request); ``` Allow `code_analysis` in `AiGenerationTaskServiceImpl.validateRequest()`. In `AiGenerationTaskWorker.execute()` add: ```java if ("code_analysis".equals(task.getGenerateType())) { return aiGenerateService.generateCodeAnalysis(task.getUserId(), task.getProjectId(), toCodeAnalysisRequest(request)); } ``` Add `toCodeAnalysisRequest()` mapping `mode`, `previousGenerationId`, `previousMarkdown`, `extraRequirements`. - [ ] **Step 4: Add prompt generation test** In `AiGenerateServiceImplTest`, assert prompt contains fixed sections and source context: ```java @Test public void codeAnalysisPromptShouldRequireFixedSectionsAndUseSourceSummary() { CodeAnalysisResponse response = service.generateCodeAnalysis(1L, 100L, new GenerateCodeAnalysisRequest()); String prompt = deepSeekClient.lastPrompt(); assertTrue(prompt.contains("项目概述与技术栈")); assertTrue(prompt.contains("系统架构与核心模块")); assertTrue(prompt.contains("核心业务流程")); assertTrue(prompt.contains("数据库设计")); assertTrue(prompt.contains("答辩准备")); assertTrue(prompt.contains("不要编造未出现的模块")); } ``` - [ ] **Step 5: Implement AI generation method** In `AiGenerateServiceImpl.generateCodeAnalysis()`: - call `projectCodeAnalysisService.buildSourceSummary(userId, projectId)`; - throw `ServiceException("请先生成源码预览后再进行代码解读")` if no analyzed files; - build prompt with fixed sections and `summary.getPromptContext()`; - include previous markdown when `mode = continue`; - parse AI markdown into `CodeAnalysisResponse`; - attach `sourceSnapshot` and warnings. - [ ] **Step 6: Run tests and verify GREEN** Run: `mvn -pl ruoyi-generator -Dtest=AiGenerationTaskServiceImplTest,AiGenerationTaskWorkerTest,AiGenerateServiceImplTest test` Expected: tests pass. - [ ] **Step 7: Commit** ```bash git add ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/IAiGenerateService.java \ ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerateServiceImpl.java \ ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerationTaskServiceImpl.java \ ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerationTaskWorker.java \ ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiGenerationTaskServiceImplTest.java \ ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiGenerationTaskWorkerTest.java \ ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiGenerateServiceImplTest.java git commit -m "feat: run code analysis through ai tasks" ``` --- ### Task 3: History and Controller Endpoints **Files:** - Create: `ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/CodeAnalysisHistoryResponse.java` - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/front/FrontProjectGenerationMapper.java` - Modify: `ruoyi-generator/src/main/resources/mapper/front/FrontProjectGenerationMapper.xml` - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/ProjectCodeAnalysisService.java` - Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/front/FrontProjectController.java` - Test: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/ProjectCodeAnalysisServiceTest.java` - [ ] **Step 1: Write failing history tests** Add tests: ```java @Test public void historyShouldOnlyReturnCodeAnalysisRecordsForOwnedProject() { List history = service.listHistory(1L, 100L); assertTrue(history.stream().allMatch(item -> "code_analysis".equals(item.getGenerateType()))); assertTrue(history.stream().allMatch(item -> Long.valueOf(100L).equals(item.getProjectId()))); } @Test public void getHistoryDetailShouldRejectOtherProjectRecord() { assertThrows(ServiceException.class, () -> service.getHistoryDetail(1L, 100L, 999L)); } ``` - [ ] **Step 2: Run tests and verify RED** Run: `mvn -pl ruoyi-generator -Dtest=ProjectCodeAnalysisServiceTest test` Expected: missing history DTO/service methods. - [ ] **Step 3: Add mapper lookup** Add mapper method: ```java FrontProjectGeneration selectGenerationForUser(@Param("userId") Long userId, @Param("projectId") Long projectId, @Param("generationId") Long generationId); ``` Add XML select: ```xml ``` - [ ] **Step 4: Implement history service methods** Add `listHistory(userId, projectId)`, `getHistoryDetail(userId, projectId, generationId)`, `createTaskRequest(...)`, and `createContinueTaskRequest(...)` to `ProjectCodeAnalysisService`. Filter list results in Java to `generateType = code_analysis` if reusing `selectGenerationsByProjectId`. - [ ] **Step 5: Add controller endpoints** In `FrontProjectController` add: ```java @GetMapping("/{projectId}/code-analysis/source-summary") public AjaxResult codeAnalysisSourceSummary(@PathVariable Long projectId) { Long userId = SecurityUtils.getUserId(); return success(projectCodeAnalysisService.buildSourceSummary(userId, projectId)); } ``` Add history/detail/task/continue endpoints. Task endpoints call `aiGenerationTaskService.createTask(userId, projectId, requestFromService)`. - [ ] **Step 6: Run tests and verify GREEN** Run: `mvn -pl ruoyi-generator -Dtest=ProjectCodeAnalysisServiceTest test` Expected: tests pass. - [ ] **Step 7: Commit** ```bash git add ruoyi-generator/src/main/java/com/ruoyi/generator/domain/front/dto/CodeAnalysisHistoryResponse.java \ ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/front/FrontProjectGenerationMapper.java \ ruoyi-generator/src/main/resources/mapper/front/FrontProjectGenerationMapper.xml \ ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/ProjectCodeAnalysisService.java \ ruoyi-admin/src/main/java/com/ruoyi/web/controller/front/FrontProjectController.java \ ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/ProjectCodeAnalysisServiceTest.java git commit -m "feat: expose project code analysis history" ``` --- ### Task 4: Frontend API, Routing, and Page Skeleton **Files:** - Modify: `easycode-web/src/api/project.js` - Modify: `easycode-web/src/router/index.js` - Create: `easycode-web/src/views/CodeAnalysisView.vue` - Create: `easycode-web/src/views/codeAnalysisView.test.mjs` - [ ] **Step 1: Write failing frontend source tests** Create `codeAnalysisView.test.mjs`: ```js test('code analysis route and page expose core controls', () => { const router = readSource('../router/index.js') const view = readSource('CodeAnalysisView.vue') const api = readSource('../api/project.js') assert.equal(router.includes("path: '/project/:projectId/code-analysis'"), true) assert.equal(router.includes("name: 'code-analysis'"), true) assert.equal(view.includes('章节导航'), true) assert.equal(view.includes('开始 AI 解读'), true) assert.equal(view.includes('继续生成'), true) assert.equal(view.includes('历史'), true) assert.equal(api.includes('getCodeAnalysisSourceSummary'), true) }) ``` - [ ] **Step 2: Run test and verify RED** Run: `node --test easycode-web/src/views/codeAnalysisView.test.mjs` Expected: file missing or assertions fail. - [ ] **Step 3: Add API wrappers** Add to `project.js`: ```js export function getCodeAnalysisSourceSummary(projectId) { ... } export function listCodeAnalysisHistory(projectId) { ... } export function getCodeAnalysisHistory(projectId, generationId) { ... } export function createCodeAnalysisTask(projectId, data) { ... } export function continueCodeAnalysisTask(projectId, data) { ... } ``` - [ ] **Step 4: Add route** Import `CodeAnalysisView` and add route with `requiresAuth: true`. - [ ] **Step 5: Add page skeleton** Create page with: - `projectId` from route; - `project`, `sourceSummary`, `history`, `activeTask`, `reportMarkdown`; - buttons for start, continue, refresh, history; - empty state when no report; - tabs for preview/edit; - history drawer placeholder. - [ ] **Step 6: Run frontend test and verify GREEN** Run: `node --test easycode-web/src/views/codeAnalysisView.test.mjs` Expected: tests pass. - [ ] **Step 7: Commit** ```bash git add easycode-web/src/api/project.js easycode-web/src/router/index.js \ easycode-web/src/views/CodeAnalysisView.vue easycode-web/src/views/codeAnalysisView.test.mjs git commit -m "feat: add code analysis page shell" ``` --- ### Task 5: Frontend Task Polling, History, Continue, and Export **Files:** - Modify: `easycode-web/src/views/CodeAnalysisView.vue` - Test: `easycode-web/src/views/codeAnalysisView.test.mjs` - [ ] **Step 1: Add failing tests for behavior markers** Extend source test: ```js assert.equal(view.includes('function waitForCodeAnalysisTask'), true) assert.equal(view.includes('continueCodeAnalysisTask'), true) assert.equal(view.includes('listCodeAnalysisHistory'), true) assert.equal(view.includes('downloadMarkdown'), true) assert.equal(view.includes('downloadWordDoc'), true) assert.equal(view.includes('renderMarkdown'), true) ``` - [ ] **Step 2: Run test and verify RED** Run: `node --test easycode-web/src/views/codeAnalysisView.test.mjs` Expected: missing function markers. - [ ] **Step 3: Implement task polling** Use existing `getAiTask(projectId, taskId)` with interval or async loop. On success parse `resultPayload` JSON and set report/history. On failed show error. - [ ] **Step 4: Implement history loading** Load history on mount, pick first successful item with parsed `response.markdown`, and allow drawer selection. - [ ] **Step 5: Implement continue generation** When continuing: - use current edited markdown if present; - fallback to latest successful history markdown; - call `continueCodeAnalysisTask(projectId, { previousGenerationId, previousMarkdown })`; - poll resulting task. - [ ] **Step 6: Implement exports** Reuse `saveBlob` and `renderMarkdown`. Markdown filename: `${projectName || 'code-analysis'}-代码解读报告.md`. Word compatible filename: `.doc`. - [ ] **Step 7: Run test and verify GREEN** Run: `node --test easycode-web/src/views/codeAnalysisView.test.mjs` Expected: tests pass. - [ ] **Step 8: Commit** ```bash git add easycode-web/src/views/CodeAnalysisView.vue easycode-web/src/views/codeAnalysisView.test.mjs git commit -m "feat: complete code analysis report workflow" ``` --- ### Task 6: Project Entry Points and Verification **Files:** - Modify: `easycode-web/src/views/ProjectListView.vue` - Modify: `easycode-web/src/views/projectListView.test.mjs` - Modify: `easycode-web/src/views/PreviewView.vue` - Modify: `easycode-web/src/views/previewView.test.mjs` - Modify: `easycode-web/src/views/GenerateView.vue` - Modify: `easycode-web/src/views/generateView.test.mjs` - [ ] **Step 1: Add failing entry tests** Project list test: ```js assert.equal(source.includes('el-tooltip content="代码解读"'), true) assert.equal(source.includes('aria-label="代码解读"'), true) assert.equal(source.includes('openCodeAnalysis'), true) ``` Preview test: ```js assert.equal(source.includes('代码解读'), true) assert.equal(source.includes('openCodeAnalysis'), true) assert.equal(source.includes('`/project/${projectId.value}/code-analysis`'), true) ``` Generate test: ```js assert.equal(source.includes('打开代码解读'), true) assert.equal(source.includes('/code-analysis'), true) ``` - [ ] **Step 2: Run tests and verify RED** Run: ```bash node --test easycode-web/src/views/projectListView.test.mjs node --test easycode-web/src/views/previewView.test.mjs node --test easycode-web/src/views/generateView.test.mjs ``` Expected: assertions fail. - [ ] **Step 3: Add entry buttons** Project list: import `Reading` or another Element Plus icon and add compact icon button that routes to `/project/${projectId}/code-analysis`. Preview: add toolbar button near download. Generate: add generated result action after preview/download where a project id is available. - [ ] **Step 4: Run tests and verify GREEN** Run the three node tests again. Expected: tests pass. - [ ] **Step 5: Run targeted backend tests** Run: ```bash mvn -pl ruoyi-generator -Dtest=ProjectCodeAnalysisServiceTest,AiGenerationTaskServiceImplTest,AiGenerationTaskWorkerTest,AiGenerateServiceImplTest test ``` Expected: tests pass. - [ ] **Step 6: Run frontend build check** Run: ```bash cd easycode-web npm run build ``` Expected: Vite build succeeds. - [ ] **Step 7: Commit** ```bash git add easycode-web/src/views/ProjectListView.vue easycode-web/src/views/projectListView.test.mjs \ easycode-web/src/views/PreviewView.vue easycode-web/src/views/previewView.test.mjs \ easycode-web/src/views/GenerateView.vue easycode-web/src/views/generateView.test.mjs git commit -m "feat: add project code analysis entry points" ``` --- ## Self-Review - Spec coverage: the plan covers no ZIP upload, project-bound source preview collection, AI task integration, history, continue generation, report UI, project entry points, and verification. - No placeholders: task steps include concrete files, method names, commands, and expected outputs. - Type consistency: `GenerateCodeAnalysisRequest`, `CodeAnalysisResponse`, `CodeAnalysisSourceSummary`, and `code_analysis` are introduced before later tasks reference them.