Files
fete/specs/011-view-attendee-list/research.md
nitrix 763811fce6
All checks were successful
CI / backend-test (push) Successful in 59s
CI / frontend-test (push) Successful in 23s
CI / frontend-e2e (push) Successful in 1m11s
CI / build-and-publish (push) Has been skipped
Add organizer-only attendee list to event detail view (011)
New GET /events/{token}/attendees endpoint returns attendee names when
a valid organizer token is provided (403 otherwise). The frontend
conditionally renders the list below the attendee count for organizers,
silently degrading for visitors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:34:27 +01:00

4.6 KiB

Research: View Attendee List (011)

Date: 2026-03-08 | Status: Complete

1. Organizer Token Verification Pattern

Decision: Query parameter ?organizerToken=<uuid> on the new endpoint.

Rationale: The project uses token-based access control without persistent sessions. The organizer token is stored in localStorage on the client. Passing it as a query parameter is the simplest approach that fits the existing architecture. The GET /events/{token} endpoint already uses path-based token lookup; adding a query parameter for the organizer token keeps the two concerns separate.

Alternatives considered:

  • Authorization header: More RESTful, but adds complexity without benefit — no auth framework in place, and query params are simpler for this single use case.
  • Embed attendees in existing GET /events/{token} response: Rejected per spec clarification — separate endpoint keeps concerns clean and avoids exposing attendee data in the public response.

2. Endpoint Design

Decision: GET /events/{token}/attendees?organizerToken=<uuid> returns { attendees: [{ name: string }] }.

Rationale:

  • Nested under /events/{token} — resource hierarchy is clear.
  • Returns an object with an attendees array (not a raw array) — allows future extension (e.g., adding metadata) without breaking the contract.
  • Each attendee object contains only name — minimal data exposure per Privacy by Design.
  • HTTP 403 for invalid/missing organizer token (not 401 — no authentication scheme exists).
  • HTTP 404 if the event token is invalid (consistent with existing GET /events/{token}).

Alternatives considered:

  • Return { attendees: [...], count: N }: Rejected — count is derivable from array length, and already available on the existing event detail endpoint. Avoids redundancy.
  • Include RSVP timestamp: Rejected — spec says chronological order but doesn't require displaying timestamps. Order is implicit in array position.

3. Backend Implementation Approach

Decision: New GetAttendeesUseCase inbound port, implemented by RsvpService. New findByEventId method on RsvpRepository outbound port.

Rationale: Follows the established hexagonal architecture pattern exactly. Each use case gets its own inbound port interface. The persistence layer already has RsvpJpaRepository with countByEventId; adding findAllByEventIdOrderByIdAsc is a natural extension (ID order = chronological insertion order).

Alternatives considered:

  • Add to GetEventUseCase: Rejected — violates single responsibility. The event detail endpoint is public; attendee retrieval is organizer-only.
  • Direct repository call in controller: Rejected — violates hexagonal architecture.

4. Frontend Integration Approach

Decision: New AttendeeList.vue component rendered conditionally in EventDetailView.vue when the viewer is the organizer. Fetches attendees via separate API call after event loads.

Rationale:

  • Separate component keeps EventDetailView manageable (it's already ~300 lines).
  • Separate API call (not bundled with event fetch) — the attendee list is organizer-only; non-organizers never trigger the request.
  • Component placed below attendee count, before RSVP form — matches spec FR-004.
  • Empty state handled within the component (FR-005).

Alternatives considered:

  • Inline in EventDetailView without separate component: Rejected — view is already complex. A dedicated component improves readability and testability.
  • Fetch attendees in the same call as event details: Not possible — separate endpoint by design.

5. Error Handling

Decision: Frontend silently degrades on 403 (does not render attendee list). No error toast or message shown.

Rationale: Per FR-007, the frontend "degrades gracefully by not rendering the list." If the organizer token is invalid (e.g., localStorage cleared on another device), the user sees the same view as a regular visitor. This is intentional — no confusing error states for edge cases that self-resolve.

Alternatives considered:

  • Show error message on 403: Rejected — would confuse users who aren't expecting organizer features.
  • Retry with different token: Not applicable — only one token per event in localStorage.

6. Accessibility Considerations

Decision: Attendee list rendered as semantic <ul> with <li> items. Section has a heading for screen readers. Count label uses singular/plural form.

Rationale: Constitution VI requires WCAG AA compliance, semantic HTML, and keyboard navigation. A list of names is naturally a <ul>. The heading provides structure for screen reader navigation.