Smart daily pack
Words banded by CEFR level, with a placement test to set the starting point.
Case study
A mobile vocabulary app built around one small, finishable habit: ten new words a day, a short daily quiz and a weekly exam built only from the days you completed.
I was responsible for the full build of the product: architecture, backend, mobile app, and deployment.
Endless courses and long lessons work until one busy day breaks the habit, and then the app gets abandoned.
The number is the product: 10 words a day, 3,650 a year.
Words banded by CEFR level, with a placement test to set the starting point.
20 questions drawn only from the lessons you aced that week, in a 24-hour window.
Daily, exam, streak-at-risk and birthday pushes, localized PL/EN.
An iOS widget, plus cached screens that stay readable without a connection.
Clients talk to one REST API. The API owns every rule and reaches the database and external services.
React Native + Expo · offline cache · iOS widget
Firebase Hosting · email confirmation and reset page
Push scheduler · signup cleanup
Problem. The exam must open on Sunday at each learner's own reminder hour, stay open for 24 hours and use only days they aced.
Solution. One service resolves the whole exam state per user, with the window computed from their time zone. The qualifying lessons are snapshotted when the exam starts, so later activity can't change its questions.
Problem. A pack has to match the learner's level and avoid every word already quizzed or skipped, even across redraws and half-finished days.
Solution. Selection excludes used and discarded words, fills the learner's level band first, blends in a couple of words from the next band and widens the range if the catalog runs thin.
Problem. Packs, streaks, push hours and exam windows all depend on "the day", which differs per user and shifts with daylight saving.
Solution. Each user has a validated IANA time zone synced from the device, and all date logic goes through a single service. Streaks are evaluated lazily on read, so no midnight job is needed.
Problem. Send the right message at each user's local hour, never twice, and never let one bad account break the batch.
Solution. A hosted service polls every 15 minutes and skips anything already logged for that user, day and kind. A log row is written only for delivered pushes, so failures retry on the next tick.