Add client-side watch/bookmark functionality: users can save events to localStorage without RSVPing via a bookmark button next to the "I'm attending" CTA. Watched events appear in the event list with a "Watching" label. Bookmark is only visible for visitors (not attendees or organizers). Includes spec, plan, research, tasks, unit tests, and E2E tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2.3 KiB
2.3 KiB
Data Model: Watch Event
Feature: 017-watch-event Date: 2026-03-12
Entities
StoredEvent (existing — localStorage)
No schema change. The existing StoredEvent interface already supports the watcher state:
StoredEvent {
eventToken: string # Required — event identifier
organizerToken?: string # Present → organizer role
title: string # Required — display in event list
dateTime: string # Required — grouping/sorting
rsvpToken?: string # Present → attendee role
rsvpName?: string # Present with rsvpToken
}
Watcher state: A StoredEvent with only eventToken, title, and dateTime populated (no organizerToken, no rsvpToken). This state already occurs naturally after RSVP cancellation.
Role Hierarchy
organizerToken present → "Organizer" (highest precedence)
rsvpToken present → "Attendee"
neither present → "Watching" (new label, lowest precedence)
State Transitions
┌──────────────┐
watch() │ │ un-watch()
(not stored) ───► │ Watching │ ───► (not stored)
│ │
└──────┬───────┘
│ RSVP
▼
┌──────────────┐
│ │
│ Attending │
│ │
└──────┬───────┘
│ Cancel RSVP
▼
┌──────────────┐
│ │ un-watch()
│ Watching │ ───► (not stored)
│ │
└──────────────┘
Note: Organizer state is set at event creation and cannot be removed through this feature. The bookmark icon is non-interactive for organizers.
No Backend Changes
This feature does not introduce any new database entities, API endpoints, or server-side logic. All data is stored in the browser's localStorage.