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>
5.1 KiB
Implementation Plan: View Attendee List
Branch: 011-view-attendee-list | Date: 2026-03-08 | Spec: spec.md
Input: Feature specification from /specs/011-view-attendee-list/spec.md
Summary
Add an organizer-only attendee list to the event detail view. A new GET /events/{token}/attendees?organizerToken=<uuid> endpoint returns attendee names when the organizer token is valid (403 otherwise). The frontend conditionally renders the list below the attendee count when the viewer is identified as the organizer via localStorage.
Technical Context
Language/Version: Java 25 (backend), TypeScript 5.9 (frontend) Primary Dependencies: Spring Boot 3.5.x, Vue 3, Vue Router 5, openapi-fetch, openapi-typescript Storage: PostgreSQL (JPA via Spring Data, Liquibase migrations) Testing: JUnit + Testcontainers (backend integration), Vitest (frontend unit), Playwright + MSW (E2E) Target Platform: Self-hosted web application (PWA) Project Type: Web application (full-stack) Performance Goals: Attendee list loads within 2 seconds (SC-001) Constraints: Privacy by Design — attendee names only exposed to organizer; no PII logging Scale/Scope: Small-to-medium events; no pagination required (spec assumption)
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principle | Status | Notes |
|---|---|---|
| I. Privacy by Design | ✅ PASS | Attendee names only exposed via organizer token verification. Non-organizers see count only (FR-003). No analytics/tracking added. |
| II. Test-Driven Methodology | ✅ PASS | Plan follows Research → Spec → Test → Implement. TDD enforced. E2E tests mandatory for both user stories. |
| III. API-First Development | ✅ PASS | New endpoint defined in OpenAPI spec first. Types generated before implementation. Response schemas include example: fields. |
| IV. Simplicity & Quality | ✅ PASS | Minimal new code: one endpoint, one use case, one component section. No over-engineering. |
| V. Dependency Discipline | ✅ PASS | No new dependencies introduced. |
| VI. Accessibility | ✅ PASS | Semantic HTML list for attendees. WCAG AA contrast. Keyboard-navigable. |
Gate result: ALL PASS — proceed to Phase 0.
Project Structure
Documentation (this feature)
specs/011-view-attendee-list/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── contracts/ # Phase 1 output
│ └── api.md # New endpoint contract
└── tasks.md # Phase 2 output (/speckit.tasks)
Source Code (repository root)
backend/
├── src/main/java/de/fete/
│ ├── domain/
│ │ ├── model/ # Existing: Event, Rsvp, tokens
│ │ └── port/
│ │ ├── in/
│ │ │ └── GetAttendeesUseCase.java # NEW: inbound port
│ │ └── out/
│ │ └── RsvpRepository.java # MODIFY: add findByEventId
│ ├── application/service/
│ │ └── RsvpService.java # MODIFY: implement GetAttendeesUseCase
│ ├── adapter/
│ │ ├── in/web/
│ │ │ └── EventController.java # MODIFY: add attendees endpoint
│ │ └── out/persistence/
│ │ ├── RsvpJpaRepository.java # MODIFY: add findByEventId query
│ │ └── RsvpPersistenceAdapter.java # MODIFY: implement findByEventId
│ └── src/main/resources/openapi/
│ └── api.yaml # MODIFY: add attendees endpoint + schema
├── src/test/java/de/fete/
│ ├── adapter/in/web/
│ │ └── EventControllerIntegrationTest.java # MODIFY: add attendees tests
│ └── application/service/
│ └── RsvpServiceTest.java # MODIFY: add getAttendees tests
frontend/
├── src/
│ ├── views/
│ │ └── EventDetailView.vue # MODIFY: add attendee list section
│ ├── components/
│ │ └── AttendeeList.vue # NEW: attendee list component
│ ├── api/
│ │ └── schema.d.ts # REGENERATED from OpenAPI
│ └── composables/
│ └── useEventStorage.ts # NO CHANGES (read-only usage)
├── src/views/__tests__/
│ └── EventDetailView.spec.ts # MODIFY: add attendee list tests
├── src/components/__tests__/
│ └── AttendeeList.spec.ts # NEW: unit tests
└── e2e/
└── view-attendee-list.spec.ts # NEW: E2E tests
Structure Decision: Extends the existing web application structure. Backend follows hexagonal architecture with new inbound port + implementation. Frontend adds one new component integrated into the existing EventDetailView.
Complexity Tracking
No constitution violations — section not applicable.