# Implementation Plan: Event List on Home Page **Branch**: `009-list-events` | **Date**: 2026-03-08 | **Spec**: `specs/009-list-events/spec.md` **Input**: Feature specification from `/specs/009-list-events/spec.md` ## Summary Transform the home page from a static empty-state placeholder into a dynamic event list that shows all events stored in the browser's localStorage. Each event card displays title, relative time, and role indicator (organizer/attendee). Events are sorted chronologically (upcoming first), past events appear faded, and users can remove events via delete icon or swipe gesture. A FAB provides persistent access to event creation. This is a **frontend-only** feature — no backend or API changes required. The existing `useEventStorage` composable already provides all necessary data access. ## Technical Context **Language/Version**: TypeScript 5.9, Vue 3.5 **Primary Dependencies**: Vue 3, Vue Router 5, Vite **Storage**: Browser localStorage via `useEventStorage` composable **Testing**: Vitest (unit), Playwright + MSW (E2E) **Target Platform**: Mobile-first PWA (centered 480px column on desktop) **Project Type**: Web application (frontend-only changes) **Performance Goals**: Event list renders within 1 second (SC-001) — trivial given localStorage read **Constraints**: No external dependencies, no tracking, WCAG AA, keyboard navigable **Scale/Scope**: Typically <50 events in localStorage; no pagination needed ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* | Principle | Status | Notes | |-----------|--------|-------| | I. Privacy by Design | ✅ PASS | Purely client-side. No data leaves the browser. No analytics. | | II. Test-Driven Methodology | ✅ PASS | Unit tests for composable, E2E for each user story. TDD enforced. | | III. API-First Development | ✅ N/A | No API changes — this feature reads only from localStorage. | | IV. Simplicity & Quality | ✅ PASS | Minimal approach: extend existing composable + new components. No over-engineering. | | V. Dependency Discipline | ✅ PASS | No new dependencies. Swipe gesture implemented with native Touch API. Relative time via built-in `Intl.RelativeTimeFormat`. | | VI. Accessibility | ✅ PASS | Semantic list markup, ARIA labels, keyboard navigation, WCAG AA contrast on faded past events. | **Gate result: PASS** — no violations. ## Project Structure ### Documentation (this feature) ```text specs/009-list-events/ ├── plan.md # This file ├── spec.md # Feature specification ├── research.md # Phase 0 output ├── data-model.md # Phase 1 output └── tasks.md # Phase 2 output (/speckit.tasks command) ``` ### Source Code (repository root) ```text frontend/ ├── src/ │ ├── composables/ │ │ ├── useEventStorage.ts # MODIFY: add removeEvent() │ │ ├── useRelativeTime.ts # NEW: Intl.RelativeTimeFormat wrapper │ │ └── __tests__/ │ │ ├── useEventStorage.spec.ts # MODIFY: add removeEvent tests │ │ └── useRelativeTime.spec.ts # NEW: relative time formatting tests │ ├── components/ │ │ ├── EventCard.vue # NEW: individual event list item │ │ ├── EventList.vue # NEW: sorted event list container │ │ ├── EmptyState.vue # NEW: extracted empty state │ │ ├── CreateEventFab.vue # NEW: floating action button │ │ ├── ConfirmDialog.vue # NEW: reusable confirmation prompt │ │ └── __tests__/ │ │ ├── EventCard.spec.ts # NEW │ │ ├── EventList.spec.ts # NEW │ │ ├── EmptyState.spec.ts # NEW │ │ └── ConfirmDialog.spec.ts # NEW │ ├── views/ │ │ └── HomeView.vue # MODIFY: compose list/empty/fab │ └── assets/ │ └── main.css # MODIFY: add event card, faded, fab styles └── e2e/ └── home-events.spec.ts # NEW: E2E tests for all user stories ``` **Structure Decision**: Frontend-only changes. New components in `components/`, composable extensions in `composables/`, styles in existing `main.css`. No backend changes. ## Complexity Tracking No constitution violations — this section is intentionally empty.