# Data Model: Event List on Home Page **Feature**: 009-list-events | **Date**: 2026-03-08 ## Entities ### StoredEvent (existing — no changes) The `StoredEvent` interface in `frontend/src/composables/useEventStorage.ts` already contains all fields needed for the event list feature. ```typescript interface StoredEvent { eventToken: string // Required — UUID, used for navigation organizerToken?: string // Present if user created this event title: string // Required — displayed on card dateTime: string // Required — ISO 8601, used for sorting + relative time expiryDate: string // Stored but not displayed in list view rsvpToken?: string // Present if user RSVP'd to this event rsvpName?: string // User's name at RSVP time } ``` ### Validation Rules An event entry is considered **valid** for display if all of: - `eventToken` is a non-empty string - `title` is a non-empty string - `dateTime` is a non-empty string that parses to a valid `Date` Invalid entries are silently excluded from the list (FR-010). ### Derived Properties (computed at render time) | Property | Derivation | |----------|-----------| | `isPast` | `new Date(dateTime) < new Date()` | | `isOrganizer` | `organizerToken !== undefined` | | `isAttendee` | `rsvpToken !== undefined && organizerToken === undefined` | | `relativeTime` | `Intl.RelativeTimeFormat` applied to `dateTime` vs now | | `detailRoute` | `/events/${eventToken}` | ### Sorting Order 1. **Upcoming events** (`dateTime >= now`): ascending by `dateTime` (soonest first) 2. **Past events** (`dateTime < now`): descending by `dateTime` (most recently passed first) ### Composable Extension The `useEventStorage` composable needs one new function: ```typescript function removeEvent(eventToken: string): void { const events = readEvents().filter((e) => e.eventToken !== eventToken) writeEvents(events) } ``` Returned alongside existing functions from `useEventStorage()`. ## State Transitions ``` localStorage read │ ▼ Parse JSON ──(error)──► empty array │ ▼ Validate entries ──(invalid)──► silently excluded │ ▼ Split: upcoming / past │ ▼ Sort each group │ ▼ Concatenate ──► rendered list ``` ### Remove Event Flow ``` User taps delete icon / swipes left │ ▼ ConfirmDialog opens │ ┌────┴────┐ │ Cancel │ Confirm │ │ │ │ ▼ ▼ │ removeEvent(token) │ │ │ ▼ │ Event removed from localStorage │ List re-renders (event disappears) └────────────────────────────────┘ ```