Fix Summary — Partner Coordination (Epic 8)

Fixed: 2026-03-09

Last updated: March 10, 2026 Reading time: 3 minutes File size: 3.85 KB

Changes made

  • M1 / N1: Updated Story 8.2 topic suggestion line — added “(minimum 5 characters)” to the title requirement, matching TopicControllerIntegrationTest#should_return400_when_titleTooShort (rejects titles < 5 chars).

  • N2: Added to Story 8.4 scope: “Title has a 500-character maximum length”, matching PartnerNoteControllerIntegrationTest#should_return400_when_titleExceeds500CharsOnUpdate.

  • N3: Corrected Story 8.4 scope from “title + free-text content” to “title (required) + content (required, free-text)”, matching PartnerNoteControllerIntegrationTest#should_return400_when_contentMissing.

  • N4: Added to Story 8.4 scope: “Note PATCH/DELETE validate that the noteId belongs to the companyName in the URL path; cross-partner access returns 404”, matching PartnerNoteControllerIntegrationTest#should_return404_when_updatingNoteFromDifferentPartner and #should_return404_when_deletingNoteFromDifferentPartner.

  • N5: Added security note to Story 8.2: for PARTNER users, companyName in request body is ignored and resolved from JWT; only ORGANIZER users may specify it explicitly — matching TopicControllerIntegrationTest#should_ignoreCompanyName_in_body_when_partnerSubmits.

  • N6: Added to Story 8.2: “Organizers may NOT cast votes (403 Forbidden); only PARTNER users may vote” — matching TopicControllerIntegrationTest#should_return403_when_organizerTriesToVote.

  • N7: Added to Story 8.2: “Organizers may suggest topics on behalf of a partner company by supplying companyName in the request body; omitting companyName as an organizer returns 400” — matching TopicControllerIntegrationTest#should_createTopic_when_organizerSubmits_onBehalfOfPartnerCompany and #should_return400_when_organizerSuggestsTopic_withoutCompanyName.

Skipped — needs manual decision

  • U1: “Data queried on demand; Caffeine-cached 15 minutes” / “EventManagementClient.getEventSummary(eventCode) (Caffeine cache 1h)” — no test validates cache TTL or that caching is active; stale-data bugs could appear only in production. Consider adding a cache-configuration test or noting the risk in a tech-debt item.

  • U2: “Dashboard P95 < 5s | Cached response < 50ms | Cold response < 500ms” (8.1); “Topic list P95 < 3s | Vote toggle < 500ms” (8.2); “Meeting list P95 < 3s | Invite 202 response < 200ms” (8.3) — PartnerPerformanceTest only covers base partner CRUD endpoints; no performance test covers analytics, topics, or meetings. Consider extending PartnerPerformanceTest or deferring to load-testing in staging.

  • U3: “Calendar invite: standard .ics file (RFC 5545) with two VEVENTs” — PartnerMeetingControllerIntegrationTest#should_return202_when_sendInviteCalled only asserts HTTP 202 and JSON response body; the ICS byte content (structure, two VEVENTs, RFC 5545 headers) is never inspected. High-risk gap — consider adding a unit test for IcsGeneratorService that parses the output and asserts VEVENT count, DTSTART, SUMMARY, and required RFC 5545 headers.

  • U4: “percentage” column in attendance table — test only asserts eventCode, totalAttendees, companyAttendees; percentage field and its formula are never asserted. Low risk.

  • U5: “Attendance table: sorted by date descending” — no test verifies row ordering in $.attendanceSummary. Low risk.

  • U6: “sent via AWS SES to all partner contacts on record” — PartnerMeetingControllerIntegrationTest#should_setInviteSentAt_when_sendInviteCalled mocks userServiceClient.getUsersByRole("PARTNER") but does not assert SES call recipients. Medium risk.

  • U7: “Agenda included in the calendar invite description” — tests confirm agenda is persisted via PATCH; no test checks that the ICS DESCRIPTION field contains agenda text. Low risk.