Storyie
BlogPricing
Storyie
Log inSign up
Sign up

Developers

Engineering write-ups on how Storyie is built — architecture, tooling, and code.

All PostsDevelopersJournaling

Entitlements Need Plan and Status

Storyie Engineering TeamJul 20, 20267 min read

Checking only plan name or only status made the same user Pro in one feature and Free in another. isProEntitled(plan, status) is the fix.

Developers

Soft Deletes Are an API Contract

Storyie Engineering TeamJul 20, 20265 min read

Soft delete on the server is only half the story. The sync pull contract must carry tombstones as typed delete changes — not omit the row and hope clients notice.

Developers

Push notification deep links across three app states

Storyie Engineering TeamJul 20, 20267 min read

A notification tap is three different races depending on app state. Storyie stopped guessing with setTimeout and waits for Expo Router readiness instead.

Developers

Exponential Backoff That Survives App Restarts

Storyie Engineering TeamJul 20, 20266 min read

In-memory retry timers forget their schedule when the OS kills the app. Storyie stores the backoff deadline in SQLite so the next launch picks up exactly where the last attempt left off.

Developers

Rate Limiting Before Auth: Drop Traffic Before Session Lookup

Storyie Engineering TeamJul 20, 20266 min read

Auth is expensive. We put a pluggable sliding-window rate limiter ahead of session lookup so brute-force never pays for a DB round-trip — and the Expo client uses the same budget.

Developers

One Signup, Two Profiles: Guarding the Public/Private Invariant with Better Auth

Storyie Engineering TeamJul 20, 20267 min read

One auth user is not enough. Storyie needs a public profile and a private profile on every real signup. We put that invariant in a Better Auth hook — and made every other path fail closed instead of inventing a row.

Developers

Designing an Offline Mutation Queue on SQLite

Storyie Engineering TeamJul 19, 20267 min read

An offline edit is a promise the app has to keep after a force-quit. Storyie persists every pending mutation as a SQLite row with a status state machine, exponential-backoff retry, and an ownership guard against stale server data.

Developers

Lexical JSON to Markdown Without a Browser

Storyie Engineering TeamJul 18, 20268 min read

The canonical Lexical-to-Markdown path needs a live editor and a registered node for every type. Our export runs in a Lambda, so it walks the JSON tree directly instead.

Developers

Soft Deletes in a Local-First Mobile Database

Storyie Engineering TeamJul 18, 20268 min read

A hard DELETE in a local-first app is a bug waiting for the next sync. Here is the tombstone column and the two guards that keep a deleted row deleted.

Developers

UTC Month Boundaries for Subscription Quotas

Storyie Engineering TeamJul 18, 20268 min read

Our free plan allows 31 diaries a month. When "a month" was UTC in one place and local time in another, the reset and the dedup key disagreed at midnight on the 1st. Here is the fix.

Developers

Guest Accounts Without Data Loss: Linking an Anonymous User to a Real One

Storyie Engineering TeamJul 18, 20269 min read

A guest writes diaries, then signs in with Google. Better Auth deletes the anonymous user right after the link resolves — so one hook has one chance to move the data. We made it atomic, retryable, and safe when both sides already exist.

Developers

Last-Write-Wins Is a Product Decision

Storyie Engineering TeamJul 18, 20268 min read

LWW is not "give up and take the newest timestamp." Storyie forgives one second of clock drift, breaks ties toward the server, guards uncommitted local edits at the SQLite layer, and always tells you when your version was replaced.

Developers

Plugin Order Broke Our OAuth: A One-Line Fix for state_security_mismatch

Storyie Engineering TeamJul 18, 20267 min read

Web login broke with state_security_mismatch while mobile kept working. The fix was one plugin, in one position: nextCookies() had to be last.

Developers

Proving a Postgres-to-Turso cutover: counts, checksums, and FK spot-checks

Storyie Engineering TeamJul 15, 20269 min read

Migration scripts exit 0 when they do not crash, not when your data arrived intact. We wrote a separate, read-only verification step to actually prove it before switching traffic to Turso.

Developers

Local-First Autosave Without Losing the Last Keystroke

Storyie Engineering TeamJul 15, 20268 min read

Debounce is a data-loss window. Storyie writes to on-device SQLite synchronously on every keystroke and defers the network save — then uses refs, not state, to keep the race honest.

Developers

When 50 Markdown Posts Broke Static Generation

Storyie Engineering TeamJul 15, 20266 min read

A 44-post import turned an O(N) parse into an O(N²) build and blew past the 60s SSG timeout. The fix hinges on caching the parse Promise, not its result.

Developers

When cascades do not cascade: deleting user data on libSQL

Storyie Engineering TeamJul 15, 20268 min read

Our FK cascades look correct in the schema and do nothing at runtime. We delete a user across 25 tables explicitly, inside one transaction, by hand.

Developers

Migrating Authentication Without Rewriting Every Caller

Storyie Engineering TeamJul 14, 20267 min read

A provider swap touches every page that reads the current user. We contained the blast radius to a single file — a CompatUser shim — instead of a 56-file rewrite. The trade-off: the shim tells one deliberate lie.

Developers

Protected by Default: A Hono API That Fails Closed

Storyie Engineering TeamJul 14, 20267 min read

Per-route auth is a forgetting machine. We rebuilt Storyie’s Hono API so a new route is locked unless you explicitly open it — and a regression test keeps it that way.

Developers

Automating X posts with GitHub Actions and Claude: how we built it for Storyie

Storyie Engineering TeamJun 21, 20267 min read

We run Claude inside GitHub Actions to draft X posts weekly, store them in Supabase as drafts, review them ourselves, then let a second workflow publish on schedule. Here is how the whole thing fits together.

Developers

Managing Stripe Products and Prices with Terraform

Storyie Engineering TeamJun 17, 20266 min read

Repeated price changes, per-environment duplication, and manual SQL migrations convinced us to declare Stripe resources in Terraform. Here's the full setup.

Developers

Seven RLS patterns we use across all 27 Supabase tables in Storyie

Storyie Engineering TeamJun 15, 20269 min read

We run RLS policies on every table in Storyie. After designing and operating 27 of them, the patterns collapsed into seven reusable shapes — here is each one with its intent and the pitfalls we hit.

Developers

Supabase RLS and multi-tenant isolation: how much can the database enforce?

Storyie Engineering TeamJun 14, 20268 min read

Relying only on WHERE clauses for tenant isolation is an accident waiting to happen. Here is how we moved that guarantee down to the database with Supabase RLS.

Developers

Shared subscription limits across web and mobile: a DB-free package design

Storyie Engineering TeamJun 12, 20267 min read

Plan limits that live in a pure-function package mean one change propagates to web, mobile, and tests simultaneously — no copy-paste, no drift.

Developers

Storyie: a diary app that ships on web, iOS, and Android

Storyie Engineering TeamJun 11, 20266 min read

Storyie is a cross-platform diary app where every entry is private by default, and going public is one tap. Here's what it does and how it's built.

Developers

Staging environment design with SST and CloudFront: safely isolating production from everything else

Storyie Engineering TeamJun 10, 20267 min read

One sst.config.ts, two stages, no WAF bill — how we wired SST v3 and CloudFront to keep production safe while still being able to test Stripe webhooks and OAuth flows.

Developers

SST v3 tips: Pulumi Output, Cron, ARM64

Storyie Engineering TeamJun 9, 20269 min read

Six months of running Storyie on SST v3 produced a list of things the docs don't cover — Pulumi Output resolution in transforms, stage-scoped env loading, Cron offsets to avoid connection pool contention, and more.

Developers

Automating App Store Optimization with an AI Agent and asc CLI

Storyie Engineering TeamJun 1, 20268 min read

We wired an AI agent to the App Store Connect CLI so that keyword research, 10-locale metadata drafts, and monthly ASO reviews run mostly unattended — with a dry-run gate before anything lands.

Developers

Making Storyie discoverable to AI: llms.txt and Markdown route handlers in Next.js

Storyie Engineering TeamMay 27, 20267 min read

We added llms.txt and Markdown route handlers to Storyie so AI assistants can understand the app without parsing HTML — dynamically generated, ISR-cached, and privacy-safe by default.

Developers

One image pipeline, two runtimes: Cloudflare R2 uploads on web and mobile

Storyie Engineering TeamMay 25, 20267 min read

Same architecture, different implementations: how we built one image upload pipeline for Next.js and Expo on top of Cloudflare R2.

Developers

10 locales, 4 layers: how we internationalized Storyie across Next.js, Expo, email, and AI

Storyie Engineering TeamMay 24, 20267 min read

Supporting 10 languages in a cross-platform monorepo means four different i18n strategies — one per layer. Here is how we wired them together without losing our minds.

Developers

Drizzle custom migration, rollback and revert on Supabase

Storyie Engineering TeamMay 20, 202610 min read

After a year of shipping Storyie, our migration file count hit 56. Here is what we learned about running Drizzle ORM in production with Supabase — two-stage CI deployment, when to write custom SQL, and how we think about rollbacks.

Developers

Claude Code Action on GitHub Issues: label → plan → PR

Storyie Engineering TeamMay 15, 20268 min read

Write an issue, attach a label, and let Claude handle the plan-then-implement loop — with a required human checkpoint between the two.

Developers

Auth and authorization in Storyie: the full picture with Supabase Auth, RLS, and RBAC

Storyie Engineering TeamMay 14, 20269 min read

Supabase Auth, RLS, and RBAC each solve a distinct problem. Here is how we wired all three together in Storyie so the database enforces security even when application code forgets to ask.

Developers

AI writing assist in a diary app: prompt design, validation, fallbacks, and usage control

Storyie Engineering TeamMay 13, 20268 min read

One endpoint, six diary patterns, ten languages — and a validation + fallback layer that keeps the feature working even when the AI API is down.

Developers

How we built AI-powered monthly reports for a diary app using Lambda and Anthropic

Storyie Engineering TeamMay 12, 20267 min read

How we wired SST Cron, Lambda, and the Anthropic API to generate a monthly diary analysis for every Pro user — and the design decisions around input limits, structured output, and idempotency that made it production-safe.

Developers

Lexical EditorState JSON serialization + React Native

Storyie Engineering TeamNov 19, 202517 min read

Building a Lexical editor that works identically on web and mobile is one of the most challenging aspects of cross-platform development. At Storyie, diary entries created on our Next.js web app must render perfectly in our React Native mobile app, and vice versa. Through a two-package architecture...

Developers