Catalog / Earn / Today Restructure — Design Spec
Date: 2026-07-21
Status: Draft for owner review
Branch target: feat/mvp1-personas-authz (or a fresh feature branch)
Goal
Make the earning experience personal and actionable for each member, make Today a family dashboard for parents, and give admins a single Manage surface for every catalog type plus a badged review queue for kids' submitted suggestions.
This is mostly reassembly of existing pieces (claim/join, submit-completion, member-request-for-4-types, editor sheets, DsSegmented tabs all already exist) plus four genuine gaps. No new SDK domain verbs are required for the core flows.
Confirmed decisions (owner)
- Earn + Rewards stay separate member tabs (not merged into one tabbed page).
- Everything on Earn/Rewards is tied to the specific user — the member-switcher is kept but defaults to self.
- The one tabbed page is the Admin Manage surface — tabs for Rewards · Activities · Chores · Bounties (4 tabs, no dedicated Recommendations tab) — and it replaces today's separate "Manage Rewards" / "Manage Activities" admin rows.
- Recommendations = member-submitted
ChoreRequests (kids can already propose any of the 4 types). Submit moves onto the Earn (chore/bounty) and Rewards (activity/reward) tabs as a "provide feedback / suggest" affordance → the suggestion section is removed from Household. Review is inline: pending suggestions of a type render at the top of that type's Manage list (approve/reject there). A badge on the Manage row in the More tab shows when anything is pending. (This is NOT the AIrecommendsheet — that stays as-is.) - Today is a role-personalized high-level dashboard (not the do-it screen):
- admin / owner / parent (any "manager") → the whole family (all members' rows) — confirmed 2026-07-22
- plain member (non-admin, non-parent, incl. kids) → their own + family goals Earn/Rewards are the action-oriented member pages; the Today/Earn check-off overlap is intentional (two entry points, same action).
Global constraints
- FVM only (
fvm flutter/fvm dart); one data path (Bloc → Repository → Client facade → Service → Adapter); presentation never imports supabase/drift. - Tabs use the existing
DsSegmented<T>atom (no FlutterTabBar); cards reuseCatalogItemCard/EarnChoreCard/reward cards; admin pages follow theRewardsManagementPagescaffold. - Suite baselines must not drop (app 757 / SDK 1163 / DS 287 at spec time).
- No brand strings in package/class names; all copy via
Strings.
Architecture — reuse map (from codebase exploration)
Reuse as-is:
CatalogBlocalready loads all four types + eligibility + wallet + claim state; both Earn and Rewards tabs instantiate it.- Interaction seams wired:
CatalogBountyClaimed(join/claim),CatalogRewardRedeemRequested,CatalogActivityRedeemRequested,submitCompletion(Today),requestChore(member submit, 4 types),approveChoreRequest/rejectChoreRequest(admin resolution). - Models:
Chore.assignedMemberIds/assignedMemberIdsUnion(assignment),ChoreKind.expectation/bounty,claimedByMemberIds/canClaimBounty()/hasJoined()/isMultiClaimFull()(claim state),ChoreRequest.itemType(chore/bounty/activity/reward discriminator). - Admin scaffold:
RewardsManagementPage/ActivitiesManagementPage(list + editor sheet);_AdminRowhub pattern.
Genuine gaps to build:
- "Assigned to me / To-Do" projection —
CatalogStatehas noassignedToMegetter (pure filter onchoresbyassignedMemberIdsUnion+ selected member). No SDK change. - Submit from Earn —
CatalogBlochas no completion-submit event; logic lives inTodayChoresBloc._onCompletionSubmitted. Add aCatalogChoreCompletionSubmittedevent reusingChoresRepository.submitCompletion. - Nav / section badge — no badge mechanism exists;
DsNavDestinationcarries none. Need a pending-recommendations count propagated to the admin surface (and optionally the nav). - Chores & Bounties admin list page — none exists (chore CRUD is only the
ChoreEditorRoutevia FAB/per-row). Build a management page mirroringRewardsManagementPage, reusing the existing chore editor sheet/route. - Manage tabs are cross-bloc today — Rewards uses
RewardsBloc, Activities usesActivitiesBloc, chores useCatalogBloc/ChoreEditorBloc. The tabbed Manage page hosts these under one scaffold with aDsSegmentedtype selector. - Recommendations queue is on the Household tab today (
ChoreRequestsSection,MembersBlocpage-scoped). Move/surface a variant into Manage; needs a shell- or page-scoped requests source.
Surface designs
1. Today — role-personalized high-level dashboard
Today is the centralized overview, scoped by the viewer's role (NOT the action surface — that's Earn/Rewards):
- manager (admin role OR owner OR parent/co-parent): the whole family — all members' rows, reusing the existing grouping (#190). Admins/parents see everyone.
- plain member (non-admin, non-parent, incl. kids): their own items + family goals (shared household goals,
GoalScope.family). - Single rule: "if the viewer is a manager (admin/owner/parental) or unknown → show the full roster; else → the viewer's own row + family goals." Implemented bloc-side in
TodayChoresBloc(_deriveViewerScope), leaving the widget a pure renderer and_tailor()untouched. - Done-states already correct per the shipped local-day reset fix. Reuse the existing selected-member submit/approve flow for a parent acting on a child's row.
2. Earn tab — personal to-do + joinable
- Reframe from "all chores greyed by eligibility" to "what's mine + what I can join."
- My To-Do: chores assigned to the active member (
assignedMemberIdsUnion.contains(memberId)), rendered as checkable/submittable rows — the actualsubmitCompletionhappens here (newCatalogChoreCompletionSubmittedevent), not only on Today. Applies to parents too (a parent checks off their own assigned chores here). - Joinable: open bounties / claimable chores the member hasn't joined (
canClaimBounty/!hasJoined), each with a Join affordance (existingCatalogBountyClaimed). - Member-switcher retained, defaults to self.
- Keep the existing
DsSegmentedfilter (All / To-Do / Joinable / …) as the in-tab control. - Suggest affordance: a "provide feedback / suggest" entry to propose a chore or bounty (relocated
requestChoreflow) — replaces the Household suggestion section for these types.
3. Rewards tab — personal
- Show the activities & rewards available/eligible to the active member, redeemable inline (existing redeem events). Personalized to the selected user (default self).
- Suggest affordance: a "provide feedback / suggest" entry to propose an activity or reward (relocated
requestChoreflow) — replaces the Household suggestion section for these types.
4. Admin — unified Manage page
- New page under
/admin(AdminGuard + MustChangePasswordGuard) with a topDsSegmentedselector: Rewards · Activities · Chores · Bounties (4 tabs; recommendations are inlined, not a tab). - Each type tab = [pending suggestions of this type at the TOP (approve/reject inline)] then the existing management list (add button + list + editor sheet). Rewards/Activities reuse
RewardsBloc/ActivitiesBloc; Chores and Bounties get a newChoresManagementPage-equivalent list (reusing the chore editor sheet/route; Bounties =ChoreKind.bountyfilter). - Replaces the standalone "Manage Rewards" / "Manage Activities" hub rows with one "Manage catalog" row in More (the tabbed page). Keeps the existing management pages' logic; just re-hosts them under the tabbed shell. The Manage row carries a pending-suggestions badge.
5. Recommendations (member suggestions) — submit on Earn/Rewards, review inline in Manage, badge in More
- Submit (member side): a "provide feedback / suggest" affordance on the Earn tab (propose a chore/bounty) and the Rewards tab (propose an activity/reward), reusing the existing
requestChoreflow (ChoreRequest.itemType). The current suggestion section on the Household tab is removed (its_RequestChoreDialoglogic relocates to Earn/Rewards). - Review (admin side): pending
ChoreRequests of a given type appear at the top of that type's Manage list, each with Approve / Reject (existingapproveChoreRequest/rejectChoreRequest; approval routes to the right create verb byitemType). No separate Recommendations tab or page. - Badge: a pending-count badge on the Manage row in More (aggregate across all four types). Needs a pending-count source surfaced to the More/Manage surface (a small shell/page-scoped requests cubit, or extend an existing bloc) and a badge affordance on the
_AdminRowwidget (which currently has none).
Proposed phasing (plan will task-break)
- Phase A — Today role-personalized dashboard: the single "own (+children if admin / +family goals if member)" rule; audience by role/participation. (Small, self-contained.)
- Phase B — Earn personalization + submit + join:
assignedToMestate, To-Do/Joinable sections,CatalogChoreCompletionSubmitted, switcher default-self. Rewards personalization. - Phase C — Admin Manage consolidation: tabbed page (4 tabs) hosting Rewards/Activities + new Chores/Bounties management; replace the two hub rows with one "Manage catalog" row in More.
- Phase D — Recommendations relocation + inline review + badge: move
requestChoresubmit onto Earn/Rewards + remove the Household suggestion section; render pending suggestions at the top of each Manage type list with approve/reject; pending-count badge on the More→Manage row (badge affordance added to_AdminRow).
Each phase is independently shippable and testable.
Testing
- Bloc tests:
assignedToMeprojection;CatalogChoreCompletionSubmittedhappy/blocked; join/claim eligibility; recommendations approve/reject routing peritemType; badge count. - Widget/flow tests: parent Today shows all members incl parents; kid Today personal; Earn To-Do check-off; Manage tab switching; badge appears on pending.
- Reuse existing test doubles (MockClient, in-memory adapter,
testAppBuilder).
Resolved (owner, 2026-07-21)
- Recommendations: NOT a dedicated tab — pending suggestions render at the top of each type's Manage list; badge on the More→Manage row. ✅
- Household requests section: moved entirely off Household (submit relocates to Earn/Rewards; review to Manage). ✅
- Badge scope: the More→Manage row only (no member-tab bottom-nav badge). ✅
- Earn ↔ Today overlap: intentional — check-off on both. ✅
Resolved (owner, 2026-07-22)
- Today scope: managers (admin/owner/parent) see the whole family; only a plain non-admin non-parent member is narrowed to self + family goals. No oversight toggle. ✅