Files
projax/internal
mAi 326f4c83b9 feat(aggregate): introduce internal/aggregate/ for fan-out + day-grouping
Phase 5a slice A: a new package that concentrates the "fan out across
linked items" pattern web/dashboard.go, web/timeline.go and mcp/tools.go
each had separate copies of. No callers touch it yet — slices B/C/D
migrate them in turn.

- Aggregator with five methods (Todos/Events/Issues/Docs/Creations) plus
  All convenience for the MCP timeline. Each method takes a *store.Item
  slice and (optionally) a Window, returns typed Row slices.
- Row types embed the underlying caldav.Todo / caldav.Event / gitea.Issue
  so existing html/template field accesses (.Todo.UID, .Event.Summary,
  …) keep resolving via Go field promotion in slices B/C.
- TimelineRow sum-type wrapper (with pointer slots per Kind) plus the
  flat template-friendly fields. Lifted-but-untouched from web/.
- BuildTimelineDays + SortTimelineRows + EventStartLabel +
  EventDurationHint lifted near-verbatim from web/timeline.go.
- CalDAV/Gitea/Store interfaces in the aggregator so unit tests stub IO
  cleanly. Real *caldav.Client / *gitea.Client / *store.Store satisfy
  by method set.
- Per-source error handling preserved: log at WARN + skip the bad
  fetch, return surviving rows.

Tests cover empty inputs, fan-out call counts, per-source error
recovery, window narrowing for todos, issue-cache hit path, doc/creation
allow-list filtering, BuildTimelineDays asc/desc order, sticky pills,
far-future fade, within-day sort.

Plan doc captures the slicing strategy + design decisions:
docs/plans/aggregator-refactor.md.

Task: t-projax-5a-aggregator
2026-05-21 23:57:54 +02:00
..