Back to work
Personal · Mobile app · 2026

Élan

"The Duolingo of reading." A mobile app that enforces a daily reading habit — random notification, 30 minutes to start, timed segment, 3 AI-generated comprehension questions. Streak validated, or not.

Flutter Dart Riverpod GoRouter Firebase Claude API RevenueCat
Challenge

How do you enforce a daily reading habit without falling into the flashcard fatigue that plagues Duolingo clones?

Approach

Randomly-timed notifications, timed reading segments, MCQs generated by Claude API to verify comprehension. Streak system, RevenueCat subscriptions for pro features.

Outcome

Shipped on iOS & Android from a single Flutter codebase.

01Context

A product I would actually use myself

I read — but not enough, not every day, and rarely with attention. The reading apps out there are either e-readers (passive) or trackers (declarative). None of them force you to read today, right now, with attention.

Élan's intuition: controlled frustration. A random notification in a window you pick. 30 minutes to start. A timed passage. Three multiple-choice questions. Miss one, no streak today. Pass, and the flame goes up.

02What I built

Core loop, streaks, freemium

  • Flutter app — Riverpod for state, GoRouter for nav, Clean Architecture by feature.
  • Random notification — a Cloud Function cron picks a random time in your window every night; another per-minute cron sends the due ones via FCM.
  • AI-generated questions — one segment, three MCQs, generated in a Cloud Function via Anthropic's Claude API, with pre-generated fallbacks for the free tier.
  • Streak system — consecutive-day counter, badges at 10, 50, 100. Free tier capped at 3, premium unlimited.
  • RevenueCat freemium — monthly & yearly subscription, contextual paywall, entitlement management.
  • Multi-provider auth — Google Sign-In + Sign in with Apple, Firestore-backed user profile.
03Product design

Minimalist, serious, motivating

Five screens: onboarding, home (flame + today status), reading (text + minimalist timer), questions (3 MCQs), result (streak/badge animation). No feed. No infinite scroll. No loud gamification. The point is for the user to close the app thinking "today, I read."

04Stack
FlutteriOS + Android
Riverpod 2.xState management
GoRouter 14Navigation
FirebaseAuth, Firestore, FCM, Functions
Claude APIQuestion generation (server-side)
RevenueCatSubscriptions
Google Sign-InAuth
Sign in with AppleAuth