Skip to main content

Today screen — Jobs-to-be-Done, chore/bounty grouping, analytic funnels (2026-06-19)

Binding definition for building the Today screen out. Grounds the chore vs bounty grouping in the SDK model and ties every section to a measurable funnel so analytics map to real jobs, not vanity counts.

The model (load-bearing distinction)

From client_sdk Chore:

Expectation (ChoreKind.expectation)Bounty (ChoreKind.bounty)
Pays tokensNEVER (tokenValue == 0, invariant 1)Yes (tokenValue > 0)
AssignmentNone — applies to every eligible kid (by minAge)Unassigned; a kid claims it (claimBountyclaimedByMemberId)
Meaning"the cost of being part of the family" — the scaffoldopt-in, freely chosen — the economy
Interactionmark done → submit → approve (0 tokens)claim → do → submit → approve → tokens

Completion always flows through submitCompletion → a pending Approval (ApprovalPolicy.manual) or an immediate auto-resolution (ApprovalPolicy.auto, still through ApprovalService). Tokens move only on approval (invariant 4).

The current Today screen renders every chore × every kid with a toggle — correct-ish for expectations, wrong for bounties (a bounty belongs to its one claimer, not all kids). This doc fixes that.

Jobs to be done

  • Parent: "When I open Today, show me what needs my decision (approvals), let me trust the day is on track, and let me nudge without nagging."
  • Kid: "Show me what I have to do (my expectations), how I can earn extra (bounties to claim), and let me mark things done myself."

Sections (each maps to one funnel)

  1. Expectations — the recurring "should-dos", grouped by kid (every eligible kid), no tokens. Mark-done → submit. (Filter: kind == expectation, active, expected in the current period.)
  2. Bounties — split: a claimable pool (unclaimed bounties any eligible kid can grab → Claim) and claimed bounties shown under their claimer to finish (submit). (Filter: kind == bounty, active.) Distinct affordance: claim, not a per-kid toggle.
  3. Approvals (parent members only) — the pending submissions queue (watchPendingApprovals) with approve / reject. The parent's oversight surface; hidden for child members.

Deferred (not this pass): Goals, spend-requests, rooms toggle, print.

Analytic funnels (instrument as we build — via MixpanelEffect.trackEvent)

Event names + properties below. The MixpanelEffect sanitizer hashes id-keys and drops financial/oversized keys, so ids are safe to pass.

Funnel 1 — Expectation completion (routine adherence; the scaffold working) today_section_shown {section:'expectations', count}chore_completion_submitted {chore_id, kind:'expectation'}chore_completion_approved {chore_id, kind:'expectation', resolved_by}

  • Watch: submitted ÷ shown (are kids doing their part), approved ÷ submitted (are parents keeping up on the no-token loop).

Funnel 2 — Bounty earning (the core motivation/economy loop) today_section_shown {section:'bounties', count, claimable_count}bounty_claimed {chore_id, token_value_bucket}chore_completion_submitted {chore_id, kind:'bounty'}chore_completion_approved {chore_id, kind:'bounty', resolved_by}

  • Watch: claimed ÷ shown is the headline (does the economy pull?), and submitted ÷ claimed (do claims convert to work). token_value_bucket is a coarse band (e.g. 1-3 / 4-9 / 10+), never the raw amount (privacy).

Funnel 3 — Parent approval (parent engagement; stalls predict churn) today_section_shown {section:'approvals', count}approval_resolved {approval_id, decision:'approved'|'rejected'}

  • Watch: resolved ÷ shown + time-to-resolve (a growing pending pile = a parent falling off → churn signal).

Page-level [page]: HomeRoute is already emitted by the nav observer; these section/action events sit under it.

Where the events fire (so funnels are honest)

  • today_section_shown — once per section per Today load, when the section has ≥1 item (from the Today bloc on load).
  • bounty_claimed / chore_completion_submitted — in the Today bloc, on the successful repository call.
  • chore_completion_approved / approval_resolved — in the bloc, on the successful approve/reject (carry resolved_by = manual | auto | parent).

Build notes

  • ChoresRepository gains claimBounty; a new ApprovalsRepository (watchPendingApprovals, approve, reject).
  • The Today bloc loads the three sections, exposes parent-vs-kid role (approvals visible to parents only), and takes the MixpanelEffectProvider to fire the funnel events (Effect Provider → Bloc is allowed, separation_of_concerns).
  • Domain molecules (per-screen): keep TodayChoreRow for expectations; add a BountyRow (claim / claimed-with-submit) and an ApprovalCard (approve / reject). Promote to the DS only if a second screen proves them.
  • Honest states: a submitted expectation/bounty shows "submitted, waiting for approval" (partial), not a tick (mirrors the current TodayChoreRow).