From 8b0be5c10377f9e629097e25f876443afb897643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= Date: Tue, 7 Jul 2026 16:12:42 +0800 Subject: [PATCH] docs: add project code analysis plan --- .../plans/2026-07-07-project-code-analysis.md | 581 ++++++++++++++++++ 1 file changed, 581 insertions(+) create mode 100644 RuoYi-Vue/docs/superpowers/plans/2026-07-07-project-code-analysis.md diff --git a/RuoYi-Vue/docs/superpowers/plans/2026-07-07-project-code-analysis.md b/RuoYi-Vue/docs/superpowers/plans/2026-07-07-project-code-analysis.md new file mode 100644 index 0000000..4fed975 --- /dev/null +++ b/RuoYi-Vue/docs/superpowers/plans/2026-07-07-project-code-analysis.md @@ -0,0 +1,581 @@ +# 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.