Skip to main content

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)

  1. Design-first — brainstorm → spec → plan → build (this doc is the spec).
  2. Member management → its own page under More → Account. The Household tab shows read-only member-profile tiles (not the management CRUD).
  3. 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; isParental gates approvals). MemberRole {admin, helper, member} = permissions (mutable Set<MemberRole>). MemberStatus {shadow, invited, active} = account lifecycle. Approval gate stays MemberKind.isParental (not the admin role) — intentional separation; approveGoal already requires a parental actingMemberId.

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)

  1. GoalsRepository (new, thin delegate — mirror HouseholdRepository): forwards the goal facade methods. app/lib/outside/repositories/goals/goals_repository.dart.
  2. watchGoals() on the SDK facadeDECISION FOR REVIEW. Today goals are read one-shot via getGoals(). Recommended: add Stream<List<Goal>> watchGoals({String? memberId, bool includeArchived}) for live updates, consistent with watchMembers/watchChores. Alternative: keep getGoals
    • manual refresh after each mutation (less code, no live cross-surface sync). I recommend watchGoals for consistency; flag if you'd rather keep it one-shot.
  3. 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.
  4. 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.
  5. 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_bloc editing here (Household stops owning the editor).
  6. Goal request → approve — a member proposes a goal (requestGoalrequested); 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.
  • GoalsRepository is a pure thin delegate; goal rules stay in EconomyService.
  • Routing: add MemberProfileRoute (nested under the Household tab) + a MembersManagementRoute (under More). auto_route codegen → restore clobbered *.g.dart/router.gr.dart siblings 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/removemoves to the Members-management page under More → Account (plus gains role editing + remove).
  • members_bloc is 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 (+ watchGoals if approved) + a GoalsBloc; 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/testAppBuilder harness 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 goalProgress already derives.

Open questions for the user (review these)

  1. watchGoals vs one-shot getGoals — add the stream (recommended) or refresh-on-mutation?
  2. Goal-approval surface — show requested goals on the MemberProfile, a Household badge, or both? Who is the default acting (approving) member resolved from?
  3. Members-management entry — confirm More → Account → Members (a new "Account" group on the currently-empty More page) is the right home.
  4. Role editing scope for T7 — edit MemberRole now, or read-only for T7 and defer role-granting UI? (The SDK supports it; it's a UI-scope call.)