Skip to main content

Household — feature architecture

DRAFT — IA decided 2026-06-25. The Household tab is the people surface (read-only member tiles + Family Goals); budget/summaries live on Dashboards and all configuration in Admin. This is the source of truth that flow tests, unit tests, and implementation derive from (same contract as Member Profile).

Purpose & scope

The Household tab (HouseholdPage, in the adult nav set Home · Earn · Rewards · Household · Profile) is the family + house at a glance: a read-only overview of every member (tap → Member Profile) plus the family-level shared things. It is deliberately not where you manage accounts/roles, nor where you configure the economy or catalog. Per-member detail lives in the member profile; member management lives in Profile → Account; economy/budget/flags are settings.

Current state vs intent (important)

  • Today (as-built): the tab renders only a members ListView + an add-member button + a member-editor bottom sheet (MembersBloc). That is the T5 state — a member roster, not the restructured Household.
  • T7 (restructure) is specced but NOT built (every plan checkbox unchecked). T7's locked decisions: Household = read-only member-profile tiles + Family Goals card + house config; member management (add/edit/remove/roles/invite) moves to Profile → Account → Members.
  • The POC's Household page also carried economy, budget, rooms, giving-destination, and catalog-management tiles. This doc argues most of those do not belong on the Household tab — see the IA assessment.

IA — where everything lives (DECIDED 2026-06-25)

The split is act / glance / browse / people / configure. The Household tab is the people surface — nothing else lives there.

SurfaceRoleHousehold-related content
Home (Today)actdo chores, approvals
Dashboardsglancefamily budget (1st widget) + budget/goal summaries + today + member glance; lean-back TV/desktop ambient — see Dashboards
Catalogbrowsechore/reward browse + redeem
Householdpeopleread-only member tiles (→ Profile) + the Family Goals card. That is the whole tab.
Profile → Adminconfigure (parental)catalog CRUD · accounts/invites · economy · feature flags · house (name/emoji/address + rooms/zones) · default buckets · Billing (owner-only) — see Admin features
Member Profilepersonal (sub-page)wallet/envelopes · goals · own budget/buckets · "Manage account" → Admin

Decisions

  1. Household tab = the people surface: read-only member tiles (→ Profile) + Family Goals. The budget + summaries live on Dashboards; all config lives in Admin.
  2. Admin lives under Profile — a single hub, MemberKind.isParental-gated. It holds every CRUD surface (catalog, accounts/invites, economy, flags, house/rooms/zones, default buckets) + Billing (owner-only; multiple owners).
  3. Helper gets NO admin access. MemberRole.helper (think babysitter) can only approve / deny completed jobs — nothing else. Admin/config is isParental only.
  4. Move funds: the member themselves (their own envelopes) and an admin (any member's wallet) can move funds — see Money & Envelopes.
  5. Member management → Admin → Accounts; the Member Profile links to it via "Manage account". Household tiles stay read-only.
  6. Rooms = "zones" via Place.floor (no new entity): restore emoji + floor, add the missing updatePlace. Managed in Admin → House.
  7. House address → an optional field on Household (not on a room — see ERD).
  8. Family budget shows on the Dashboard: a non-admin can recommend a change (admin reviews — mirrors goal request → approve); an admin gets an "Edit" link into Admin → Family budget.
  9. Base envelopes = Spend + Save (fixed base) + a Give bucket the admin can remove / rename / re-icon. Members CRUD their own buckets (except admin-permanent ones). See Money & Envelopes.

Feature set (target)

Status: ✅ built · 🔨 to build (SDK-ready) · 📍 lives off-tab (Admin / Dashboards).

FeatureStatusSDK surfaceNotes
Member roster (read-only tiles → Profile)🔨 (today: editable list)watchMembers() + walletOf + getGoals(memberId)restructure to a read-only tile w/ wallet glance + 🎯 goal chip
Family Goals card🔨getGoals(memberId:null) + createGoal(scope:family) + lifecyclereuse the goal components from member-profile
Member management📍 Admin → AccountsaddMember/updateMember/removeMember/setMemberRoleoff the tab; profile links via "Manage account"
Budget + summaries📍 Dashboardsbudget + goalProgress aggregationthe dashboard's first widget
House config · economy · flags · default buckets · billing📍 Adminsee Admin featuresconfigure, not overview. SDK gaps: updatePlace, Household.address

ERD

Notes: there is no giveDestinationName on Household (POC had it) and no updatePlace anywhere — both are SDK gaps. Family-goal progress (goalProgress) sums all members' save balances.

Multi-household (DEFERRED — forward-compatible model)

A family may eventually span multiple houses (co-parents across two homes; a kid whose identity is present in both). The feature (a house picker, switching, cross-house views) is deferred — but the model is shaped now so we can evolve into it without a migration that splits identity or money:

  • Account ↔ households = many-to-many. An auth account (authUserId) may be associated with more than one household (e.g. a parent managing two homes).
  • Member ↔ households = many-to-many via a membership/identity link. A person can be present in multiple households (aligns with the post-MVP "continuous kid identity" / divorce-clone note).
  • Wallet + goals belong to the MEMBER, not the house. They are member-scoped envelopes (see Money & Envelopes), so they travel with the member across houses — multi-house never fragments a member's money or goals.
  • House-scoped (one per house): chores, rooms/zones, family goals, economy config, default allocation, address.
  • Roles + the owner flag are per-membership. A person's MemberRoles and owner flag live on the HouseholdMember record, so they are scoped to that household — admin-in-A / member-in-B is supported. One subscription is per account (an account may manage N homes); the zero-admin and zero-owner guards are enforced per household (service + schema trigger). See Personas and Roles & permissions.

Build implication now: keep wallet/goals keyed by memberId (member identity), not householdId; don't hard-code "one household per account/member" in ways a future membership join would have to undo.

State machines

Household tab (members) bloc

(The member editor state machine — open/save/saveFailure — relocates to the Profile → Account Members-management page; it leaves the Household tab.)

Family Goal lifecycle

Identical to the member goal lifecycle (see Member Profile → State machines): active → requested → active (approve, parental) → complete, → archived → active. The only difference is scope == family (memberId == null), so a family goal is proposed/approved at the household level, not for one member.

Data flow

The members-management surface (Profile → Account) reuses HouseholdRepository (add/update/remove/role) — the CRUD logic relocates, it is not duplicated.

SDK surface (+ gaps)

Have: watchMembers/getMembers/addMember/updateMember/removeMember/setMemberRole/ setMemberHomePlace/setMemberTraits/setMemberColorKey/assignableMembers, walletOf, getGoals/createGoal/updateGoal/archiveGoal/restoreGoal/requestGoal/ approveGoal/completeGoal/goalProgress, setHouseholdName, updateEconomyConfig, getPlaces/createPlace/deletePlace, getFeatureFlags/setProductFeatureFlag.

Gaps to fill before the relevant build:

  1. updatePlace — absent at every layer (facade/service/StoragePort/adapter). Needed to rename a room (today = delete + recreate). Required only if Rooms management lands.
  2. Household.giveDestinationName — model field + setter absent. Required only if giving-destination lands.
  3. watchGoals(...) stream — absent; family + member goals are one-shot getGoals today. A nicety for live family-goal updates (T7 P1).

Test plan (anchors)

Unit / bloc: members roster load + live re-emit; family GoalsBloc load + request/approve/complete/archive transitions (mirror member_profile_bloc_test.dart). Flow / golden: Household tab shows read-only member tiles (wallet glance + goal chip) + a Family Goals card; tapping a tile → MemberProfile; a family goal request → "awaiting approval"; (members-management page lives in its own flow test under Profile → Account). Widget: member tile renders glance + goal chip; family-goal tile states.

Build order (after IA sign-off)

  1. Household tab restructure — read-only member tiles (wallet glance + 🎯 goal chip) + tap→MemberProfile; remove inline add/edit from the tab.
  2. Family Goals card — family-scope goals list + add + request→approve (reuse the member-profile goal components/state machine).
  3. Members-management page under Profile → Account — relocate the editor, add role grants + remove (T7 P2).
  4. (Conditional on IA decisions) house-config header tile; Rooms management (needs updatePlace); economy/giving in Profile → Settings (needs giveDestinationName).

Each step ships with its tests per the test plan and goes through a flutter review gate, same as the member-profile feature.