# Research: Event List Temporal Grouping

**Feature**: 010-event-list-grouping | **Date**: 2026-03-08

## 1. Week Boundary Calculation

**Decision**: Use ISO 8601 week convention (Monday = first day of week). "This Week" spans from tomorrow through Sunday of the current week.

**Rationale**: The spec explicitly states "ISO convention where Monday is the first day of the week" (Assumptions section). The browser's `Date.getDay()` returns 0 for Sunday, 1 for Monday — straightforward to compute end-of-week as next Sunday 23:59:59.

**Implementation**: Compare event date against:
- `startOfToday` and `endOfToday` for "Today"
- `startOfTomorrow` and `endOfSunday` for "This Week"
- `after endOfSunday` for "Later"
- `before startOfToday` for "Past"

Edge case (spec scenario 4): On Sunday, "This Week" is empty (tomorrow is already next week Monday), so events for Monday appear under "Later". This falls out naturally from the algorithm.

**Alternatives considered**:
- Using a date library (date-fns, luxon): Rejected — dependency discipline (Constitution V). Native `Date` + `Intl` is sufficient for this logic.
- Locale-dependent week start: Rejected — spec mandates ISO convention explicitly.

## 2. Date Formatting for Subheaders

**Decision**: Use `Intl.DateTimeFormat` with `{ weekday: 'short', day: 'numeric', month: 'short' }` to produce labels like "Wed, 12 Mar".

**Rationale**: Consistent with existing use of `Intl.RelativeTimeFormat` in `useRelativeTime.ts`. Respects user locale for month/weekday names. No external dependency needed.

**Alternatives considered**:
- Hardcoded English day/month names: Rejected — the project already uses `Intl` APIs for locale awareness.
- Full date format (e.g., "Wednesday, March 12, 2026"): Rejected — too long for mobile cards.

## 3. Time Display on Event Cards

**Decision**: Add a `timeDisplayMode` prop to `EventCard.vue` with two modes:
- `'clock'`: Shows formatted time (e.g., "18:30") using `Intl.DateTimeFormat` with `{ hour: '2-digit', minute: '2-digit' }`
- `'relative'`: Shows relative time (e.g., "3 days ago") using existing `formatRelativeTime()`

**Rationale**: Spec requires different time representations per section: clock time for Today/This Week/Later, relative time for Past. A prop-driven approach keeps EventCard stateless regarding section context.

**Alternatives considered**:
- EventCard determining its own display mode: Rejected — card shouldn't know about sections; parent owns that context.
- Passing a pre-formatted string: Viable but less type-safe. A mode enum is clearer.

## 4. Grouping Data Structure

**Decision**: The `useEventGrouping` composable returns an array of section objects:

```typescript
interface EventSection {
  key: 'today' | 'thisWeek' | 'later' | 'past'
  label: string  // "Today", "This Week", "Later", "Past"
  events: GroupedEvent[]
}

interface DateGroup {
  date: string       // ISO date string (YYYY-MM-DD) for keying
  label: string      // Formatted date label (e.g., "Wed, 12 Mar")
  events: StoredEvent[]
}

interface GroupedEvent extends StoredEvent {
  dateGroup: string  // ISO date for sub-grouping
}
```

Actually, simpler: the composable returns sections, each containing date groups, each containing events.

```typescript
interface EventSection {
  key: 'today' | 'thisWeek' | 'later' | 'past'
  label: string
  dateGroups: DateGroup[]
}

interface DateGroup {
  dateKey: string        // YYYY-MM-DD
  label: string          // Formatted: "Wed, 12 Mar"
  events: StoredEvent[]
}
```

**Rationale**: Two-level grouping (section → date → events) matches the spec's hierarchy. Empty sections are simply omitted from the returned array (FR-002). The "Today" section still has one DateGroup but the template skips rendering its subheader (FR-005).

**Alternatives considered**:
- Flat list with section markers: Harder to template, mixes data and presentation.
- Map/Record structure: Arrays preserve ordering guarantees (Today → This Week → Later → Past).

## 5. Visual Emphasis for "Today" Section

**Decision**: Apply a CSS class `.section--today` to the Today section that uses:
- Slightly larger section header (font-weight: 800, font-size: 1.1rem vs 700/1rem for others)
- A subtle left border accent using the primary gradient pink (`#F06292`)

**Rationale**: Consistent with Electric Dusk design system. Subtle enough not to distract but visually distinct. The existing past-event fade (opacity: 0.6, saturate: 0.5) already handles the other end of the spectrum.

**Alternatives considered**:
- Background highlight: Could clash with card backgrounds on mobile.
- Icon/emoji prefix: Spec doesn't mention icons; keep it typography-driven per design system.

## 6. Accessibility Considerations

**Decision**:
- Section headers are `<h2>` elements
- Date subheaders are `<h3>` elements
- The event list container keeps its existing `role="list"`
- Each section is a `<section>` element with `aria-label` matching the section label

**Rationale**: Constitution VI requires semantic HTML and ARIA. The heading hierarchy (h2 > h3) provides screen reader navigation landmarks. The `<section>` element with label allows assistive technology to announce section boundaries.

## 7. Existing Test Updates

**Decision**:
- Existing `EventList.spec.ts` unit tests will be updated to account for the new grouped structure (sections instead of flat list)
- Existing `home-events.spec.ts` E2E tests will be extended with new scenarios for temporal grouping
- New `useEventGrouping.spec.ts` tests the pure grouping function in isolation

**Rationale**: TDD (Constitution II). The grouping logic is a pure function — ideal for thorough unit testing with various date combinations and edge cases.
