Skip to main content

Notifications — requirements

Epic. MVP-1 requirements breakdown for the Notifications local tier (see the feature architecture). Covers on-device scheduling only — permission request, per-member reminder preferences, chore-due reminders, and parent approval prompts. Each FR is sized to become one or a few user stories. Push (FCM/APNs) and milestone notifications are MVP-2/paid.

TypeFunctional
Layer (build approach)Cross — local sched (free) + FCM/APNs (paid)
RICER 8 × I 2 × C 80% / E 3 = 4.3 · Tier MVP-1 (local)
KPI (summary)Notification opt-in %; re-engagement taps → WAEH
Traces tofeature notifications · C4 containers
Depends onAnalytics · Account & profile management

Success criteria (definitive KPI)

Success = ≥ 60% of activated households grant notification permission AND re-engagement: ≥ 40% of reminder_tapped events are followed by a chore_completed within the same calendar day, sustained across weeks 2–4 post-activation.

  • Metric A (opt-in rate): notification_optin_set(granted: true) / total activated households. Target: ≥ 60%. Measured at the household level (the account holder's device; per-member prefs are downstream of the grant). A rate below 50% in the first cohort signals a permission-UX problem, not a product-fit problem.
  • Metric B (re-engagement rate): chore_completed events preceded by a reminder_tapped on the same calendar day / total reminder_tapped events. Target: ≥ 40%. Window: weeks 2–4 post-activation (activation = first approved completion); weeks 2–4 exclude the novelty effect of week 1.
  • Guardrail (frequency erosion): if reminder_tapped volume drops > 30% week-over-week without a corresponding opt-out, investigate scheduling drift or quiet-hours misconfiguration — a health signal, not a tunable target.
  • Baseline: no install base yet — treat 60% / 40% as the launch hypothesis; re-baseline from the first cohort's week-2 data. 60% opt-in is informed by ADHD/neurodiversity app benchmarks where reminders are a primary stated need; 40% same-day completion tap-through is a conservative floor given functional-only content.

Analytics — events to record

All events are INTERNAL BI — content-free, no child identity, no chore content, never marketing (see COPPA and the three-bucket model). Never emit a promotional or marketing event triggered by a child's action.

EventWhenKey propertiesFeeds
notification_optin_setPlatform permission dialog resolvesgranted (bool), platform (ios|android)KPI-A numerator; per-platform opt-in health
reminder_scheduledA chore-due reminder is written to the local schedulerscheduledCount (coarse: 1|2-5|6+), hasQuietHours (bool)Scheduling health; drift audit
reminder_tappedUser taps a local notification; app foregroundsnotificationType (chore_due|approval_request)KPI-B denominator; re-engagement funnel
approval_prompt_tappedAccount holder taps an approval-request notification(no additional props — chore identity must not be logged)Approval-funnel latency signal

reminder_tapped is the KPI-B denominator; the numerator is a chore_completed event (owned by Today) on the same calendar day. The cross-KPI join is BI-side (no person identity in either event). Both events must be live before KPI-B is measurable — instrument together, not in sequence.

Scope

Notifications MVP-1 is the on-device local tier: the permission grant flow, per-member reminder on/off and quiet-hours preferences, chore-due reminders scheduled from local device state, and approval-prompt notifications delivered to the account holder when a child submits a chore. Notifications are functional only — they carry no chore content, no promotional copy, and are never delivered to a child as marketing. Reminders sent to a child's device are functional task prompts only (chore due soon) and require the account holder's prior notification grant.

Functional requirements

FR-NOTIFY-1 — Notification permission request

Priority: P1 · Status: 🔨 to build Statement. As the account holder, I am prompted to grant notification permission at an appropriate moment in onboarding so reminders can be delivered on this device. Acceptance

  • Given a fresh install with no prior permission decision When the in-app pre-prompt appears Then it explains the value (functional reminders, never spam, can be turned off anytime) before the platform dialog is shown; notification_optin_set fires on resolution regardless of outcome.
  • Given permission is denied When I navigate to Settings → Notifications Then a clear nudge links to platform settings; the in-app dialog is never re-shown without me initiating.
  • Given permission is granted Then the scheduler activates; Given it is denied or subsequently revoked Then no local notifications are scheduled and the preference UI reflects the disabled state.

FR-NOTIFY-2 — Per-member reminder preferences

Priority: P1 · Status: 🔨 to build Statement. As the account holder, I can enable or disable chore-due reminders per household member and set quiet hours so notifications respect each member's schedule. Acceptance

  • Given a household member When I open their notification preferences Then I can toggle reminders on/off and set a quiet-hours window (start time, end time); reminder_scheduled reflects hasQuietHours: true when a window is set.
  • Given quiet hours are configured When a reminder would fire inside the window Then it is suppressed without rescheduling.
  • Preferences persist locally across restarts and sync to Supabase when online so they survive reinstalls on the same account.

FR-NOTIFY-3 — Chore-due reminder scheduling (local, on-device)

Priority: P1 · Status: 🔨 to build Statement. As a household member, I receive a local on-device reminder when a chore assigned to me is due soon so I am prompted to act before missing the window. Acceptance

  • Given a chore with a due time When reminder scheduling runs Then a local notification fires ≈ 30 minutes before the due time (configurable default); reminder_scheduled emits.
  • Given the chore is completed or removed before the notification fires Then the scheduled notification is cancelled.
  • Given the device is offline When the reminder fires Then it still delivers (local scheduling requires no network); tapping it opens the Today surface.
  • Notification copy is content-minimal (e.g. "You have a chore due soon") — no chore name, no token amount, no member name in the payload.

FR-NOTIFY-4 — Parent approval-request prompt

Priority: P1 · Status: 🔨 to build Statement. As the account holder (parent), I receive a local notification when a child submits a chore for approval so I can review it promptly. Acceptance

  • Given a chore submission enters submitted state When the scheduler evaluates it Then an approval-request notification is delivered to the account holder's device within 60 seconds; approval_prompt_tapped fires when tapped.
  • Given the submission is already approved or rejected before the notification is tapped Then tapping it routes to the approval queue (empty/acted-state) without error.
  • Notification copy is content-minimal (e.g. "A chore is waiting for your review") — no child name, no chore name in the payload.

FR-NOTIFY-5 — Notification tap routes to the correct surface

Priority: P2 · Status: 🔨 to build Statement. As a user, tapping a notification brings me to the relevant in-app surface so I can act without searching. Acceptance

  • Given a chore_due notification When tapped Then the app opens to the Today surface.
  • Given an approval_request notification When tapped Then the app opens to the approval queue.
  • Given the app is backgrounded or terminated When the notification is tapped Then the app cold-starts to the correct route via the notification type tag only — no chore id or member id in the payload; routing is type-only.

Architecture considerations

  • One data pathNotificationsBloc → NotificationsRepository → client_sdk facade → NotificationsService → LocalNotificationsAdapter. No bloc or page imports flutter_local_notifications directly; the adapter is the sole I/O boundary.
  • Scheduler in the SDK serviceNotificationsService owns scheduling logic (timing, quiet-hours evaluation, cancellation on completion); LocalNotificationsAdapter wraps flutter_local_notifications (or equivalent) and is the only surface that touches the platform plugin.
  • Content-free payloads — notification payloads carry only a type tag (chore_due / approval_request) and a route hint; no chore id, member id, name, or token amount enters the notification channel. This satisfies the minor-safe pre-emit filter structurally — there is nothing to strip at runtime.
  • Offline-first — local reminders are scheduled on-device and fire without a network connection. The scheduler hydrates from the Drift write-through cache (the same offline store powering Today), so reminders survive airplane mode.
  • Cancellation consistency — when a chore_completed or completion_approved event lands (via the Today offline queue or a live sync), NotificationsService.cancelForChore is called; the adapter cancels any pending local notification to prevent stale reminders.
  • Push deferred — no FCM/APNs token is registered in MVP-1. The NotificationsAdapter interface is designed to be swapped for a PushNotificationsAdapter in MVP-2 without changing the service or bloc.
  • Household-scoped RLS — notification preferences are stored in a notification_preferences table scoped to the household's RLS policy; no cross-household reads are possible.

Design work (ahead of build)

  • Pre-prompt / permission UX — the in-app pre-prompt before the platform dialog; must state clearly "functional reminders only, never promotional, you can turn off at any time." Required on both iOS (always) and Android 13+ (POST_NOTIFICATIONS explicit grant).
  • Notification preference surface — a per-member prefs card in Settings → Notifications: toggle, quiet-hours time-range picker, and a visible "notifications off" state (when permission is denied) with a link to platform settings.
  • Notification copy — functional, content-minimal strings for chore_due and approval_request; must omit child name, chore name, and token amount. Copy should be warm but brief (≤ 8 words per notification).
  • Approval-prompt acted state — the approval-queue view when the submission was already reviewed before the parent taps the notification; must not show a confusing blank screen.

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-NOTIF-1 — Chore-due lead time.Default 20 min (ADHD-leaning) + a per-household preference (15 / 20 / 30); A/B post-launch.
  • D-NOTIF-2 — Approval-prompt batching.One summary notification with a count ("3 chores need approval") → taps into the approval queue, which preserves per-item context.
  • D-NOTIF-3 — Kid-mode suppression. ✅ Chore-due reminders fire in kid-mode (they help the child); approval prompts do not (parent-only). Decided now so the scheduler is correct when kid-mode (MVP-2) lands.
  • D-NOTIF-4 — Quiet-hours default. ✅ Ship a sensible default window 21:00–07:00, user-editable / disable — avoids night-time noise out of the box.

Out of scope (MVP-1)

  • Push notifications (FCM/APNs) — cross-device delivery via a push provider → MVP-2/paid; the NotificationsAdapter interface is designed to support this without service changes.
  • Milestone notifications (goal reached, kudos received) → MVP-2; the goal-loop KPI is tracked via the Member Profile epic, not the local scheduler.
  • Promotional / marketing notifications — never to children under any tier; parent-only lifecycle communications (if any) are a marketing-bucket concern routed through Email digests, not the local notification tier.
  • Teen (13–17) consent nuances for push — deferred alongside push; the local tier's permission is a standard platform grant tied to the adult account holder.
  • Daily or weekly digest notifications — a summary of household activity is a separate product decision; not MVP-1.