Skip to content

Onset Build Plan: Stack Value, Experiments, Paywall, Clinic

Status: Gates 1–5 product DoD complete. Gate 5 business DoD open (pitches + pilot).
Source: PRODUCT_REVIEW + money-saved calculator (Instacart-style).
Rule: Build only the current gate. Experiments stay Release-off until counsel clears copy.


North star

Onset stops selling "nicer reminders" and sells two unavoidable answers:

  1. Consumer: "Am I wasting the money I already spend on my stack?"
  2. Clinic: "Are my patients taking what I prescribed?"

Gamification = dollars and streaks tied to those answers. No XP, levels, or leaderboards.


Locked product decisions

Decision Choice
Money metric language "Stack cost", "Taken", "Missed", "Stack value recovered". Never "health ROI" or outcome claims.
Free vs Pro Soft free stays: 10 items, 7-day trends, Stack Cost basics. 3 free bottle scans/month via BottleScanUsageTracker + FeatureGate. Pro = unlimited + Experiments + 30-day + inventory alerts + Watch/widgets.
Docs sync .cursorrules and README match soft free path (Gate 2).
Experiments copy Counsel review before App Store release. Ship behind FeatureFlags until cleared.
Freeze list No new work on Protocol Lab sims, cycle simulator, public marketplace, fitness, calendar export, performance prep. Keep code; stop expanding.
Clinic Activate existing $49/mo SaaS. Patient free via clinic. Patient Pro = Intelligence Bundle.

Gates (earned, not calendar)

Each gate unlocks exactly one next thing on its Definition of Done.

Gate 1 : Stack Value (money calculator) : DONE

Goal: Every priced stack shows monthly cost, taken, missed, and all-time recovered.

DoD: - [x] bottlePrice + related fields on UserProtocolItem (lightweight migration) - [x] StackCostEngine unit-tested for daily/monthly/taken/missed math - [x] Price entry in Protocol editor + Add prices sheet + scan review - [x] Today card: Stack Cost (empty state asks for prices) - [x] Savings screen (More): month + all-time + year projection - [x] Copy audit: no health claims, no em-dashes - [x] Analytics: stackPriceAdded, stackCostCardViewed, savingsScreenViewed

Out of scope: weekly push, share cards, paywall rewrite, experiments.

Gate 2 : Paywall honesty + aha path

DoD: - [x] Scanner uses FeatureGate 3 free scans/month via BottleScanUsageTracker - [x] Stack Cost visible on OnsetExplicitPaywall when priced - [x] .cursorrules + README agree on free vs Pro - [x] Soft free path chosen in writing (no trial for now): Continue with free access + 3 scans/month + Stack Cost. Pro unlocks unlimited scans / 30-day / inventory alerts / Watch / sync. - [x] Ops note: RevenueCat → Meta Ads: enable in RevenueCat dashboard (Integrations → Meta) and map to Meta app ID before paid UA. Not a code change.

  • [x] Paywall copy: stack monthly cost + Pro annual ~$4/mo framing

Gate 3 : Experiments v1 (counsel-gated)

Entry: Gate 2 done + written counsel OK on result-card copy (or ship DEBUG/Staging only).

DoD: - [x] StackExperiment model: itemId, metric, baselineStart/End, activeStart, durationDays, status - [x] Metrics v1: Daily Journal energy + sleep quality (2 max; Health sleep duration deferred) - [x] Result card: before avg, during avg, adherence %, dates. No "improved" / "worked" - [x] Pro-gated. Free sees locked teaser on Stack Value when flag is on - [x] Flag: stackExperiments (ON in Debug/Staging, OFF in Release until counsel)

Gate 4 : Retention loops on real value

DoD: - [x] Sunday local notification: Weekly Stack Report (cost + taken + missed + streak) - [x] One streak freeze per week - [x] Shareable monthly receipt card (extend ProtocolShareCard pattern via StackValueShareCard) - [x] Milestone: "Experiment window complete" local notification (only if Gate 3 flag ON)

Gate 5 : Clinic activation (mostly sales + thin product)

DoD (product): - [x] Clinic-facing adherence export / summary that includes % doses taken (dose-weighted fields on shared_adherence upsert) - [x] Drop-off signal: patient silent ≥7 days → is_silent + days_since_last_completion on share payload (clinic web surfaces badge) - [x] Pitch kit: feed/06 + one-pager in ~/Downloads/onset-marketing-kit/pitch/ (pointer in docs/clinic/PITCH_KIT.md)

DoD (business, not code): 10 clinics pitched, 1 pilot scheduled.


Gate 1 data model

UserProtocolItem (new optional fields)

/// Bottle purchase price in the user's currency (USD default). Nil = unpriced.
var bottlePrice: Double?
/// ISO 4217, default "USD"
var bottlePriceCurrency: String?
/// When the user last set/confirmed the price
var bottlePriceUpdatedAt: Date?

Reuse existing: servingsPerContainer, currentStock, frequency, lastRestocked.

UserPreferences (optional, Gate 1b if time)

/// 0...1 estimated miss rate before Onset. Nil = don't show "recovered vs before" line.
var preOnsetMissRate: Double?

StackCostEngine (pure functions, no SwiftUI)

Inputs: active items with prices, completions in range, calendar month.

Output Formula
costPerDose(item) bottlePrice / servingsPerContainer (require both > 0)
dailyCost(item) costPerDose * servingsPerDay(frequency)
monthlyStackCost sum of dailyCost × daysInMonth (or 30.44 avg for projection)
takenValue(range) sum over completions (non-skipped) of costPerDose
scheduledValue(range) sum over active days of dailyCost for items that were active
missedValue(range) max(0, scheduledValue - takenValue)
recoveredAllTime sum of takenValue since first priced completion
yearProjection monthlyStackCost × 12

Empty / partial rules: - If zero items priced: show empty state, do not invent defaults on Today. - Optional later: category defaults in editor only as placeholders user must confirm. - Skipped completions count as neither taken nor (for v1) missed; missed = scheduled and not completed and not skipped by end of day. For v1 simplicity: missed = scheduledValue − takenValue for past days only (today counts taken only).


Gate 1 UI copy (paste-ready)

Today card : empty

STACK COST
Add bottle prices to see what your stack costs each month.
[Add prices]

Today card : populated

STACK COST
$143 this month
Taken $112 · Missed $31
Cost per day $4.76
[See savings]

Savings screen : header

Your stack value
What you spend, what you take, what you miss.

Savings : month section

THIS MONTH
Stack cost          $143.00
Taken               $112.20
Missed              $30.80
Adherence           78%

Savings : all time

ALL TIME
Stack value taken   $840.00
That's the value of every dose you checked off in Onset.

Savings : year line

At your current stack: about $1,716 per year.
General wellness organizer. Dollar amounts are based on prices you enter and doses you log. Not financial or medical advice.

Protocol / Inventory price field

Bottle price
What you paid for this bottle (optional)
$ [ 24.99 ]
120 servings · about $0.21 per dose

Paywall line (Gate 2)

Your stack is about $143/month.
Onset Pro is $4/month on the annual plan.

Weekly report push (Gate 4)

Title: Your week in Onset
Body: Taken $38 · Missed $4 · 6-day streak. Open your Stack Value.

Share card (Gate 4)

MY STACK VALUE
$112 taken this month
Built with Onset · theonset.app

Taboo on these surfaces

No: optimize, improve, boost, ROI on health, "saved your body", treat, cure, you should.


Experiments result card copy (Gate 3, counsel before Release)

EXPERIMENT RESULT
Magnesium Glycinate · 30 days

Metric: Sleep (Apple Health)
Before (14 days): average 6h 52m
During (30 days): average 7h 21m
Adherence during: 93%

Your logged numbers side by side. Onset does not interpret results or give medical advice.

Never: "improved", "worked", "effective", "increased your sleep by".


Analytics events (add to ProductAnalytics)

Event When
stackPriceAdded User saves a bottle price
stackCostCardViewed Today card appears with priced data
savingsScreenViewed Savings screen open
stackCostEmptyCtaTapped Empty-state Add prices
experimentStarted Gate 3
experimentCompleted Gate 3
experimentScreenViewed Gate 3
weeklyStackReportOpened Gate 4
streakFreezeUsed Gate 4
stackValueShared Gate 4
clinicAdherenceShared Gate 5

File touch list (Gate 1)

Area Files
Model Onset/Core/Models/UserProtocolItem.swift
Engine New Onset/Core/Engine/StackCostEngine.swift
Tests New OnsetTests/StackCostEngineTests.swift
Editor ProtocolItemEditor.swift, SupplementDetailView.swift inventory section
Inventory InventoryView.swift
Today TodayView.swift or small StackCostCard.swift
Savings New Features/Savings/SavingsView.swift
Nav MoreView.swift row
Analytics ProductAnalytics.swift

Sell track (parallel, not blocked by Gate 1 code)

Week Action
Now Pitch 10 clinics with ~/Downloads/onset-marketing-kit/instagram/feed/06-clinic-protocol.png
Gate 2 Insert Affiliate: 10 creators, Reel scripts from ADS_PLAYBOOK
Gate 3+ $30/day Meta test only after Stack Cost is in a TestFlight users can feel

Success metrics

Metric Target
% new users who price ≥1 item in 48h ≥40%
Paywall→purchase after Gate 2 ≥4%
D30 retention: Experiment starters vs not ≥2×
Paying clinic pilots 1 in 45 days

Implementation order inside Gate 1

  1. Schema fields + StackCostEngine + tests
  2. Price field in editor / inventory
  3. Today card
  4. Savings screen + More entry
  5. Analytics + copy pass

Start at step 1 next.