Skip to main content

T7 — Household Restructure Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: superpowers:subagent-driven-development. Steps use - [ ] checkboxes. Status: DRAFT — paired with docs/superpowers/specs/2026-06-24-t7-household-restructure-design.md. Build only after the user reviews the spec. Open-question defaults are resolved below (flagged ⚐ — user may override).

Goal: Household tab = read-only member-profile tiles (each holding individual goals) + a Family Goals section; member management moves to its own page under More → Account; goal request→approve wired end to end.

Architecture: UI + thin layers only — the SDK domain (roles, goals, wallet) is fully built. New GoalsRepository (thin), new blocs depend on repositories (never the facade directly / never drift/supabase). auto_route for the new routes.

Tech Stack: Flutter 3.44 / Dart 3.9 (FVM), bloc, auto_route, the existing DS atoms + flow-test harness (MocksContainer/testAppBuilder).

Global Constraints

  • Layering: Bloc → Repository → client_sdk facade → Service. Presentation never imports drift/supabase/client_sdk/src. Goal rules stay in EconomyService.
  • Approval gate is MemberKind.isParental (not the admin role). approveGoal({id, actingMemberId}) requires a parental actingMemberId.
  • GoalScope: familymemberId == null; membermemberId != null.
  • Anti-corruption git guardrails (from the T4–T8 build): no git reset/checkout <path>/clean/stash/add -A; explicit git add <file>; no build_runner --delete-conflicting-outputs (scope --build-filter + restore clobbered *.g.dart/router.gr.dart/state.g.dart siblings from HEAD); before commit verify NO *_test.dart deletions; the app test suite count MUST stay ≥ the phase's baseline.
  • i18n: new user-facing strings go through Strings (avoid the T5 hardcoded-string drift). Immutability via copyWith. a11y floor on every surface.
  • Branch: feat/t7-household-restructure off main.

Resolved open-question defaults (⚐ = user may override)

  • watchGoals: ADD Stream<List<Goal>> watchGoals({String? memberId, bool includeArchived}) to the facade (consistent with watchMembers/watchChores). If the user prefers, fall back to one-shot getGoals + refresh-on-mutation.
  • Approval surface: requested goals appear (a) on the MemberProfile as a "Pending your OK" affordance to a parental viewer, and (b) as a small Household-level "N goal requests" badge. Acting (approving) member = the resolved current parental member (until SP2 auth lands, use the household's first MemberKind.isParental member).
  • Members-management entry: More → Account group → Members (user-confirmed: own page under More/Account).
  • Role editing: include MemberRole editing (admin/helper/member chips, admin-only) on the management editor. Can be made read-only if the user prefers to defer.

Phase 1: Goal foundation (repository + optional watch + bloc)

Files:

  • Create: app/lib/outside/repositories/goals/goals_repository.dart
  • Modify (⚐ if watchGoals approved): packages/client_sdk/lib/src/client/{client.dart,client_impl.dart} + services/economy_service.dart (+ the in-memory/cached/local adapters' goal read) to add watchGoals.
  • Create: app/lib/inside/blocs/goals/{bloc.dart,state.dart,events.dart}
  • Register the repository in the app runner (RepositoriesAll).
  • Test: app/test/unit/goals_bloc_test.dart, app/test/unit/goals_repository_test.dart (+ SDK test if watchGoals added).

Interfaces — Produces: GoalsRepository delegating createGoal/getGoals/requestGoal/approveGoal/completeGoal/archiveGoal/restoreGoal/updateGoal/goalProgress (+ watchGoals); GoalsBloc exposing family goals + per-member goals, with lifecycle events (request/approve/complete/archive/create/update).

  • TDD the repository delegates + the bloc lifecycle transitions (family vs member filtering; parental-only approve; request→active). Mirror HouseholdRepository + an existing bloc.
  • Wire into the runner; analyze clean; app suite ≥ baseline; commit.

Phase 2: Members-management page (More → Account)

Files:

  • Create: app/lib/inside/routes/authenticated/members_management/page.dart (full CRUD list + add/edit/remove).
  • Move/refactor: T5's members/member_editor_sheet.dart editing here; extend with role grants (admin/helper/member chips, admin-only ⚐) + remove (wire the missing remove path).
  • Modify: more/page.dart → add an Account section with a Members entry → MembersManagementRoute. router.dart → add the route (under More). Regenerate router (scoped).
  • Test: app/test/flows/members_management_test.dart.

Interfaces — Consumes: HouseholdRepository.{watchMembers,addMember,updateMember,removeMember,setMemberHomePlace}.

  • TDD: open More → Account → Members; add/edit/remove a member; grant a role (admin-only gate); home-room + watch-only still editable. Run → fix → green.
  • Router regen + restore clobbered siblings; analyze clean; suite ≥ baseline; commit.

Phase 3: Household tab → read-only profile tiles + Family Goals

Files:

  • Modify: household/page.dart → replace the inline editable members list with read-only profile tiles (avatar/emoji, name, age/role, a wallet glance via walletOf, a 🎯 N goals chip) that route to MemberProfileRoute; add a Family Goals card (GoalsBloc, scope == family) with add/edit; keep existing house config.

  • Modify: members_bloc.dart → split read (tiles) from the management CRUD (now in Phase 2).

  • Test: app/test/flows/household_profiles_test.dart.

  • TDD: Household shows profile tiles (goal-count chip + wallet glance) + a Family Goals section; tapping a tile routes to the profile; family-goal add works. Green.

  • analyze clean; suite ≥ baseline; commit.

Phase 4: MemberProfile page

Files:

  • Create: app/lib/inside/routes/authenticated/member_profile/page.dart + a profile bloc (or reuse GoalsBloc + a member read).
  • Modify: router.dartMemberProfileRoute nested under the Household tab (param: memberId). Regenerate (scoped).
  • Test: app/test/flows/member_profile_test.dart.

Interfaces — Consumes: HouseholdRepository (member read), walletOf(memberId), GoalsRepository (member-scoped goals).

  • TDD: profile shows identity (name/emoji/age/traits/home-room/watch-only) + roles (read) + wallet glance (spend/save/give) + personal goals (scope==member, memberId==this) with add + the request affordance. Green.
  • Router regen + restore siblings; analyze clean; suite ≥ baseline; commit.

Phase 5: Goal request → approve flow

Files:

  • Modify: the MemberProfile + Household — surface requested goals (⚐ MemberProfile "Pending your OK" + Household badge); wire requestGoal (member proposes) → approveGoal({id, actingMemberId}) (parental approve) → active.

  • Modify: resolve the acting parental member (household first-parental until SP2).

  • Test: app/test/flows/goal_request_approve_test.dart + unit coverage for the parental-only approve gate.

  • TDD: a member requests a goal (→ requested, shows in the queue); a parental member approves (→ active, leaves the queue); a non-parental acting member is rejected. Green.

  • analyze clean; suite ≥ baseline; commit. Then final whole-branch review (flutter-reviewer) → finishing-a-development-branch.


Self-review notes

  • Coverage: the spec's 6 build items map to phases — GoalsRepository/watchGoals (P1), Members-management+roles (P2), Household tiles+Family Goals (P3), MemberProfile+wallet glance+personal goals (P4), request→approve (P5). ✅
  • Reuse: member editor + DS atoms + flow harness reused; net-new = members-management page, MemberProfile page, GoalsRepository/bloc.
  • Risks: router/codegen clobber (Global Constraint covers restore); the T5→management relocation must keep existing T5 tests green (adjust, don't delete); the acting-member resolution is a placeholder until SP2 auth.