All work

Salt Mammal

Addiction support, no shame

Not a sober-day counter. A tool for surviving the five to fifteen minutes while a craving peaks, reachable in under two taps.

The problem

Recovery apps mostly sell measurement, where the counter is the product and a relapse means a reset and a dose of shame — or they sell paywalled education. None of them sell surviving the next fifteen minutes, which is the moment that actually decides the outcome.

What it does

One tap opens Craving Mode: a full-screen breathing orb whose haptic cadence lets you shut your eyes, an in-flow check-in on whether the wave is passing, then a drawer offering a delay timer, a grounding exercise, or a one-tap message to a support contact wired up during onboarding. A slip routes into a debrief rather than resetting a streak.

How it's built

  1. No login wall, but real billing and cross-device sync

    Anonymous users are keyed by device, which forces the merge into a real account to have a defined answer for every unique constraint in the schema rather than a generic reparent. It runs as one transaction, blind-reparenting foreign-key-only models and applying an explicit account-wins policy per constraint.

  2. Identity headers stripped on every inbound request

    The edge proxy deletes the identity and device headers from every request — including server actions, which arrive on page routes rather than API routes — before re-injecting an identity decoded from a signed token. Tokens are device-bound with a long expiry, so the session is also re-read and revoked tokens rejected.

  3. A breath engine that is the same on both platforms, and testable

    One inhale-hold-exhale cycle drives web and mobile. On mobile the animation sequence is re-armed each cycle rather than looped infinitely, so phase callbacks and escalating haptics stay in lockstep; Reduce Motion degrades to opacity with the haptics still carrying the cadence. The timings are hoisted into a shared module so CI can assert them.

  4. Duty of care expressed as fail-closed defaults

    The research step for any health content throws rather than letting a model fall back on memory, and refuses to proceed below two usable primary sources. The image relevance judge returns false when the evaluation call itself fails, on the reasoning that a missing image is always the safe outcome on a recovery post.

The hard part

Identity, mostly: supporting real payments and cross-device sync while never forcing a login means the anonymous-to-account merge has to be exhaustive rather than best-effort, with a stated policy for every uniqueness rule in the schema. The rest is deciding, repeatedly, which direction each failure should fall in — and for this product almost every one falls closed, because on a recovery app the cost of showing something wrong is not symmetrical with the cost of showing nothing.

Stack

  • Next.js
  • React Native
  • Expo
  • Anthropic
  • OpenAI
  • Skia
  • RevenueCat

Built, shipped and maintained by me. Try Salt Mammal, or see the rest of the work.