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


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


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.