2026-04-27-report-preview-and-legacy-api-removal.md 16 KB

Report Preview and Legacy API Removal Implementation Plan

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.


Working Directory

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.


Task 1: Update Runtime Controller Tests for Removed Public Contract

Files:

  • Modify: ability-center-runtime/src/test/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportControllerWebMvcTest.java
  • Modify: ability-center-runtime/src/test/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportControllerTest.java

Step 1: Write the failing controller-level tests

In ExamSprintReportControllerWebMvcTest.java:

  1. Remove the import of ExamSprintReportApplicationService.ReportHtmlPreviewContent.
  2. 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")
    
  3. Update the achievement sync fixture the same way, keeping only the downloadUrl as the final argument.

  4. 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)
    
  5. Remove assertions that check $.data.previewHtmlUrl.

  6. 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);
    }
    
  7. Delete the previewHtmlReturnsTextHtmlForSucceededReport test.

  8. Remove any stubbing of applicationService.previewReportHtml(...).

In ExamSprintReportControllerTest.java:

  1. Remove jsonPath("$.data.previewHtmlUrl").isNotEmpty() assertions.
  2. Remove extraction of previewHtmlUri.
  3. Remove mockMvc.perform(get(previewHtmlUri)) calls and HTML-content assertions.
  4. Keep the PDF download assertions for both report types.

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.


Task 2: Update Application Service Tests for Removed previewHtmlUrl and Preview Service Method

Files:

  • Modify: abilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportApplicationServiceTest.java

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

  1. In createOutlookReportSyncGeneratesUploadAndReturnsDownloadUrl, delete the response.previewHtmlUrl() assertion.
  2. In createAchievementReportSyncGeneratesUploadAndReturnsDownloadUrl, delete the response.previewHtmlUrl() assertion.
  3. Rename getReportReturnsDownloadAndPreviewUrlsForSuccessfulReport to getReportReturnsDownloadUrlForSuccessfulReport.
  4. In that renamed test, delete the response.previewHtmlUrl() assertion.
  5. Delete previewReportHtmlRendersSavedPayloadForSuccessfulReport.
  6. Delete 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.


Task 3: Remove Preview Fields from Contract Records

Files:

  • Modify: abilities/exam-sprint/contracts/src/main/java/cn/yunzhixue/ability/center/examsprint/contracts/report/CreateExamSprintReportWithUrlResponse.java
  • Modify: abilities/exam-sprint/contracts/src/main/java/cn/yunzhixue/ability/center/examsprint/contracts/report/ExamSprintReportDetailResponse.java

Step 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.


Task 4: Remove Preview Method from Application Service and Implementation

Files:

  • Modify: abilities/exam-sprint/application/src/main/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportApplicationService.java
  • Modify: abilities/exam-sprint/application/src/main/java/cn/yunzhixue/ability/center/examsprint/application/report/DefaultExamSprintReportApplicationService.java
  • Modify as needed: abilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportApplicationServiceTest.java

Step 1: Remove preview from the service interface

In ExamSprintReportApplicationService.java:

  1. Delete ReportHtmlPreviewContent previewReportHtml(String reportId);.
  2. Delete the nested ReportHtmlPreviewContent record.
  3. Keep 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:

  1. Remove the import of ExamSprintReportRenderer if it is no longer needed.
  2. Remove the private final List<ExamSprintReportRenderer> renderers; field.
  3. Remove the List<ExamSprintReportRenderer> renderers constructor parameter.
  4. Remove this.renderers = List.copyOf(renderers);.
  5. In submitReportGenerationSync, remove previewHtmlUrl construction and return CreateExamSprintReportWithUrlResponse with downloadUrl as the final argument.
  6. In getReport, remove the previewHtmlUrl local variable, remove its assignment, and return ExamSprintReportDetailResponse with failureReason immediately after downloadUrl.
  7. Delete the entire previewReportHtml(String reportId) method.
  8. Keep 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.


Task 5: Remove Public Controller Endpoints and Update Runtime Tests

Files:

  • Modify: ability-center-runtime/src/main/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportController.java
  • Modify if needed: ability-center-runtime/src/test/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportControllerWebMvcTest.java
  • Modify if needed: ability-center-runtime/src/test/java/cn/yunzhixue/ability/center/examsprint/adapter/http/ExamSprintReportControllerTest.java

Step 1: Remove controller endpoint methods

In ExamSprintReportController.java:

  1. Remove imports:

    import cn.yunzhixue.ability.center.examsprint.application.report.ExamSprintReportApplicationService.ReportHtmlPreviewContent;
    import org.springframework.http.HttpStatus;
    
  2. Delete createReportDeprecated().

  3. Delete previewReportHtml(String reportId).

  4. Keep downloadReport(String reportId) unchanged.

Step 2: Fix runtime test compile errors

If compile errors remain in runtime tests:

  1. Remove imports that only supported deleted preview tests.
  2. Ensure CreateExamSprintReportWithUrlResponse and ExamSprintReportDetailResponse constructor calls use the new DTO shapes.
  3. Ensure no test references previewHtmlUrl.
  4. Keep the 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.


Task 6: Search for Remaining Preview API References

Files:

  • Inspect only unless references require cleanup.

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:

  • Remove public URL construction for /preview/html.
  • Remove preview endpoint stubs/assertions.
  • Do not remove HTML templates, renderer implementations, or PDF pipeline renderer usage.

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.


Task 7: Final Verification

Files:

  • No code edits expected.

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:

  • Removed preview endpoint and old generic endpoint from the controller.
  • Removed previewHtmlUrl from response records.
  • Removed preview service method and content record.
  • Runtime/application tests updated to assert the new contract.
  • Internal HTML renderers/templates and PDF generation pipeline remain intact.

Do not commit unless the user explicitly asks.