Skip to content
Work

iOS app · Product engineering

Shortwhile

An iOS-first reading app built around one complete story and one idea to think about each day, and the backend behind it: accounts, sync, server-side subscription authority and an editorial rights pipeline.

Release
In developmentNot yet on the App Store or TestFlight
Client
React Native, ExpoTypeScript, iOS first
Platform
Supabase, RevenueCatPostgreSQL with row-level security, Edge Functions and server-side entitlements
Validation
299 automated testsSQL policy checks, Maestro simulator flows
Shortwhile's Today screen: the day's story, Icarus, under a drawing of Daedalus forming Icarus's wings, with the question 'What happens when freedom outruns caution?', Ovid, 5 minutes, and The Gift of the Magi below under Also for today.Shortwhile's Discover screen: an editorial collection, Read These Once in Your Life, with five stories and three cover artworks, then search and All Stories, 17 stories from A to Z.
Today and Discover. Every cover shown is a public-domain or open-access artwork whose rights are recorded and verified.

01

The product

Shortwhile is a calm daily ritual rather than a library: one complete story, then something worth thinking about afterwards, in roughly fifteen minutes. Readers can start without an account, finish their first story free, and keep their saves, progress, completions and reflections when they sign in.

The reading interface is the visible part. Most of the engineering is in what keeps a reader’s data, access and content trustworthy: what happens offline, on a second device, after a payment, or when a request arrives twice or out of order.

screens across reading, discovery, library and account
34
screens across reading, discovery, library and account
automated tests at the current checkpoint
299
automated tests at the current checkpoint
Edge Functions: entitlement refresh, webhooks, account deletion
3
Edge Functions: entitlement refresh, webhooks, account deletion
stories in the prototype catalogue
17
stories in the prototype catalogue
Shortwhile's first onboarding screen: three cover artworks above 'One great story. One meaningful idea. Fifteen minutes. Every day.', with Get started and a sign-in link.Onboarding step 'Which ideas draw you in? Choose a few, up to five.' with Love, Courage and Wisdom selected among fifteen ideas.
Onboarding: the promise, then a few ideas to shape what comes next. Signing in is optional.

02

Accounts and data

A guest’s state lives on the device in SQLite. At sign-in, one server function merges it into the account inside a single transaction, and records the merge so a retried request cannot apply it twice. After that, saves, progress, completions and reflections sync with the account.

Row-level security on every user table
Policies scope each row to the signed-in user with auth.uid(), the anonymous role has no access to user tables, and progress and save writes also check that the story is available. Event and merge tables have client access revoked entirely.
A conflict rule for each kind of data
Saves take the latest intent by event time, progress keeps the furthest position, completions are recorded once per read, and reflections use version-checked updates that keep a recovery copy on the device that lost. Every write is idempotent through client-generated IDs.
Magic links beyond the happy path
Email sign-in uses PKCE, so a link opened on another device cannot complete the sign-in. Expired and reused links are refused, offline and incomplete links are handled, the resend cooldown follows the server’s, and tokens are only kept in the iOS Keychain.
Streaks decided by the server
Completions credit reading days through a database trigger on the server’s clock, with a grace window, so changing the device clock cannot fake a streak.

03

Subscriptions without trusting the client

RevenueCat handles purchases, but Supabase decides access. The app’s view of membership is only ever provisional.

A server-side entitlement projection
Entitlements are written only by privileged server functions, always rebuilt from RevenueCat’s current state rather than from a webhook payload, and never overwrite a newer read.
Idempotent, order-independent webhooks
RevenueCat’s event ID is the primary key, so duplicates are acknowledged without reprocessing; failures return an error so RevenueCat retries; and a stale replay or an expiry that arrives before its renewal still settles on the current state. The shared secret is compared in constant time.
Authenticated refresh
After a purchase the app asks the server to refresh. The account is taken from the access token, never the request body, and refreshes are rate-limited per account.
Premium text gated in the database
Members-only story text is protected by a row-level policy that checks the server’s entitlement record, so a modified client cannot unlock it.

This has been verified end to end with RevenueCat’s Test Store, including real webhook deliveries. App Store sandbox testing comes with the Apple Developer setup, and membership enforcement stays off in the live database until launch.

04

Security, content and quality

A security review with a real finding
The review found no critical issues and one high-severity one: the live auth configuration still allowed development redirect URLs, which could let someone who started a sign-in for another person’s email receive their code. Both were removed and the fix verified against the live project, including a refused replay. Lower-severity items are tracked as launch work.
Provenance for every story
Each story records where its text came from, the source edition, how it was transformed and who checked it; each cover records its rights basis, evidence, reviewer and date. A database constraint stops rights being marked verified without evidence, and a trigger blocks publishing until they are. A small CLI validates, dry-runs and imports content.
Tests at several layers
299 automated tests cover the content pipeline, catalogue programming and the subscription server logic, including 20 RevenueCat event fixtures. SQL checks exercise the policies against the database inside rolled-back transactions, and Maestro scripts the main flows on the iOS simulator.
Accessibility as a requirement
Controls carry VoiceOver labels and roles, layouts restack at large Dynamic Type sizes, and the Reader and onboarding respect Reduce Motion.

05

Where it stands

The major product architecture is built and tested: the reading experience, accounts and sync, server-side subscriptions and the content pipeline. Shortwhile is not yet launched and is not on TestFlight. The remaining work is mostly outside the codebase:

  • Apple Developer enrolment, App Store Connect products and sandbox purchase testing.
  • Production configuration for Sign in with Apple, which is implemented in the app.
  • Clearing text rights and editorial approval for every story; cover rights are verified, text rights are still being researched.
  • Production services: a custom email domain for sign-in mail, CAPTCHA, backups, and published terms and privacy policy.
  • A Release build tested on device, the final app icon and brand assets.