Skip to main content

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

TypeSourceNotes
CompletionEntryClient.getCompletionsChore name + emoji resolved from ChoresRepository.getChores at load time; falls back to choreId if the chore was deleted
EarnEntryClient.watchLedger (first event, kind == earn)Delta always positive
RedemptionEntryClient.getRedemptionsCanonical spend record — the complementary spend/give ledger entries are excluded to avoid double-counting
MovePairEntryClient.watchLedger (kind == move), debit+credit paired by shared refIdWhen 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 hierarchy
  • app/lib/inside/blocs/timeline/cubit.dart — load + merge logic
  • app/lib/outside/repositories/timeline/timeline_repository.dart — thin repo delegate
  • app/lib/inside/routes/authenticated/member_timeline/page.dartMemberTimelinePage + dayLabel

Relationship

Member Profile — timeline is a sub-page of the member's profile.