Cherimo: rebuilding an app for the small things from usage data
On this page
What it is
Their favourite things and the things they dislike, anniversaries, the gifts you gave and how they landed, the thing they mentioned wanting in passing, the places you went together. The small things you do not want to forget and do anyway, organized per person. From what you have saved, an AI suggests gifts, date plans and thoughtful messages.
It is not a shared couples’ app for two. You use it alone. There is no invitation, and nothing you record is ever shown or sent to the other person. The person does not have to be a partner: family, children and friends all fit.

How it is built
A Turborepo monorepo holds the web and mobile apps together.
apps/web: Next.js (App Router) on Vercel. The marketing pages, every signed-in screen and the API routesapps/mobile: Expo SDK 58 / React Native 0.88, for iOS and Androidpackages/shared: Japanese and English i18n and the zod schemas
Supabase is the backend: Postgres with RLS on every table, Apple and Google sign-in, Storage for images. The AI is Claude through the Vercel AI SDK, and monthly AI usage is counted from the log table rather than a dedicated counter. Anniversary reminders are decided by a Vercel Cron job and sent as Web Push and mobile push. The home-screen widgets, @bacons/apple-targets on iOS and react-native-android-widget on Android, show the days until and since a chosen anniversary.
Billing runs on two rails, Stripe on the web and RevenueCat on mobile, but the single source of truth for entitlements is one column, users.plan. Screens and API routes never read Stripe tables or RevenueCat subscription state directly. Whichever rail a purchase comes through, updating that one column makes it count.
Development and production are separate Supabase projects, with environment variables synced from Infisical to Vercel. Writes to the production database are blocked by an agent hook, so Claude Code cannot touch production by mistake.
What the usage data said
A few months after launch, I sat down with the production logs. My standing hypothesis was that people were dropping out because data entry was tedious. It was wrong. A high share of users created a person and went on to record preferences; onboarding was working.
The drop-off happened on the day of sign-up. People entered everything on day one and never came back. And anniversaries averaged a little over one per user, with a maximum of two. Nobody was anywhere near the free limit of ten.
The cause was the data model. With only one person allowed, you enter a birthday and the day you got together, and that is it. Notifications fire once or twice a year. For the other 363 days the app has nothing to say. Of the eleven AI features, about half were ever used.
The conclusion was that the thing to build was not another AI feature. It was support for more than one person.
What 1.4.0 did
- Dropped the unique constraint on
partners.user_idso a user can have several people - Found and fixed everything that assumed one person: an avatar update overwriting everyone, failing upserts,
.single()throwing on multiple rows - Made records save to the currently selected person. Anniversaries, preferences, gifts, notes and AI output had all been pinned to the first person, so records for anyone else could not be created
- Made the home screen and widgets span everyone, listing all anniversaries soonest first
- Added a weekly note that resurfaces something they like, as a daily cron job with no AI involved
- Fixed data export, which had only ever written one person’s data
- Added
maxPartnersto the plans (3 on Free, 10 on Plus, unlimited on Pro)
Before that, 1.2.0 was a full accessibility pass: every screen usable with VoiceOver and TalkBack, labels on icon-only buttons, and the widget reading as one natural sentence.
What I learned
- Decide what to build from the distribution in the raw logs, not from dashboard averages. “Maximum two” explained the structure where “average one point one” did not
- Keep entitlements in one column. Add payment rails without adding places that decide
- Ship invisible updates such as an Expo SDK upgrade as their own patch release (1.4.5), not mixed with visible changes, so the build that passed device testing is the build that ships

Cherimo is on iPhone, Android and the web. cherimo.app
RELATED
Flutter, AWS, homelab. A few side projects and open-source tools. For architecture questions or collaboration, reach out via X DM or the About page. About