Settings (Profile hub) — requirements
Epic. MVP-1 requirements breakdown for the settings hub (see the feature architecture). Each FR is sized to become one or a few user stories. The settings tiles are a navigation scaffold that routes members to secondary surfaces; they now live inside the Profile tab (the trailing IA slot that replaced the old More tab). Build cost is low; reachability value is high.
| Type | Functional |
| Layer (build approach) | Frontend — nav scaffold + auto_route |
| RICE | R 8 × I 0.5 × C 100% / E 1 = 4.0 · Tier MVP-1 |
| KPI (summary) | Settings reachability; pending-item badge accuracy |
| Traces to | feature settings · C4 components · prioritization |
| Depends on | Admin · Account |
Success criteria (definitive KPI)
Success = 100% of secondary surfaces reachable from Profile in ≤ 2 taps AND pending-item badge accuracy = 100% (badge count matches actual pending count) — both gates held from the first production build.
- Metric A (reachability): each tile in the Profile hub routes to its target in exactly one tap; combined with the bottom-nav tap to reach Profile, no secondary surface requires > 2 taps from anywhere in the app. Target: 100%. Any broken route is a P1 regression (build gate, not a trend metric).
- Metric B (badge accuracy): the pending-item badge on the Profile tab and on the Admin tile matches the live pending-approval / pending-invite count from the SDK at every render. Target: 100%. Staleness is a trust failure.
- Baseline: no install base yet — both are structural invariants enforced at
build and code-review time, not cohort thresholds. Instrument
more_openedandsettings_item_openedfrom day one to surface routing funnel drop-off.
Analytics — events to record
All events are INTERNAL BI — content-free, no child identity, never
marketing (see COPPA and the
consent-gated analytics substrate).
isParental is a coarse session attribute of the adult account holder; it
carries no child PII and is never used to target children.
| Event | When | Key properties | Feeds |
|---|---|---|---|
more_opened | Profile tab tapped (event key predates the More→Profile rename) | isParental (bool, coarse) | engagement denominator; nav-pattern analysis |
settings_item_opened | Any hub tile tapped | item (admin|appearance|accessibility|account|about|help|notifications), isParental (bool, coarse) | reachability audit; feature-adoption signal |
Both events ship with the surface — they are the minimum instrumentation needed to audit Metric A funnel drop-off. No child-linked properties present.
Scope
Settings are a navigation hub (not a functional surface) inside the Profile tab — the trailing IA slot that replaced the old More tab. It renders a list of secondary destinations: Admin (isParental-gated), Appearance, Accessibility, Account, About / legal, and Help & feedback; sign-out lives at the bottom of the Profile page (moved off the top header in the 2026-07-26 redesign). A pending-item badge on the Profile tab icon and on the Admin tile surfaces unactioned approvals and pending invites. Notification preferences are a stub in MVP-1; subscription / billing placement is an open decision.
Functional requirements
FR-SETTINGS-1 — Profile hub renders correct item list per persona
Priority: P1 · Status: 🔲 not built
Statement. As any member, I open Profile and see a list of secondary surfaces
appropriate to my role — Admin appears only when isParental = true.
Acceptance
- Given
isParental = trueWhen Profile renders Then the hub shows: Admin (badged), Appearance, Accessibility, Account, About, Help — in stable order. - Given
isParental = falseWhen Profile renders Then Admin is absent; all other tiles are present. - No tile flickers into or out of view on re-render or back-navigation.
FR-SETTINGS-2 — isParental gate on the Admin tile and route
Priority: P1 · Status: 🔲 not built (gate complements FR-ADMIN-1) Statement. As the app, I ensure a non-parental member cannot reach the Admin hub via the Profile tile or a direct deep-link route. Acceptance
- Given
isParental = falseWhen the Admin route is attempted (tile or deep-link) Then the tile is absent and the auto_route guard redirects to Profile; no Admin content is rendered. - Given
isParental = trueWhen the Admin tile is tapped Then the guard passes and the Admin hub loads. - The guard reads
isParentalfromMoreBlocstate — no direct SDK import in the guard file.
FR-SETTINGS-3 — Pending-item badge (approval + invite count)
Priority: P1 · Status: 🔲 not built Statement. As a parental member, I see a live badge on the Profile tab and on the Admin tile showing the total count of pending approvals and pending invites. Acceptance
- Given ≥ 1 pending chore-completion approval When Profile renders Then the badge displays the count and updates reactively as approvals are actioned.
- Given ≥ 1 pending invite (sent, not yet accepted) When Profile renders Then the count includes pending invites; the Admin tile badge mirrors the same sum.
- Given zero pending items When Profile renders Then no badge is shown (suppressed, not "0").
- Given
isParental = falseWhen Profile renders Then no badge is rendered; non-parental members have no approval queue. - Badge data is stream-fed from
MoreBloc → MoreRepository → SDK watchPendingBadgeCount(); no polling; zero stale renders guaranteed by the stream subscription lifecycle.
FR-SETTINGS-4 — Navigate to Appearance
Priority: P1 · Status: 🔲 not built Statement. As any member, I reach Appearance settings from Profile in one tap. Acceptance
- Given I am on Profile When I tap Appearance Then I land on the Appearance page and
settings_item_opened(item: 'appearance')fires. - Back-navigation returns to Profile without re-fetching the badge count from scratch.
FR-SETTINGS-5 — Navigate to Accessibility prefs
Priority: P1 · Status: 🔲 not built Statement. As any member, I reach Accessibility preferences from Profile in one tap. Acceptance
- Given I am on Profile When I tap Accessibility Then I land on the Accessibility prefs page and
settings_item_opened(item: 'accessibility')fires. - The Accessibility tile is always visible and never role-gated; preferences are per-member, not household-scoped.
FR-SETTINGS-6 — Navigate to Account; sign-out at Profile-page bottom
Priority: P1 · Status: 🔲 not built (sign-out delegates to FR-ACCOUNT-3) Statement. As an account holder, I reach Account settings from the Profile tab in one tap, and I find the sign-out action at the bottom of the Profile page. Acceptance
- Given I am on the Profile tab When I tap Account Then I land on the Account page (display name, email) and
settings_item_opened(item: 'account')fires. - Given I scroll to the bottom of the Profile page When I tap Sign out Then the FR-ACCOUNT-3 sign-out flow executes;
sign_outfires and the app navigates to the sign-in screen. - Sign out is not surfaced in the top header (retired in the 2026-07-26 redesign); it lives at the very bottom of the Profile page.
FR-SETTINGS-7 — About / legal
Priority: P2 · Status: 🔲 not built Statement. As any member, I can reach app version info, Terms of Service, and Privacy Policy from Profile. Acceptance
- Given I tap About When the page loads Then I see the app version string, a ToS link, and a Privacy Policy link;
settings_item_opened(item: 'about')fires. - ToS and Privacy Policy open via the system browser or an in-app web view (see Open decisions).
FR-SETTINGS-8 — Help & feedback stub
Priority: P2 · Status: 🔲 not built Statement. As any member, I can tap Help from Profile and reach a support contact surface; a full help center is deferred. Acceptance
- Given I tap Help When the page loads Then a support email link or web link is shown and
settings_item_opened(item: 'help')fires. - The stub must not dead-end; a tappable contact mechanism is required even if minimal.
Architecture considerations
- One data path —
MoreBloc → MoreRepository → client_sdkfacade; no page or widget importsdriftorsupabasedirectly. Appearance, Accessibility, and Account navigations are pure routing; no bloc data fetch is required beyond the persona check and badge stream. - auto_route nav scaffold — More is an auto_route stack; each destination is
a named route in the app router. The isParental gate is an
AutoRouteGuardthat readsisParentalfrom the active-session bloc. The guard fires on every Admin route attempt (tile or deep-link), not just on initial render. Widget- level tile omission is a UX guard; the route guard is the security layer — both are required. - Badge data source —
watchPendingBadgeCount()on the SDK aggregates pending chore-completion approvals (CompletionService) and pending invite records (MemberService) into a single integer stream.MoreBlocsubscribes on first render and cancels on dispose; no polling, no manual refresh needed. - Privacy —
isParentalis a session attribute of the adult account holder; it is never derived from child data. Both analytics events are INTERNAL BI only; no child PII crosses the analytics seam.
Design work (ahead of build)
- Profile hub list IA — final item list, display order, grouping (flat list vs. labelled sections), and icon / label pairing for each row; document which items are always-visible vs. persona-gated.
- Badge treatment — numeric badge on the Profile bottom-nav tab icon and on the Admin tile: max-display cap (e.g. "9+"), colour, and zero-state (hidden vs. persistent dot).
- Admin tile visual distinction — the Admin row should read as configure, not act; consider a section divider, gear icon, or subtle background to separate it from personal-preference items (Appearance, Accessibility, Account).
- Sign-out placement — resolved (2026-07-26): a footer / destructive row at the bottom of the Profile page, removed from the top header entirely.
Decisions (resolved for MVP-1)
Resolved — see the MVP-1 decisions log for the canonical record, rationale, and status legend (✅ decided · ⚖️ counsel confirms · 🔜 MVP-1.x).
- D-SETTINGS-1 — Sign-out placement. ✅ Bottom of the Profile page (2026-07-26 redesign; superseded the earlier "Account sub-page" ruling) — removed from the top header, avoids accidental taps.
- D-SETTINGS-2 — Subscription tile. ✅ Owner-only "Subscription" row in Profile that deep-links to Admin → Billing (discoverable shortcut; Admin remains the config home). Reconciles with D-ADMIN-1.
- D-SETTINGS-3 — About / legal link target. ✅ In-app web view for ToS / Privacy (contained; pins a versioned URL tied to consent records); system-browser fallback if the web view is unavailable.
- D-SETTINGS-4 — Notifications tile. ✅ Ship the tile to a real (minimal) notifications-preferences route — local notifications are in MVP-1, so the tile is functional (quiet-hours + lead-time prefs live there), not a stub.
Out of scope (MVP-1)
- Notification preferences — tile stubs only in MVP-1; functional surface deferred until the notifications feature track is built.
- Subscription / billing entry on Profile — deferred pending FR-ADMIN-11 billing SDK readiness and placement open decision above.
- Search within settings — the item list is short enough in MVP-1 to browse; search is deferred.
- Full in-app help center / support chat — FR-SETTINGS-8 is a contact-link stub; a full help center is a later track.
- Shared-device PIN-gated profile picker — deferred (see profile-switching feature). The active-member display-lens switcher itself shipped on the Profile page in the 2026-07-26 redesign.