summaryrefslogtreecommitdiff
path: root/docs/adr/002-timeline-aggregation.md
blob: 2700776565d2fede8a5730c294a78cecd07de414 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# ADR 002: Timeline Aggregation Architecture

## Status
Accepted

## Context
The dashboard aggregates data from multiple sources (Todoist, Trello, PlanToEat, Google Calendar, Google Tasks). Users need a unified chronological view of upcoming items across all sources without opening multiple apps.

Key challenges:
- Different data sources have different models (Task, Card, Meal, Event)
- Some sources have time-of-day, others only have dates
- Meals have no explicit time but should appear at logical meal times
- Need to support grouping by day section (Today, Tomorrow, Later)

## Decision
Implement a **polymorphic TimelineItem model** that normalizes all data sources into a single sortable structure.

### Technical Details:

**Unified Model (`internal/models/timeline.go`):**
```go
type TimelineItem struct {
    ID          string
    Type        TimelineItemType  // task, meal, card, event, gtask
    Title       string
    Description string
    Time        time.Time
    AllDay      bool
    URL         string
    DaySection  string  // overdue, today, tomorrow, later
    // ... additional fields
}
```

**Meal Time Defaults:**
- Breakfast → 08:00
- Lunch → 12:00
- Dinner → 19:00
- Other → 12:00

**Implementation:**
- `internal/handlers/timeline_logic.go` - `BuildTimeline()` aggregation function
- `internal/handlers/timeline.go` - HTTP handler
- `internal/models/timeline.go` - Data models
- Store methods: `GetTasksByDateRange()`, `GetMealsByDateRange()`, `GetCardsByDateRange()`

**Grouping Strategy:**
Items are grouped into collapsible day sections:
- **Overdue** - Past due items (expanded)
- **Today** - Due today (expanded)
- **Tomorrow** - Due tomorrow (expanded)
- **Later** - 2+ days out (collapsed by default)

## Consequences

**Pros:**
- Single unified view reduces context switching
- Consistent sorting regardless of data source
- Extensible - new sources just need a converter to TimelineItem
- Collapsible sections reduce cognitive load

**Cons:**
- Meal times are assumed, not actual (user might eat breakfast at 10am)
- All-day items appear at midnight, requiring special handling
- Multiple API calls per request (mitigated by caching)

## Alternatives Considered

**Option A: Source-specific views only**
- Rejected: Defeats the purpose of a unified dashboard

**Option B: Store normalized items in database**
- Rejected: Adds complexity, staleness issues, harder to keep in sync

**Option C: Client-side aggregation (JavaScript)**
- Rejected: More complex, slower on mobile, harder to test