# Tasks: RSVP to an Event **Input**: Design documents from `/specs/008-rsvp/` **Prerequisites**: plan.md, spec.md, data-model.md, contracts/create-rsvp.yaml, research.md, quickstart.md **Tests**: Included — constitution mandates Test-Driven Methodology (tests before implementation). **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 descriptions ## Phase 1: Setup **Purpose**: OpenAPI spec and database migration — shared infrastructure for all user stories - [x] T001 Update OpenAPI spec with RSVP endpoint, request/response schemas, and `attendeeCount` population in `backend/src/main/resources/openapi/api.yaml` - [x] T002 [P] Create Liquibase migration for rsvps table in `backend/src/main/resources/db/changelog/003-create-rsvps-table.xml` - [x] T003 [P] Include new migration in `backend/src/main/resources/db/changelog/db.changelog-master.xml` --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: Token value objects and cross-cutting refactoring — MUST complete before user stories **Why blocking**: All new RSVP code uses typed tokens. Existing code must be refactored first to avoid mixing raw UUID and typed tokens. - [x] T004 [P] Create `EventToken` record in `backend/src/main/java/de/fete/domain/model/EventToken.java` - [x] T005 [P] Create `OrganizerToken` record in `backend/src/main/java/de/fete/domain/model/OrganizerToken.java` - [x] T006 [P] Create `RsvpToken` record in `backend/src/main/java/de/fete/domain/model/RsvpToken.java` - [x] T007 Refactor `Event` domain model to use `EventToken`/`OrganizerToken` in `backend/src/main/java/de/fete/domain/model/Event.java` - [x] T008 Refactor `EventRepository` port to use typed tokens in `backend/src/main/java/de/fete/domain/port/out/EventRepository.java` - [x] T009 Refactor `EventPersistenceAdapter` to map typed tokens in `backend/src/main/java/de/fete/adapter/out/persistence/EventPersistenceAdapter.java` - [x] T010 Refactor `EventService` to use typed tokens in `backend/src/main/java/de/fete/application/service/EventService.java` - [x] T011 Refactor `EventController` to unwrap/wrap typed tokens at API boundary in `backend/src/main/java/de/fete/adapter/in/web/EventController.java` - [x] T012 Update `EventServiceTest` to use typed tokens in `backend/src/test/java/de/fete/application/service/EventServiceTest.java` - [x] T013 Update `EventControllerIntegrationTest` to use typed tokens in `backend/src/test/java/de/fete/adapter/in/web/EventControllerIntegrationTest.java` - [x] T014 Verify all existing tests pass after token refactoring (`cd backend && ./mvnw test`) **Checkpoint**: All existing tests green with typed tokens. New RSVP domain work can begin. --- ## Phase 3: User Story 1 — Submit an RSVP (Priority: P1) MVP **Goal**: A guest can open an active event page, tap the RSVP CTA, enter their name, submit, and see confirmation. Server persists the RSVP and returns an rsvpToken. localStorage stores RSVP data. Attendee count is populated from real data. **Independent Test**: Open an event page, submit an RSVP with a name, verify attendee count updates, verify localStorage contains rsvpToken and name. ### Backend Tests for US1 - [x] T015 [P] [US1] Write unit tests for `RsvpService` (create RSVP, validation, event-not-found) in `backend/src/test/java/de/fete/application/service/RsvpServiceTest.java` - [x] T016 [P] [US1] Write integration tests for `POST /events/{eventToken}/rsvps` (201 success, 400 validation, 404 not found) in `backend/src/test/java/de/fete/adapter/in/web/EventControllerIntegrationTest.java` ### Backend Implementation for US1 - [x] T017 [P] [US1] Create `Rsvp` domain entity in `backend/src/main/java/de/fete/domain/model/Rsvp.java` - [x] T018 [P] [US1] Create `CreateRsvpUseCase` inbound port in `backend/src/main/java/de/fete/domain/port/in/CreateRsvpUseCase.java` - [x] T019 [P] [US1] Create `RsvpRepository` outbound port with `save()` and `countByEventId()` in `backend/src/main/java/de/fete/domain/port/out/RsvpRepository.java` - [x] T020 [P] [US1] Create `RsvpJpaEntity` in `backend/src/main/java/de/fete/adapter/out/persistence/RsvpJpaEntity.java` - [x] T021 [P] [US1] Create `RsvpJpaRepository` (Spring Data) in `backend/src/main/java/de/fete/adapter/out/persistence/RsvpJpaRepository.java` - [x] T022 [US1] Implement `RsvpPersistenceAdapter` in `backend/src/main/java/de/fete/adapter/out/persistence/RsvpPersistenceAdapter.java` - [x] T023 [US1] Implement `RsvpService` (create RSVP logic, validate event exists) in `backend/src/main/java/de/fete/application/service/RsvpService.java` - [x] T024 [US1] Add `createRsvp()` method to `EventController` in `backend/src/main/java/de/fete/adapter/in/web/EventController.java` - [x] T025 [US1] Wire attendee count: add `countByEventId()` call to GET event flow, populate `attendeeCount` in response in `backend/src/main/java/de/fete/adapter/in/web/EventController.java` - [x] T026 [US1] Verify backend tests pass (`cd backend && ./mvnw test`) ### Frontend Tests for US1 - [ ] T027 [P] [US1] Write unit tests for `BottomSheet` component in `frontend/src/components/__tests__/BottomSheet.spec.ts` - [ ] T028 [P] [US1] Write unit tests for `RsvpBar` component in `frontend/src/components/__tests__/RsvpBar.spec.ts` - [ ] T029 [P] [US1] Update unit tests for `useEventStorage` composable (rsvpToken/rsvpName fields) in `frontend/src/composables/__tests__/useEventStorage.spec.ts` ### Frontend Implementation for US1 - [ ] T030 [US1] Regenerate TypeScript types from updated OpenAPI spec (`frontend/src/api/schema.d.ts`) - [ ] T031 [P] [US1] Extend `useEventStorage` composable with `rsvpToken` and `rsvpName` fields in `frontend/src/composables/useEventStorage.ts` - [ ] T032 [P] [US1] Create `BottomSheet.vue` component (slide-up, backdrop, focus trap, ESC close, aria-modal) in `frontend/src/components/BottomSheet.vue` - [ ] T033 [P] [US1] Create `RsvpBar.vue` sticky bottom bar (CTA state + status state) in `frontend/src/components/RsvpBar.vue` - [ ] T034 [US1] Integrate `RsvpBar` + `BottomSheet` + RSVP form into `EventDetailView`, including error state when server is unreachable, in `frontend/src/views/EventDetailView.vue` - [ ] T035 [US1] Add bottom sheet and sticky bar styles to `frontend/src/assets/main.css` - [ ] T036 [US1] Update `EventDetailView` unit tests for RSVP integration in `frontend/src/views/__tests__/EventDetailView.spec.ts` ### E2E Tests for US1 - [ ] T037 [US1] Write E2E tests: RSVP submission flow, localStorage verification, attendee count update in `frontend/e2e/event-rsvp.spec.ts` **Checkpoint**: US1 complete — guest can submit RSVP, see confirmation, attendee count populated. All backend + frontend tests green. --- ## Phase 4: User Story 2 — RSVP Blocked on Expired Events (Priority: P2) **Goal**: Expired events hide the RSVP form and the server rejects RSVP submissions with 409 Conflict. **Independent Test**: Attempt to RSVP to an expired event — verify form is hidden client-side and server returns 409. ### Tests for US2 - [ ] T038 [P] [US2] Write backend test for expired event rejection (409) in `backend/src/test/java/de/fete/application/service/RsvpServiceTest.java` - [ ] T039 [P] [US2] Write integration test for `POST /events/{eventToken}/rsvps` returning 409 on expired event in `backend/src/test/java/de/fete/adapter/in/web/EventControllerIntegrationTest.java` ### Implementation for US2 - [ ] T040 [US2] Add expiry check to `RsvpService.createRsvp()` — throw `EventExpiredException` when event date has passed in `backend/src/main/java/de/fete/application/service/RsvpService.java` - [ ] T041 [US2] Handle `EventExpiredException` in `GlobalExceptionHandler` — return 409 Conflict in `backend/src/main/java/de/fete/adapter/in/web/GlobalExceptionHandler.java` - [ ] T042 [US2] Hide RSVP bar/form on expired events in `EventDetailView` (check `expired` field from API response) in `frontend/src/views/EventDetailView.vue` - [ ] T043 [US2] Write E2E test for expired event: verify RSVP form hidden, direct API call returns 409 in `frontend/e2e/event-rsvp.spec.ts` - [ ] T044 [US2] Verify all tests pass (`cd backend && ./mvnw test && cd ../frontend && npm run test:unit`) **Checkpoint**: US2 complete — expired events block RSVPs client-side and server-side. --- ## Phase 5: Polish & Cross-Cutting Concerns **Purpose**: Final verification across all stories - [ ] T045 Run full backend verify (`cd backend && ./mvnw verify`) - [ ] T046 Run frontend build and type-check (`cd frontend && npm run build`) - [ ] T047 Run all E2E tests (`cd frontend && npx playwright test`) - [ ] T048 Visual verification of RSVP flow using `browser-interactive-testing` skill --- ## Dependencies & Execution Order ### Phase Dependencies - **Setup (Phase 1)**: No dependencies — can start immediately - **Foundational (Phase 2)**: Depends on T001 (OpenAPI spec) for schema awareness; T002-T003 (migration) independent - **US1 (Phase 3)**: Depends on Phase 2 completion (typed tokens in place) - **US2 (Phase 4)**: Depends on Phase 3 (RSVP creation must exist before expiry guard) - **Polish (Phase 5)**: Depends on all user stories complete ### User Story Dependencies - **US1 (P1)**: Can start after Phase 2 — no dependency on US2 - **US2 (P2)**: Depends on US1 (the RSVP endpoint and form must exist before adding the expiry guard) ### Within Each User Story - Tests MUST be written first and FAIL before implementation - Domain model/ports before persistence adapters - Persistence before services - Services before controllers - Backend before frontend (API must exist for frontend to consume) - Frontend components before view integration - Unit tests before E2E tests ### Parallel Opportunities **Phase 1**: T002 and T003 can run in parallel with T001 **Phase 2**: T004, T005, T006 in parallel; then T007-T013 sequentially (refactoring chain) **Phase 3 Backend**: T015+T016 (tests) in parallel; T017+T018+T019+T020+T021 (domain/ports/JPA) in parallel; then T022→T023→T024→T025 sequential **Phase 3 Frontend**: T027+T028+T029 (tests) in parallel; T031+T032+T033 in parallel; then T034→T035→T036→T037 sequential **Phase 4**: T038+T039 (tests) in parallel; then T040→T041→T042→T043→T044 sequential --- ## Implementation Strategy ### MVP First (User Story 1 Only) 1. Complete Phase 1: Setup (OpenAPI + migration) 2. Complete Phase 2: Foundational (token value objects + refactoring) 3. Complete Phase 3: User Story 1 (full RSVP flow) 4. **STOP and VALIDATE**: Guest can submit RSVP, see confirmation, attendee count works 5. Deploy/demo if ready ### Incremental Delivery 1. Setup + Foundational → Token refactoring complete, schema ready 2. Add US1 → Full RSVP flow works → Deploy/Demo (MVP!) 3. Add US2 → Expired events guarded → Deploy/Demo 4. Polish → All tests green, visual verification done --- ## Notes - Cancelled event guard (FR-010) is deferred until US-18 — NOT included in tasks - No CAPTCHA/rate-limiting per spec (KISS, privacy-first) - RSVP editing/withdrawal deferred to separate edit-RSVP spec - Frontend uses plain `string` for tokens (no branded types) per clarification - Backend uses typed records (`EventToken`, `OrganizerToken`, `RsvpToken`) per clarification