Skip to main content

Catalog — requirements

Epic. MVP-1 requirements breakdown for the Catalog browse surface (see the feature architecture). Each FR is sized to become one or a few user stories. The SDK adapter layer is already built (SupabaseCatalogAdapter) — this epic covers the bloc, page, and flow-test layer.

TypeFunctional
Layer (build approach)Frontend — design_system atoms + app bloc/page + flow-test
RICER 9 × I 2 × C 80% / E 2.5 = 5.8 · Tier MVP-1
KPI (summary)Browse→action conversion
Traces tofeature catalog · C4 components
Depends onMoney (redeem) · Admin (CRUD) · Today

Success criteria (definitive KPI)

Success = ≥ 40% of Catalog sessions end in an action (claim, redeem, or open editor) within the same session, sustained across weeks 2–4 after activation.

  • Metric: sessions with ≥ 1 chore_claimed, reward_redeemed, or catalog_editor_opened / total catalog_viewed sessions.
  • Target: ≥ 40% conversion rate.
  • Window: sustained across weeks 2–4 post-activation (activation = household's first approved chore completion).
  • Why this bar: the Catalog's job is to move a member toward an act; a browse surface that doesn't convert is furniture. 40% reflects that some sessions are deliberate "shopping" that may span multiple visits.
  • Guardrail (catalog depth): if conversion rises but median catalog items per active household stays ≤ 2, high conversion is forced selection (shallow catalog), not genuine engagement. Require median ≥ 4 catalog items per active household before treating conversion as healthy.
  • Baseline: no install base yet — treat 40% / ≥ 4 items as the launch hypothesis; re-baseline from first-cohort wk-2 data.

Analytics — events to record

All events are internal BI — event-type + coarse properties, no child identity or PII, content-free. Never routed to marketing; never used to target minors. Emitted through the consent-gated analytics substrate.

EventWhenKey propertiesPriorityFeeds
catalog_viewedCatalog screen openedtab (chores|bounties|activities|rewards), itemCount (coarse bucket)P1-with-surfaceKPI denominator
chore_claimedBounty claimed from CatalogchoreKind (bounty), memberRef (opaque)P1-with-surfaceprimary KPI numerator
reward_redeemedReward redeemedtokenCost (coarse bucket), memberRef (opaque)P1-with-surfaceprimary KPI numerator
catalog_editor_openedChore editor entry point tappedsurface (catalog), choreKind (chore|bounty|activity|reward)P1-with-surfaceprimary KPI numerator · admin funnel

All four events ship with the surface — the KPI is only measurable once both the denominator (catalog_viewed) and the three numerator events are instrumented.

Scope

Catalog is the browse IA quadrant (act / glance / browse / people). It shows everything available to household members: assigned chores, claimable bounties, unlockable activities, and redeemable rewards. Members browse and act (claim, redeem); Admin CRUD lives in the Admin hub. The chore editor route already exists — the Catalog surfaces its entry point for parental members only. MVP-1 delivers the tabbed browse IA, bounty claiming, reward redemption, activity lock visibility, empty states, and the editor entry point.

Functional requirements

FR-CATALOG-1 — Tabbed browse IA (chores, bounties, activities, rewards)

Priority: P1 · Status: 🔨 to build (SDK-ready) Statement. As a member, I open the Catalog and see four tabs — Chores, Bounties, Activities, and Rewards — so I can browse what is available to me in one place. Acceptance

  • Given a household with items in each category When I open Catalog Then four tabs render and each shows household-scoped items.
  • Given I switch tabs Then catalog_viewed fires with the correct tab value.
  • Given a tab has no eligible items Then the empty state renders (FR-CATALOG-7), never a blank screen.

FR-CATALOG-2 — Eligibility filtering per member

Priority: P1 · Status: 🔨 to build Statement. As a member, I only see chores and bounties I am eligible to act on — ineligible items are hidden by default. Acceptance

  • Given a chore with minAge above my age When Catalog loads Then it does not appear in my Chores tab.
  • Given a bounty with no assignedMemberIds restriction When any age-eligible member opens Catalog Then it appears for them.
  • Eligibility resolution is delegated to the SDK service layer; the bloc passes memberId; no eligibility logic in the page widget.

FR-CATALOG-3 — Claim a bounty

Priority: P1 · Status: 🔨 to build (BountyRow widget reusable from Today surface) Statement. As a member, I tap "Claim" on a bounty and it enters my Today list for the day, so I can act on it without an admin assigning it to me. Acceptance

  • Given a claimable bounty When I tap Claim Then it appears in my Today list and the button reflects a claimed state.
  • Given a bounty's maxPerDay cap is reached Then Claim is disabled with a clear affordance.
  • Given claim succeeds Then chore_claimed fires with choreKind = bounty and an opaque memberRef.
  • The claim call goes through CatalogBloc → Repository → client_sdk facade; no direct adapter call in the page.

FR-CATALOG-4 — Redeem a reward

Priority: P1 · Status: 🔨 to build Statement. As a member, I tap "Redeem" on a reward and the token cost is debited from my balance, so I can spend earned tokens on household rewards. Acceptance

  • Given my balance ≥ reward cost When I tap Redeem and confirm Then tokens are debited via EconomyService and the reward shows a confirmed state.
  • Given my balance < reward cost Then Redeem is disabled with a balance indicator.
  • Given redemption succeeds Then reward_redeemed fires with coarse-bucketed tokenCost and opaque memberRef.
  • A single tap-and-confirm pattern prevents accidental redemption; no undo in MVP-1 (append-only ledger).

FR-CATALOG-5 — Chore editor entry point (parental members only)

Priority: P2 · Status: 🔨 to build (editor route already exists from P1/P2 build) Statement. As a parental member, I tap an edit affordance on a catalog item and the existing chore editor opens pre-populated, so I can adjust items without leaving the browse context. Acceptance

  • Given I am a parental member When I tap the edit affordance on any catalog item Then the existing chore editor route opens pre-populated with that item.
  • Given I am a non-parental member Then no edit affordance is visible; items are read-only.
  • Given the editor opens Then catalog_editor_opened fires with surface = catalog and the item's choreKind.

FR-CATALOG-6 — Activity lock state visible

Priority: P2 · Status: 🔨 to build Statement. As a member, locked activities show a lock indicator and a one-line unlock condition so I understand what is required to access them. Acceptance

  • Given an activity with an unmet ActivityGate When I view the Activities tab Then the item shows a lock icon and a coarse gate label.
  • Given the gate is met When the tab refreshes Then the lock clears without a restart.
  • Tapping a locked activity renders an informational sheet or toast; it does not crash or navigate.

FR-CATALOG-7 — Empty states per tab

Priority: P2 · Status: 🔨 to build (DS empty-state atom available) Statement. As a member, an empty tab shows a purposeful message rather than a blank screen so I understand what the section is for. Acceptance

  • Given a tab with no eligible items for me When it renders Then an empty state with copy reflecting "nothing for you yet" displays.
  • Given a parental member views an empty tab Then the empty state includes a CTA into the Admin catalog editor.
  • DS empty-state atom is reused; no new illustration asset required for MVP-1.

Architecture considerations

  • One data pathCatalogBloc → Repository → client_sdk facade; no direct drift/supabase imports in page or bloc. SupabaseCatalogAdapter is already built.
  • Read via repository → facadeCatalogService mediates all reads; the bloc calls the repository, never the adapter.
  • Household-scoped RLS — all catalog tables are RLS-gated by household_id; no cross-household leakage at Postgres or SDK level.
  • Redeem flows through EconomyService — reward redemption is a token debit; the bloc must call the economy path (via facade) alongside the catalog path; both calls are SDK-mediated, not direct.
  • Claim re-uses Today's claim pathchore_claimed from Catalog is the same SDK service operation as from Today; the service enforces maxPerDay server-side.
  • Chore editor route already exists — FR-CATALOG-5 wires an entry point only; the editor page from P1/P2 Admin work is not re-built here. isParental guard is the existing authz check.
  • Live updates — a watch* stream on catalog state keeps claim/redeem affordances current; a stale Claim button on a fully-claimed bounty is a data-integrity issue, not just UX.

Design work (ahead of build)

  • Catalog browse IA — tab layout, card anatomy per kind (chore / bounty / activity / reward), hierarchy of name / token value / action CTA. No design delivered yet.
  • Reward redeem flow — confirmation affordance (sheet or inline confirm), success feedback (token debit animation; ties into Money DS work), insufficient-balance error state.
  • Empty states — copy per tab for "no items exist" (parental CTA) vs. "nothing eligible for you" (member). DS atom reuse; no new illustration asset for MVP-1.
  • Activity lock treatment — lock icon placement, gate condition label copy ("earn X more" vs. "complete Y first"). Copy decision needed before build.

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-CATALOG-1 — Eligibility display. ✅ Show ineligible items grayed-out with a short rationale ("unlocks at…" / "for ages…"), not hidden — transparency + aspiration aid motivation. Full household catalog visible.
  • D-CATALOG-2 — Bounty claim mechanics.First-come-first-served (current SDK assumption) for MVP-1; admin-assigns-after-request and the claim-request flow are out of MVP-1 scope.
  • D-CATALOG-3 — Post-claim state. ✅ A fully-claimed bounty shows "claimed today" (visible, disabled) rather than disappearing; remaining daily slots shown when more than one.
  • D-CATALOG-4 — Redemption reversal.No undo (append-only ledger). A correction is a new compensating entry by an admin, never a mutation.

Out of scope (MVP-1)

  • Template library — import common chores from a household chore store; deferred.
  • Member-facing search / filter — flat scrollable list for MVP-1; search is a post-MVP addition.
  • Bounty claim notifications — push alert when a bounty is claimed by another member.
  • Activity gating CRUD — gate management lives in Admin; Catalog surfaces lock state read-only.
  • Admin CRUD inline in catalog — all mutation paths are owned by the Admin hub.
  • Photo-gated bounty claim — photo capture at claim time deferred to the chore-photo-submissions feature.