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: addgenerateCodeAnalysis.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: allowcode_analysis.ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiGenerationTaskWorker.java: executecode_analysistasks.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/andruoyi-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.getStructureforbackend,frontend,admin_frontend,sql; -
walk
children; -
include only configured code extensions;
-
skip
node_modules,target,dist,.git,.idea; -
create
PreviewFileRequestwithtemplateType,nodeId,tableId,category; -
read
contentfromfrontProjectPreviewService.getFileContent; -
trim content above
100 * 1024characters; -
build
promptContextfrom 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
sourceSnapshotand 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:
-
projectIdfrom 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, andcode_analysisare introduced before later tasks reference them.