Child timeline
Status: ⭐ Differentiator · ✅ BUILT (Wave-2 A5)
Scope
The child timeline is a visual "look-back" surface — the Today surface is for acting, the timeline is for reflecting. Shows chore completions, token earnings, redemptions, and bucket-move / goal-contribution events in reverse-chron order. Primary audience is the child; parents can also view it from the child's Member Profile.
Implementation (Wave-2, Slice A5 — commit f3322d6)
The timeline is a pure projection — no stored state. On load, TimelineCubit fires four parallel reads and merges them into a unified, reverse-chronological list capped at 100 entries (TimelineState.kMaxEntries).
Phase-1 entry types
| Type | Source | Notes |
|---|---|---|
CompletionEntry | Client.getCompletions | Chore name + emoji resolved from ChoresRepository.getChores at load time; falls back to choreId if the chore was deleted |
EarnEntry | Client.watchLedger (first event, kind == earn) | Delta always positive |
RedemptionEntry | Client.getRedemptions | Canonical spend record — the complementary spend/give ledger entries are excluded to avoid double-counting |
MovePairEntry | Client.watchLedger (kind == move), debit+credit paired by shared refId | When the credit leg has a non-null goalId, isGoalContribution is true and the UI renders "saved toward goal" instead of generic bucket-move copy |
Excluded: adjust entries are never shown. spend and give ledger entries are excluded (covered by RedemptionEntry). Move entries with a null refId (unpaired anomalies) are skipped.
Kudos is NOT a Phase-1 entry type. It is not built and does not appear on the timeline. The four entry types above are the complete shipped set.
Presentation rules
- Reverse-chronological, grouped by viewer-local calendar day.
- Day headings via pure
dayLabel(day, now): "Today", "Yesterday", named weekday within 7 days, then "12 July" format for older entries. - Footer shown when the pre-cap count exceeded 100 entries (
isCapped). - No shame entries — nothing about missed or declined chores.
IA placement
Lives as a Member Profile sub-page: a teaser section on MemberProfilePage links to the full MemberTimelinePage (route MemberTimelineRoute, path param :memberId). Parents viewing a child's profile see the same page — household-scoped reads, no new exposure surface.
Source files
app/lib/inside/blocs/timeline/timeline_entry.dart— sealed entry hierarchyapp/lib/inside/blocs/timeline/cubit.dart— load + merge logicapp/lib/outside/repositories/timeline/timeline_repository.dart— thin repo delegateapp/lib/inside/routes/authenticated/member_timeline/page.dart—MemberTimelinePage+dayLabel
Relationship
Member Profile — timeline is a sub-page of the member's profile.