T7 — Household restructure design spec (2026-06-24)
Status: DRAFT for user review. Approved direction 2026-06-24 (the user picked "design it properly first" + the locked decisions below). No implementation until the user signs off on this spec. Next step after sign-off:
writing-plans.
Goal: Restructure the Household experience to match the product model: the Household tab shows read-only member profiles (each holding that member's individual goals) plus a Family Goals section; member management (app-user accounts: add/edit/remove, roles, invites) moves to its own page under More → Account; and the goal request → approve lifecycle is wired end to end.
Grounded in: the POC (../Chore_app) Household/MemberProfile/Members structure
(see .git/sdd/progress-p1p2.md POC study + memory rewhaven-member-roles-and-goals)
and the current rebuilt-app + SDK state (mapped 2026-06-24).
Locked decisions (from the user, 2026-06-24)
- Design-first — brainstorm → spec → plan → build (this doc is the spec).
- Member management → its own page under More → Account. The Household tab shows read-only member-profile tiles (not the management CRUD).
- Wallet-on-profile → resolved here: include a read-only wallet glance
(spend/save/give) on the member profile. It is cheap —
walletOf(memberId)already exists and is ledger-derived. The full Money/Wallet management UI stays out of scope.
The two people-concepts (do not conflate)
- Member PROFILE = a tracked family member (does chores, earns, holds individual goals). Lives on the Household tab as a read-only tile → opens the MemberProfile page.
- Member MANAGEMENT = managing app-user accounts/roles/invites. Lives on its own page under More → Account.
- Roles (already in the SDK):
MemberKind {parent, coParent, child}= family relationship (immutable;isParentalgates approvals).MemberRole {admin, helper, member}= permissions (mutableSet<MemberRole>).MemberStatus {shadow, invited, active}= account lifecycle. Approval gate staysMemberKind.isParental(not the admin role) — intentional separation;approveGoalalready requires a parentalactingMemberId.
What already exists (no SDK domain work needed)
MemberRole/roles,MemberStatus,homePlaceId,watchOnly— all built.Goal {scope: family|member, status, memberId, name, targetTokens, emoji, imageUrl, dueLabel};GoalStatus {active, requested, complete, archived}.- Facade goal methods:
createGoal,getGoals({memberId, includeArchived}),requestGoal(id),approveGoal({id, actingMemberId}),completeGoal(id),archiveGoal(id),restoreGoal(id),updateGoal(Goal),goalProgress(goalId). walletOf(memberId) → Wallet {spend, save, give},balanceOf(...).- Member methods:
watchMembers,addMember,updateMember,removeMember,setMemberHomePlace,assignableMembers.
What T7 builds (UI + thin layers)
GoalsRepository(new, thin delegate — mirrorHouseholdRepository): forwards the goal facade methods.app/lib/outside/repositories/goals/goals_repository.dart.watchGoals()on the SDK facade — DECISION FOR REVIEW. Today goals are read one-shot viagetGoals(). Recommended: addStream<List<Goal>> watchGoals({String? memberId, bool includeArchived})for live updates, consistent withwatchMembers/watchChores. Alternative: keepgetGoals- manual refresh after each mutation (less code, no live cross-surface sync). I
recommend
watchGoalsfor consistency; flag if you'd rather keep it one-shot.
- manual refresh after each mutation (less code, no live cross-surface sync). I
recommend
- Household tab restructure — read-only member-profile tiles + a Family Goals
card (
scope == family) + existing house config (keep). The current T5 inline members list becomes profile tiles linking to the MemberProfile page. - MemberProfile page (new route under the Household tab) — identity (name, emoji,
age, traits, home-room, watch-only) + roles (read; editing happens in management)
- wallet glance (read-only spend/save/give via
walletOf) + personal goals (scope == member,memberId == this) with add + the request→approve lifecycle.
- wallet glance (read-only spend/save/give via
- Members-management page under More → Account — full CRUD (add/edit/remove),
role grants (admin/helper/member chips, admin-only), invite fields (scaffold;
live invite is its own later effort). Relocates T5's
member_editor_sheet+members_blocediting here (Household stops owning the editor). - Goal request → approve — a member proposes a goal (
requestGoal→requested); a parental member approves (approveGoal({id, actingMemberId})→active). Surface the queue where a parent will see it (proposed: a "Goal requests · needs your OK" section on the MemberProfile and/or a Household-level badge). The acting member must be parental — resolve the current acting member from the session/household.
Architecture (load-bearing rules hold)
- New
GoalsBloc(+ a profile bloc) depend on repositories (GoalsRepository,HouseholdRepository) — never the facade directly, never drift/supabase. GoalsRepositoryis a pure thin delegate; goal rules stay inEconomyService.- Routing: add
MemberProfileRoute(nested under the Household tab) + aMembersManagementRoute(under More). auto_route codegen → restore clobbered*.g.dart/router.gr.dartsiblings after build_runner (known hazard). - Immutability, DS atoms, i18n strings (avoid the T5 hardcoded-string drift), a11y floor.
Reconciling what T5 built
T5 put a members list + editor sheet on the Household tab. Under this design:
- The Household members list → read-only profile tiles (tap → MemberProfile).
- The editor sheet + add/edit/remove → moves to the Members-management page under More → Account (plus gains role editing + remove).
members_blocis reused/split: a read path for the Household tiles + the profile, and the management CRUD path on the management page.
Proposed phasing (for the plan, after sign-off)
- P1 — Goal foundation:
GoalsRepository(+watchGoalsif approved) + aGoalsBloc; tests. - P2 — Members management page (More → Account): relocate the T5 editor; add role grants + remove; tests.
- P3 — Household tab restructure: read-only profile tiles + Family Goals card; tests.
- P4 — MemberProfile page: identity + roles(read) + wallet glance + personal goals; tests.
- P5 — Goal request → approve flow + the parent approval surface; tests.
Testing
- Flow tests per surface (Household tiles, MemberProfile, Members-management, goal
request→approve) via the
MocksContainer/testAppBuilderharness mocking repos. - Unit tests for the new blocs (goal lifecycle transitions, family-vs-member filtering, role-edit gating to admins, parental-only approve).
- Reuse the anti-corruption guardrails from the T4–T8 build (no destructive git,
explicit
git add, verify no test-file deletions, assert suite count ≥ baseline).
Out of scope
- Full Money/Wallet/History UI (only the read-only profile wallet glance).
- Live co-parent invite acceptance / auth wiring (SP2, parked).
- The AI recommender service (stub).
- Goal funding/allocation flows beyond what
goalProgressalready derives.
Open questions for the user (review these)
watchGoalsvs one-shotgetGoals— add the stream (recommended) or refresh-on-mutation?- Goal-approval surface — show requested goals on the MemberProfile, a Household badge, or both? Who is the default acting (approving) member resolved from?
- Members-management entry — confirm More → Account → Members (a new "Account" group on the currently-empty More page) is the right home.
- Role editing scope for T7 — edit
MemberRolenow, or read-only for T7 and defer role-granting UI? (The SDK supports it; it's a UI-scope call.)