# Tasks: View Attendee List

**Input**: Design documents from `/specs/011-view-attendee-list/`
**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/api.md

**Tests**: Included — TDD enforced per constitution principle II. E2E tests mandatory per plan.

**Organization**: Tasks grouped by user story for independent implementation and testing.

## Format: `[ID] [P?] [Story] Description`

- **[P]**: Can run in parallel (different files, no dependencies)
- **[Story]**: Which user story this task belongs to (e.g., US1, US2)
- Exact file paths included in all descriptions

---

## Phase 1: Setup (API Contract)

**Purpose**: Define the API contract in OpenAPI and generate types for both backend and frontend.

- [x] T001 Add `GET /events/{token}/attendees` endpoint, `GetAttendeesResponse`, and `Attendee` schemas to `backend/src/main/resources/openapi/api.yaml` per `contracts/api.md`
- [x] T002 Regenerate backend Spring interfaces (`cd backend && ./mvnw compile`)
- [x] T003 Regenerate frontend TypeScript types (`cd frontend && npm run generate:api`)

**Checkpoint**: OpenAPI spec updated, generated types available in both backend and frontend.

---

## Phase 2: Foundational (Backend Domain Ports)

**Purpose**: Create the inbound port and extend the outbound port that all backend implementation depends on.

- [x] T004 [P] Create `GetAttendeesUseCase` inbound port interface in `backend/src/main/java/de/fete/domain/port/in/GetAttendeesUseCase.java` with method `List<String> getAttendeeNames(UUID eventToken, UUID organizerToken)`
- [x] T005 [P] Add `List<Rsvp> findByEventId(Long eventId)` method to `backend/src/main/java/de/fete/domain/port/out/RsvpRepository.java`

**Checkpoint**: Domain ports defined — service and adapter implementation can begin.

---

## Phase 3: User Story 1 — View Attendee List as Organizer (Priority: P1) 🎯 MVP

**Goal**: Organizer sees a list of attendee names on the event detail page. Non-organizers see only the count (existing behavior).

**Independent Test**: Create an event, submit RSVPs, then view the detail page with the organizer token. Attendee names should be listed.

### Tests for User Story 1 ⚠️

> **Write these tests FIRST — ensure they FAIL before implementation.**

- [x] T006 [P] [US1] Write unit tests for `RsvpService.getAttendeeNames` (valid token, invalid token, event not found, no RSVPs) in `backend/src/test/java/de/fete/application/service/RsvpServiceTest.java`
- [x] T007 [P] [US1] Write integration tests for `GET /events/{token}/attendees` (200 with attendees, 200 empty, 403 invalid token, 404 event not found) in `backend/src/test/java/de/fete/adapter/in/web/EventControllerIntegrationTest.java`
- [x] T008 [P] [US1] Write unit tests for `AttendeeList.vue` (renders attendee names, empty state message, loading state) in `frontend/src/components/__tests__/AttendeeList.spec.ts`
- [x] T009 [P] [US1] Write unit tests for organizer-conditional rendering in `EventDetailView.vue` (shows list for organizer, hides for visitor) in `frontend/src/views/__tests__/EventDetailView.spec.ts`
- [x] T010 [P] [US1] Write E2E test: organizer sees attendee names, visitor sees count only, in `frontend/e2e/view-attendee-list.spec.ts`

### Backend Implementation for User Story 1

- [x] T011 [P] [US1] Add `findAllByEventIdOrderByIdAsc` query method to `backend/src/main/java/de/fete/adapter/out/persistence/RsvpJpaRepository.java`
- [x] T012 [P] [US1] Implement `findByEventId` in `backend/src/main/java/de/fete/adapter/out/persistence/RsvpPersistenceAdapter.java`
- [x] T013 [US1] Implement `GetAttendeesUseCase` in `backend/src/main/java/de/fete/application/service/RsvpService.java` — look up event by token, verify organizer token, return attendee names ordered by ID
- [x] T014 [US1] Add `getAttendees` endpoint handler to `backend/src/main/java/de/fete/adapter/in/web/EventController.java` — map to `GetAttendeesUseCase`, return 200/403/404

### Frontend Implementation for User Story 1

- [x] T015 [US1] Create `AttendeeList.vue` component in `frontend/src/components/AttendeeList.vue` — accepts attendee names array as prop, renders semantic `<ul>/<li>` list, shows empty state message when no attendees
- [x] T016 [US1] Integrate `AttendeeList.vue` into `frontend/src/views/EventDetailView.vue` — fetch `GET /events/{token}/attendees` with organizer token from localStorage, render below attendee count (before RSVP form), silently degrade on 403

**Checkpoint**: User Story 1 fully functional. Organizer sees attendee names; visitor sees count only. All tests pass.

---

## Phase 4: User Story 2 — Attendee Count Label (Priority: P2)

**Goal**: The attendee list section shows a count label ("5 Attendees" / "1 Attendee") alongside the names.

**Independent Test**: Verify the count label above the list matches the number of entries, and uses singular/plural correctly.

### Tests for User Story 2 ⚠️

> **Write these tests FIRST — ensure they FAIL before implementation.**

- [x] T017 [P] [US2] Write unit tests for count label in `AttendeeList.vue` (plural "5 Attendees", singular "1 Attendee", zero "0 Attendees") in `frontend/src/components/__tests__/AttendeeList.spec.ts`

### Implementation for User Story 2

- [x] T018 [US2] Add count heading to `AttendeeList.vue` in `frontend/src/components/AttendeeList.vue` — render `<h3>` with singular/plural label based on attendee array length

**Checkpoint**: User Story 2 complete. Count label renders correctly with singular/plural form. All tests pass.

---

## Phase 5: Polish & Cross-Cutting Concerns

**Purpose**: Verification across both stories, accessibility, edge cases.

- [x] T019 Run full backend verification (`cd backend && ./mvnw verify`) — checkstyle, all tests green
- [x] T020 Run full frontend build and tests (`cd frontend && npm run build && npm run test:unit`)
- [x] T021 Run E2E tests (`cd frontend && npx playwright test e2e/view-attendee-list.spec.ts`)
- [x] T022 Verify WCAG AA contrast and semantic HTML (attendee list uses `<ul>/<li>`, section has heading for screen readers)
- [x] T023 Verify edge cases: long names truncated visually, special characters escaped, large attendee list scrollable

---

## Dependencies & Execution Order

### Phase Dependencies

- **Setup (Phase 1)**: No dependencies — start immediately
- **Foundational (Phase 2)**: Depends on T002 (generated backend interfaces)
- **User Story 1 (Phase 3)**: Depends on Phase 2 completion
- **User Story 2 (Phase 4)**: Depends on T015 (AttendeeList component exists)
- **Polish (Phase 5)**: Depends on Phase 3 + Phase 4 completion

### User Story Dependencies

- **User Story 1 (P1)**: Can start after Phase 2 — no dependencies on other stories
- **User Story 2 (P2)**: Depends on US1's `AttendeeList.vue` component (T015) existing

### Within Each User Story

- Tests MUST be written and FAIL before implementation
- Ports/models before services
- Services before endpoints/controllers
- Backend before frontend (API must exist for frontend integration)

### Parallel Opportunities

- T004 + T005 can run in parallel (different files)
- T006 + T007 + T008 + T009 + T010 can all run in parallel (different test files)
- T011 + T012 can run in parallel (different persistence files)

---

## Parallel Example: User Story 1

```bash
# Launch all tests in parallel (TDD — write first):
Task: T006 "Unit tests for RsvpService.getAttendeeNames"
Task: T007 "Integration tests for GET /events/{token}/attendees"
Task: T008 "Unit tests for AttendeeList.vue"
Task: T009 "Unit tests for EventDetailView.vue organizer rendering"
Task: T010 "E2E test for attendee list"

# Launch persistence layer in parallel:
Task: T011 "Add findAllByEventIdOrderByIdAsc to RsvpJpaRepository"
Task: T012 "Implement findByEventId in RsvpPersistenceAdapter"
```

---

## Implementation Strategy

### MVP First (User Story 1 Only)

1. Complete Phase 1: Setup (OpenAPI + type generation)
2. Complete Phase 2: Foundational (domain ports)
3. Complete Phase 3: User Story 1 (backend + frontend)
4. **STOP and VALIDATE**: Test independently — organizer sees names, visitor sees count only
5. Deploy/demo if ready

### Incremental Delivery

1. Setup + Foundational → API contract and ports ready
2. Add User Story 1 → Test independently → Deploy (MVP!)
3. Add User Story 2 → Test independently → Deploy (count label enhancement)
4. Polish phase → Full verification, accessibility, edge cases
