Skip to content

bug: page /api/appointment/all and return AppointmentSummary DTOs (N+1 + unbounded list) - #363

Open
devin-ai-integration[bot] wants to merge 1 commit into
masterfrom
devin/1790835805-appointment-list-paging
Open

devin-ai-integration[bot] wants to merge 1 commit into
masterfrom
devin/1790835805-appointment-list-paging

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Summary

Fixes code-scan finding sfind-b69c72a5 (high). Before this change, GET /api/appointment/all returned appointmentDao.findAll(): every row, each with its EAGER User serialized. That User included the password hash and the lazy recipientList, which costs one extra SELECT per user while JSON is written (open-session-in-view).

The endpoint now runs one paged JPQL constructor projection plus a count query:

// AppointmentDao
@Query(value = "select new com.userFront.domain.AppointmentSummary(a.id, a.date, a.location, a.description, a.confirmed, u.username) "
        + "from Appointment a left join a.user u",
       countQuery = "select count(a) from Appointment a")
Page<AppointmentSummary> findAllSummaries(Pageable pageable);

// AppointmentResource  GET /api/appointment/all?page=0&size=50
page < 0 || size < 1 || size > 200  -> 400
body    = List<AppointmentSummary>   // still a JSON array, newest first (date desc, id desc)
headers = X-Total-Count, X-Page, X-Page-Size
  • The JSON shape matches what the AdminPortal table reads: {id, date, location, description, confirmed, user: {username}}. The response no longer includes the password, recipients, accounts or roles.
  • Appointment.user is now @ManyToOne(fetch = LAZY) + @JsonIgnore. No other code path reads it (AppointmentController only sets it).
  • AppointmentService.findAll() is replaced by findAllSummaries(Pageable). It had no other callers.
  • RequestFilter adds Access-Control-Expose-Headers: X-Total-Count, X-Page, X-Page-Size so the Angular app on :4200 can read the total.
  • AdminPortal appointment page: passes page/size (50) and adds a Newer/Older pager driven by X-Total-Count. Behavior change: without the pager, admins would see only the 50 newest appointments.
  • h2 is added at test scope for the new @DataJpaTest.

Measured with H2, 30 users, each with 1 appointment and 1 recipient:

SQL statements rows returned password hash in JSON
master: findAll() + Jackson 61 30 (all) yes
this PR: findAllSummaries(page 0, size 10) 2 (select ... limit + count) 10 no

Tests

  • AppointmentResourceTest (Mockito + standalone MockMvc): paging headers and DTO JSON shape (no user.password or user.recipientList), default page/size, newest-first sort, and 400 for size>200, size 0, page -1 and a non-numeric page.
  • AppointmentDaoTest (@DataJpaTest, Hibernate statistics): one page costs exactly 2 prepared statements, ordering is correct, and the serialized JSON has no hash or recipients.

How it was verified / limits: this repo has no CI. The Boot 1.5.4 parent can't be resolved offline (Maven Central is blocked in-session), so mvn test was not run. Instead, the touched classes and both tests were compiled (javac --release 8) and run with JUnitCore on a harness classpath: cached Boot 1.5.8 starters (web, data-jpa, test), H2 1.4.197 and spring-security-core. All 4 tests passed. The AdminPortal changes were not built or linted: there is no node_modules, and the npm registry is blocked.

Overlap

Older open PR #123 adds an AppointmentSummary DTO for the password-hash finding, but without paging or the query fix. #70, #26 and #336 touch the same resource for HTTP-method changes. Expect small merge conflicts in AppointmentResource; only one DTO approach should land.

Devin-Org: engineering

Link to Devin session: https://app.devin.ai/sessions/8f834a5573cc498dbb9b9bdf55b6b1ae
Open in Devin Desktop: https://app.devin.ai/desktop/session/8f834a5573cc498dbb9b9bdf55b6b1ae?variant=devin


Devin Review

Status Commit
⚪ Not started —

Run Devin Review

Devin Review (Staging)

@devin-ai-integration

Copy link
Copy Markdown
Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants