# Data Model: Cancel RSVP

**Feature**: 014-cancel-rsvp | **Date**: 2026-03-09

## Entities

### RSVP (existing — no schema changes)

| Field | Type | Constraints | Notes |
|-------|------|-------------|-------|
| id | BIGSERIAL | PK, auto-generated | Internal DB ID, never exposed |
| rsvp_token | UUID | UNIQUE, NOT NULL | Bearer credential for the guest |
| event_id | BIGINT | FK → events.id, NOT NULL | Links RSVP to event |
| name | VARCHAR(100) | NOT NULL | Guest display name |

**No migration needed.** The cancel feature only deletes existing rows — no new columns or tables.

## State Transitions

```
┌──────────┐    POST /events/{token}/rsvps    ┌──────────┐
│ No RSVP  │ ──────────────────────────────► │ Attending │
│ (guest)  │ ◄────────────────────────────── │  (guest)  │
└──────────┘  DELETE /events/{token}/rsvps/   └──────────┘
                    {rsvpToken}
```

The transition is fully reversible: after cancellation, the guest can create a new RSVP (new token generated).

## Client-Side Storage (localStorage)

### StoredEvent (existing interface — no changes)

```typescript
interface StoredEvent {
  eventToken: string      // always present
  title: string           // always present
  dateTime: string        // always present
  organizerToken?: string // present if organizer
  rsvpToken?: string      // present if RSVP'd — CLEARED on cancel
  rsvpName?: string       // present if RSVP'd — CLEARED on cancel
}
```

### Cancel Effects on localStorage

| Action | rsvpToken | rsvpName | Event in list |
|--------|-----------|----------|---------------|
| Cancel from detail view | Removed | Removed | Kept |
| Remove from event list | Removed | Removed | Removed |

## Repository Changes

### RsvpRepository (domain port)

New method:

```java
/**
 * Delete an RSVP by event ID and RSVP token.
 * @return true if a record was deleted, false if not found
 */
boolean deleteByEventIdAndRsvpToken(Long eventId, RsvpToken rsvpToken);
```

### RsvpJpaRepository

New method:

```java
long deleteByEventIdAndRsvpToken(Long eventId, UUID rsvpToken);
```

Returns count of deleted rows (0 or 1). Spring Data JPA auto-implements this derived query.
