# Quickstart: Cancel RSVP **Feature**: 014-cancel-rsvp | **Date**: 2026-03-09 ## Implementation Order 1. **OpenAPI spec** — Add DELETE endpoint to `api.yaml` 2. **Regenerate types** — Backend (Maven generate) + Frontend (`npm run generate:api`) 3. **Backend TDD** — Write tests → implement repository → service → controller 4. **Frontend composable** — Add `removeRsvp()` to `useEventStorage.ts` 5. **Frontend US-1** — RsvpBar tap-to-reveal + EventDetailView cancel logic 6. **Frontend US-2** — EventList conditional dialog + server-side cancel before removal 7. **Frontend US-3** — Edge case handling (stale tokens treated as success) 8. **E2E tests** — Playwright tests for all three user stories ## Key Commands ```bash # Backend cd backend && ./mvnw test # Run backend tests cd backend && ./mvnw verify # Full verify (checkstyle + tests) cd backend && ./mvnw spring-boot:run # Run backend locally # Frontend cd frontend && npm run generate:api # Regenerate types from OpenAPI cd frontend && npm run test:unit # Run unit tests cd frontend && npx playwright test # Run E2E tests cd frontend && npm run dev # Dev server # Both cd backend && ./mvnw test && cd ../frontend && npm run test:unit # Quick check ``` ## Key Files to Modify | File | Change | |------|--------| | `backend/src/main/resources/openapi/api.yaml` | Add DELETE `/events/{token}/rsvps/{rsvpToken}` | | `backend/.../port/in/CancelRsvpUseCase.java` | New use case interface | | `backend/.../port/out/RsvpRepository.java` | Add `deleteByEventIdAndRsvpToken()` | | `backend/.../RsvpJpaRepository.java` | Add derived delete query | | `backend/.../RsvpPersistenceAdapter.java` | Implement delete | | `backend/.../RsvpService.java` | Implement `CancelRsvpUseCase` | | `backend/.../EventController.java` | Add `cancelRsvp()` handler | | `frontend/src/composables/useEventStorage.ts` | Add `removeRsvp()` | | `frontend/src/components/RsvpBar.vue` | Tap-to-reveal cancel button | | `frontend/src/views/EventDetailView.vue` | Cancel logic + confirm dialog | | `frontend/src/components/EventList.vue` | Conditional dialog message + server cancel | | `frontend/e2e/cancel-rsvp.spec.ts` | E2E tests for all scenarios | ## Gotchas - The JPA `deleteBy...` method requires `@Transactional` on the calling service method. - The `@Transactional` import must be `jakarta.transaction.Transactional` (not Spring's). - After updating OpenAPI spec, run `npm run generate:api` in frontend AND Maven generate-sources in backend. - The RsvpBar component currently has no click handler on the status state — this needs to be added carefully with proper accessibility (role, aria-expanded, keyboard support). - The EventList's `confirmDelete` currently calls `removeEvent()` synchronously — it needs to become async for the server call.