← Work

Case study · In development — live preview

ZzzStake

Put real money on your own sleep goal — miss it, and you forfeit the stake.

ZzzStake screenshot

ZzzStake applies the commitment-device mechanic behind stickK and Beeminder to sleep: put money on a sleep goal you set yourself, and missing it costs you the stake.

The problem

Sleep trackers produce a score every morning and no consequence for ignoring it. Loss aversion is one of the most reliable levers in behavioral economics, and stickK and Beeminder already use it for habits. ZzzStake points the same mechanic at sleep.

How it works

You pick a goal — a sleep score, a consistent wake-up time, falling asleep by a set time, or hours slept — plus a window of nights, a stake, and how many emergency skips you want. Sleep data comes in from Apple Health, and a daily job settles every stake whose window has closed.

Meet the goal on every night except your skips and you keep your stake; miss it and the stake is forfeited. There's deliberately no upside beyond getting your own money back.

Engineering decisions

  1. No real money until the gates close

    The app runs as a live preview: stakes, scores, and outcomes are tracked end to end, and every forfeit is written to a ledger with no payment attached. Payment processing stays off until payment-provider approval and legal review are complete, because a bug in resolution would otherwise take someone's money.

  2. Its own score, not Apple's

    Apple's Sleep Score isn't available through HealthKit, so ZzzStake computes its own from raw sleep stages, weighting duration, consistency, and interruptions 50/30/20.

  3. The published rules can't drift from the engine

    The public FAQ's worked examples are computed by the real scoring functions, and tests pin the wording — if the formula changes, the explanation changes with it or the build fails.

  4. Settles on outcomes, per goal type

    Each goal type has its own pass/fail predicate, and the type system refuses to compile if a goal type is added without one.

  5. Client-agnostic ingestion

    Sleep data arrives through one authenticated endpoint that accepts raw samples from a health-export app, alongside a bulk importer for Apple Health exports. Real data flows without waiting on a native iOS build.

  6. Dates are the hardest part

    A night is dated by the morning you woke up, and all calendar math goes through one local-date module. An earlier UTC shortcut shifted evening stakes a night forward and closed cancellation windows hours early. The test suite is pinned to UTC with a guard test, so timezone bugs can't hide on a dev machine.

  7. Recoverable writes without transactions

    The serverless Postgres driver has no transaction support, so resolution is ordered: update the stake, then write the ledger, then send email last on a best-effort basis. A failure at any step leaves a state the next run can recover from.

Stack

Framework
Next.js 16 (App Router), React 19, TypeScript
UI
Tailwind CSS, shadcn/ui
Database
Neon Postgres, Drizzle ORM
Auth
bcrypt + JWT cookies, Google sign-in
Validation
Zod
Email
Resend
Scheduled jobs
Vercel Cron (daily resolution)
Testing
Vitest