Files
fete/specs/014-cancel-rsvp/plan.md
nitrix 41bb17d5c9
All checks were successful
CI / backend-test (push) Successful in 59s
CI / frontend-test (push) Successful in 24s
CI / frontend-e2e (push) Successful in 1m18s
CI / build-and-publish (push) Has been skipped
Add cancel RSVP feature (backend DELETE endpoint + frontend UI)
Allows guests to cancel their RSVP via a DELETE endpoint using their
guestToken. Frontend shows cancel button in RsvpBar and clears local
storage on success. Includes unit tests, integration tests, and E2E spec.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:45:37 +01:00

91 lines
4.7 KiB
Markdown

# Implementation Plan: Cancel RSVP
**Branch**: `014-cancel-rsvp` | **Date**: 2026-03-09 | **Spec**: [spec.md](spec.md)
**Input**: Feature specification from `/specs/014-cancel-rsvp/spec.md`
## Summary
Allow guests to cancel their RSVP either explicitly from the event detail view (tap-to-reveal pattern on the RSVP bar) or implicitly when removing an RSVP'd event from their event list. The backend provides an idempotent DELETE endpoint; the frontend handles confirmation, API call, localStorage cleanup, and UI state reset.
## 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 + Mockito (backend unit), MockMvc + Testcontainers (backend integration), Vitest (frontend unit), Playwright + MSW (frontend E2E)
**Target Platform**: Self-hosted PWA (web browser, mobile-first)
**Project Type**: Web application (hexagonal backend + SPA frontend)
**Performance Goals**: Cancel operation < 500ms server-side
**Constraints**: Privacy by design (no analytics), token-based auth (no login), idempotent delete
**Scale/Scope**: Single new endpoint, 3 modified frontend components, 1 new composable method
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
| Principle | Status | Notes |
|-----------|--------|-------|
| I. Privacy by Design | PASS | No new PII stored. Delete operation removes data. No analytics. |
| II. Test-Driven Methodology | PASS | Plan includes TDD cycle: tests before implementation. E2E mandatory. |
| III. API-First Development | PASS | OpenAPI spec updated first, types generated before implementation. |
| IV. Simplicity & Quality | PASS | Minimal changes to existing code. No new abstractions. Idempotent delete is the simplest correct approach. |
| V. Dependency Discipline | PASS | No new dependencies required. |
| VI. Accessibility | PASS | Interactive elements will use semantic HTML, ARIA, keyboard navigation. Confirm dialog already accessible. |
**Gate result**: ALL PASS — proceed to Phase 0.
## Project Structure
### Documentation (this feature)
```text
specs/014-cancel-rsvp/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── contracts/ # Phase 1 output
│ └── cancel-rsvp.yaml # DELETE endpoint contract
└── tasks.md # Phase 2 output (by /speckit.tasks)
```
### Source Code (repository root)
```text
backend/
├── src/main/java/de/fete/
│ ├── domain/
│ │ ├── model/Rsvp.java # existing (no changes)
│ │ ├── model/RsvpToken.java # existing (no changes)
│ │ └── port/
│ │ ├── in/CancelRsvpUseCase.java # NEW use case port
│ │ └── out/RsvpRepository.java # MODIFY (add deleteByRsvpToken)
│ ├── application/service/RsvpService.java # MODIFY (implement cancel)
│ └── adapter/
│ ├── in/web/EventController.java # MODIFY (add DELETE handler)
│ └── out/persistence/
│ ├── RsvpJpaRepository.java # MODIFY (add deleteByRsvpToken)
│ └── RsvpPersistenceAdapter.java # MODIFY (implement delete)
├── src/main/resources/openapi/api.yaml # MODIFY (add DELETE endpoint)
└── src/test/java/de/fete/
├── application/service/RsvpServiceTest.java # MODIFY (add cancel tests)
└── adapter/in/web/EventControllerIntegrationTest.java # MODIFY (add cancel tests)
frontend/
├── src/
│ ├── api/schema.d.ts # REGENERATE (from updated OpenAPI)
│ ├── components/
│ │ ├── RsvpBar.vue # MODIFY (tap-to-reveal cancel)
│ │ ├── EventList.vue # MODIFY (conditional dialog msg)
│ │ └── ConfirmDialog.vue # existing (no changes)
│ ├── composables/useEventStorage.ts # MODIFY (add removeRsvp)
│ └── views/EventDetailView.vue # MODIFY (add cancel logic)
└── e2e/
└── cancel-rsvp.spec.ts # NEW (E2E tests)
```
**Structure Decision**: Follows existing hexagonal architecture. New use case port + implementation in existing service. Single new endpoint added to existing controller.
## Complexity Tracking
No constitution violations — table not needed.