For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Remove the unused public HTML preview API and deprecated generic report creation endpoint while preserving typed report creation, status query, PDF generation, and PDF download.
Architecture: Treat this as an API contract cleanup: tests first lock the desired public contract, contracts/application/controller are then simplified to remove previewHtmlUrl and preview methods, and the PDF generation pipeline keeps using internal HTML renderers. The runtime controller should expose only typed creation, detail query, and PDF download endpoints.
Tech Stack: Java 17, Spring Boot MVC, Maven reactor, JUnit 5, AssertJ, MockMvc, Jackson records/DTOs.
Run all commands from this worktree unless a step says otherwise:
/Users/exiao/Codes/dcjxb.microservice/.worktrees/report-api-cleanup
Baseline already verified before writing this plan:
mvn -pl ability-center-runtime -am -Dtest=ExamSprintReportControllerWebMvcTest,ExamSprintReportControllerTest test
mvn -pl abilities/exam-sprint/application -am -Dtest=ExamSprintReportApplicationServiceTest test
Both commands passed on 2026-04-27.
Do not create a git commit unless the user explicitly asks for one.
Files:
ability-center-runtime/src/test/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportControllerWebMvcTest.javaability-center-runtime/src/test/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportControllerTest.javaStep 1: Write the failing controller-level tests
In ExamSprintReportControllerWebMvcTest.java:
ExamSprintReportApplicationService.ReportHtmlPreviewContent.Update new CreateExamSprintReportWithUrlResponse(...) calls so they pass only these fields:
new CreateExamSprintReportWithUrlResponse(
"report-sync-001",
ExamSprintReportType.OUTLOOK,
ExamSprintReportGenerationStatus.SUCCESS,
Instant.parse("2026-01-01T00:00:00Z"),
Instant.parse("2026-01-01T00:01:00Z"),
Instant.parse("2026-01-02T00:00:00Z"),
"https://dcjxb-cdntest.yunzhixue.cn/exam-assault-report/exam-sprint-outlook-report-report-sync-001.pdf")
Update the achievement sync fixture the same way, keeping only the downloadUrl as the final argument.
Update new ExamSprintReportDetailResponse(...) calls so they pass only these fields:
new ExamSprintReportDetailResponse(
"report-001",
ExamSprintReportType.OUTLOOK,
ExamSprintReportGenerationStatus.SUCCESS,
Instant.parse("2026-01-01T00:00:00Z"),
Instant.parse("2026-01-01T00:05:00Z"),
Instant.parse("2026-01-02T00:00:00Z"),
"https://dcjxb-cdntest.yunzhixue.cn/exam-assault-report/exam-sprint-outlook-report-report-001.pdf",
null)
Remove assertions that check $.data.previewHtmlUrl.
Replace the old oldGenericCreateReportEndpointIsRemoved test with a test that proves removed endpoints are no longer exposed:
@Test
void removedReportEndpointsAreNotExposed() throws Exception {
mockMvc.perform(post("/api/exam-sprint/reports")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"reportType\":\"OUTLOOK\",\"payload\":{}}"))
.andExpect(status().isNotFound());
mockMvc.perform(get("/api/exam-sprint/reports/{reportId}/preview/html", "report-001"))
.andExpect(status().isNotFound());
verifyNoInteractions(applicationService);
}
Delete the previewHtmlReturnsTextHtmlForSucceededReport test.
Remove any stubbing of applicationService.previewReportHtml(...).
In ExamSprintReportControllerTest.java:
jsonPath("$.data.previewHtmlUrl").isNotEmpty() assertions.previewHtmlUri.mockMvc.perform(get(previewHtmlUri)) calls and HTML-content assertions.Step 2: Run controller tests to verify they fail before implementation
Run:
mvn -pl ability-center-runtime -am -Dtest=ExamSprintReportControllerWebMvcTest,ExamSprintReportControllerTest test
Expected: FAIL. Accept either compile failures from the still-old DTO constructor shapes, or test failures because the preview endpoint still exists / previewHtmlUrl still appears.
Step 3: Checkpoint status
Run:
git status --short
Expected: only the two runtime test files and this plan file should be modified so far.
Do not commit.
previewHtmlUrl and Preview Service MethodFiles:
abilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportApplicationServiceTest.javaStep 1: Write failing application-contract tests
Add imports near the other java.* imports:
import cn.yunzhixue.ability.center.examsprint.contracts.report.CreateExamSprintReportWithUrlResponse;
import cn.yunzhixue.ability.center.examsprint.contracts.report.ExamSprintReportDetailResponse;
import java.lang.reflect.Method;
import java.lang.reflect.RecordComponent;
import java.util.Arrays;
Add this test near the top of ExamSprintReportApplicationServiceTest:
@Test
void publicReportContractsDoNotExposeHtmlPreview() {
assertThat(recordComponentNames(CreateExamSprintReportWithUrlResponse.class))
.contains("downloadUrl")
.doesNotContain("previewHtmlUrl");
assertThat(recordComponentNames(ExamSprintReportDetailResponse.class))
.contains("downloadUrl")
.doesNotContain("previewHtmlUrl");
assertThat(Arrays.stream(ExamSprintReportApplicationService.class.getDeclaredMethods())
.map(Method::getName))
.doesNotContain("previewReportHtml");
}
Add this helper near the other private helpers:
private List<String> recordComponentNames(Class<? extends Record> recordType) {
return Arrays.stream(recordType.getRecordComponents())
.map(RecordComponent::getName)
.toList();
}
Update existing application service tests:
createOutlookReportSyncGeneratesUploadAndReturnsDownloadUrl, delete the response.previewHtmlUrl() assertion.createAchievementReportSyncGeneratesUploadAndReturnsDownloadUrl, delete the response.previewHtmlUrl() assertion.getReportReturnsDownloadAndPreviewUrlsForSuccessfulReport to getReportReturnsDownloadUrlForSuccessfulReport.response.previewHtmlUrl() assertion.previewReportHtmlRendersSavedPayloadForSuccessfulReport.previewReportHtmlRejectsPendingReport.Step 2: Run application tests to verify they fail before implementation
Run:
mvn -pl abilities/exam-sprint/application -am -Dtest=ExamSprintReportApplicationServiceTest test
Expected: FAIL because previewHtmlUrl is still a record component and previewReportHtml is still on the application service interface.
Step 3: Checkpoint status
Run:
git status --short
Expected: runtime tests, application test, and this plan file are modified.
Do not commit.
Files:
abilities/exam-sprint/contracts/src/main/java/cn/yunzhixue/ability/center/examsprint/contracts/report/CreateExamSprintReportWithUrlResponse.javaabilities/exam-sprint/contracts/src/main/java/cn/yunzhixue/ability/center/examsprint/contracts/report/ExamSprintReportDetailResponse.javaStep 1: Implement the contract change
Change CreateExamSprintReportWithUrlResponse to:
public record CreateExamSprintReportWithUrlResponse(
String reportId,
ExamSprintReportType reportType,
ExamSprintReportGenerationStatus generationStatus,
Instant createdAt,
Instant updatedAt,
Instant expiresAt,
String downloadUrl) {
}
Change ExamSprintReportDetailResponse to:
public record ExamSprintReportDetailResponse(
String reportId,
ExamSprintReportType reportType,
ExamSprintReportGenerationStatus generationStatus,
Instant createdAt,
Instant updatedAt,
Instant expiresAt,
String downloadUrl,
String failureReason) {
}
Step 2: Run targeted compile/tests to expose remaining call sites
Run:
mvn -pl abilities/exam-sprint/application,ability-center-runtime -am -DskipTests compile test-compile
Expected: FAIL with constructor or method references that still include previewHtmlUrl or preview service methods.
Step 3: Checkpoint status
Run:
git status --short
Do not commit.
Files:
abilities/exam-sprint/application/src/main/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportApplicationService.javaabilities/exam-sprint/application/src/main/java/cn/yunzhixue/ability/center/examsprint/application/report/DefaultExamSprintReportApplicationService.javaabilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportApplicationServiceTest.javaStep 1: Remove preview from the service interface
In ExamSprintReportApplicationService.java:
ReportHtmlPreviewContent previewReportHtml(String reportId);.ReportHtmlPreviewContent record.ReportDownloadContent.Final shape should be:
public interface ExamSprintReportApplicationService {
CreateExamSprintReportResponse createOutlookReport(JsonNode payload);
CreateExamSprintReportResponse createAchievementReport(JsonNode payload);
CreateExamSprintReportWithUrlResponse createOutlookReportSync(JsonNode payload);
CreateExamSprintReportWithUrlResponse createAchievementReportSync(JsonNode payload);
ExamSprintReportDetailResponse getReport(String reportId);
ReportDownloadContent downloadReport(String reportId);
record ReportDownloadContent(String fileName, byte[] bytes, String contentType) {
}
}
Step 2: Remove preview implementation
In DefaultExamSprintReportApplicationService.java:
ExamSprintReportRenderer if it is no longer needed.private final List<ExamSprintReportRenderer> renderers; field.List<ExamSprintReportRenderer> renderers constructor parameter.this.renderers = List.copyOf(renderers);.submitReportGenerationSync, remove previewHtmlUrl construction and return CreateExamSprintReportWithUrlResponse with downloadUrl as the final argument.getReport, remove the previewHtmlUrl local variable, remove its assignment, and return ExamSprintReportDetailResponse with failureReason immediately after downloadUrl.previewReportHtml(String reportId) method.List import if still used for another type; otherwise remove it.Step 3: Update test service factory constructor call
In ExamSprintReportApplicationServiceTest.java, update new DefaultExamSprintReportApplicationService(...) to remove the final List.of(new PreviewTestRenderer()) argument. Keep PreviewTestRenderer if it is still used by ExamSprintReportGenerationPipeline in the test helper.
Expected constructor call shape:
return new DefaultExamSprintReportApplicationService(
repository,
dispatcher,
new ExamSprintReportGenerationPipeline(
repository,
renderers,
pdfGenerator,
storage,
FIXED_CLOCK),
storage,
properties(),
FIXED_CLOCK,
OBJECT_MAPPER,
VALIDATOR);
Step 4: Run application tests
Run:
mvn -pl abilities/exam-sprint/application -am -Dtest=ExamSprintReportApplicationServiceTest test
Expected: PASS.
Step 5: Checkpoint status
Run:
git status --short
Do not commit.
Files:
ability-center-runtime/src/main/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportController.javaability-center-runtime/src/test/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportControllerWebMvcTest.javaability-center-runtime/src/test/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportControllerTest.javaStep 1: Remove controller endpoint methods
In ExamSprintReportController.java:
Remove imports:
import cn.yunzhixue.ability.center.examsprint.application.report.ExamSprintReportApplicationService.ReportHtmlPreviewContent;
import org.springframework.http.HttpStatus;
Delete createReportDeprecated().
Delete previewReportHtml(String reportId).
Keep downloadReport(String reportId) unchanged.
Step 2: Fix runtime test compile errors
If compile errors remain in runtime tests:
CreateExamSprintReportWithUrlResponse and ExamSprintReportDetailResponse constructor calls use the new DTO shapes.previewHtmlUrl.removedReportEndpointsAreNotExposed test from Task 1.Step 3: Run runtime tests
Run:
mvn -pl ability-center-runtime -am -Dtest=ExamSprintReportControllerWebMvcTest,ExamSprintReportControllerTest test
Expected: PASS.
Step 4: Checkpoint status
Run:
git status --short
Do not commit.
Files:
Step 1: Search source and test code for removed public contract names
Run:
rg "previewHtmlUrl|previewReportHtml|/preview/html|createReportDeprecated" ability-center-runtime abilities/exam-sprint
Expected: no matches in src/main/java or active tests. It is acceptable for this implementation plan or historical docs to mention the removed names.
Step 2: If matches remain in production or active test code, remove them
Rules:
/preview/html.Step 3: Run compile for affected modules
Run:
mvn -pl abilities/exam-sprint/application,ability-center-runtime -am -DskipTests compile test-compile
Expected: PASS.
Do not commit.
Files:
Step 1: Run targeted application tests
Run:
mvn -pl abilities/exam-sprint/application -am -Dtest=ExamSprintReportApplicationServiceTest test
Expected: PASS.
Step 2: Run targeted runtime tests
Run:
mvn -pl ability-center-runtime -am -Dtest=ExamSprintReportControllerWebMvcTest,ExamSprintReportControllerTest test
Expected: PASS.
Step 3: Run broader affected-module verification
Run:
mvn -pl abilities/exam-sprint/application,ability-center-runtime -am test
Expected: PASS.
Step 4: Inspect final diff
Run:
git status --short
git diff -- ability-center-runtime abilities/exam-sprint docs/plans/2026-04-27-report-preview-and-legacy-api-removal.md
Expected:
previewHtmlUrl from response records.Do not commit unless the user explicitly asks.