Files
yidaima/RuoYi-Vue/docs/superpowers/plans/2026-07-07-project-code-analysis.md
2026-07-07 16:12:42 +08:00

23 KiB

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:

@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:

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
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:

@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:

@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:

CodeAnalysisResponse generateCodeAnalysis(Long userId, Long projectId, GenerateCodeAnalysisRequest request);

Allow code_analysis in AiGenerationTaskServiceImpl.validateRequest().

In AiGenerationTaskWorker.execute() add:

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:

@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
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:

@Test
public void historyShouldOnlyReturnCodeAnalysisRecordsForOwnedProject() {
    List<CodeAnalysisHistoryResponse> 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:

FrontProjectGeneration selectGenerationForUser(@Param("userId") Long userId,
        @Param("projectId") Long projectId, @Param("generationId") Long generationId);

Add XML select:

<select id="selectGenerationForUser" resultMap="FrontProjectGenerationResult">
    <include refid="selectFrontProjectGenerationVo"/>
    where user_id = #{userId}
      and project_id = #{projectId}
      and generation_id = #{generationId}
</select>
  • 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:

@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
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:

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:

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
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:

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
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:

assert.equal(source.includes('el-tooltip content="代码解读"'), true)
assert.equal(source.includes('aria-label="代码解读"'), true)
assert.equal(source.includes('openCodeAnalysis'), true)

Preview test:

assert.equal(source.includes('代码解读'), true)
assert.equal(source.includes('openCodeAnalysis'), true)
assert.equal(source.includes('`/project/${projectId.value}/code-analysis`'), true)

Generate test:

assert.equal(source.includes('打开代码解读'), true)
assert.equal(source.includes('/code-analysis'), true)
  • Step 2: Run tests and verify RED

Run:

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:

mvn -pl ruoyi-generator -Dtest=ProjectCodeAnalysisServiceTest,AiGenerationTaskServiceImplTest,AiGenerationTaskWorkerTest,AiGenerateServiceImplTest test

Expected: tests pass.

  • Step 6: Run frontend build check

Run:

cd easycode-web
npm run build

Expected: Vite build succeeds.

  • Step 7: Commit
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.