Skip to main content
←Back to projects

CASE STUDY · 01

English Journal: a pronunciation journal that listens to how you speak

You can read English just fine; now you need people to understand you. English Journal listens to how you speak, spots the sound you keep missing and decides what you practice tomorrow. No mascots, no lives, no empty rewards. And it works even offline.

ROLE
End-to-end design and development
TYPE
Pronunciation journal · Installable web app (PWA)
STACK
Next.js 16 · React 19 · Supabase · Gemini API · Dexie · Kokoro TTS
STATUS
In production · since 2025
English Journal: a pronunciation journal that

THE PROBLEM

Language apps usually need a constant connection, reward streaks instead of real learning and, when they use AI, every answer costs money.

THE GOAL

An app you can open on the subway with no signal, that tells you honestly what you know and what you don’t, and only uses AI when it truly helps.

PROCESS

From a pronunciation notebook to a full app

  1. 01

    Device first

    Everything you do is saved instantly on your phone or computer. Cloud sync happens in the background, with automatic retries.

  2. 02

    AI on a budget

    Before calling Gemini, the app checks answers with its own rules. That saves calls and keeps corrections predictable.

  3. 03

    Private data per user

    139 Supabase migrations with row-level security on every table: each person can only see their own data.

  4. 04

    Thoroughly tested

    Around 6,600 automated tests with Vitest and Playwright cover everything from review logic to accessibility.

TECHNICAL DECISIONS

What happens behind the interface

Technical decisions to keep the app fast, never lose data and keep AI spending under control.

recovery.tssync queue
// lib/sync/recovery.ts: retries with growing delays
const RETRY_DELAYS_MS = [5_000, 30_000, 2 * 60_000]

export function getNextRetryAt(retryCount: number, attemptedAt: string): string {
  const delay = RETRY_DELAYS_MS[Math.min(retryCount - 1, RETRY_DELAYS_MS.length - 1)]
  return new Date(new Date(attemptedAt).getTime() + delay).toISOString()
}

/** Releases entries left in `syncing` by a crashed or closed tab. */
export async function reclaimStaleSyncingEntries(currentTime = Date.now()) {
  const staleBefore = new Date(currentTime - SYNCING_STALE_MS).toISOString()
  return db.syncOutbox
    .where('status')
    .equals('syncing')
    .filter((entry) => Boolean(entry.lastAttemptAt && entry.lastAttemptAt < staleBefore))
    .modify({ status: 'pending' })
}
  • Local-first sync (Dexie + Supabase)

    Answers are saved to IndexedDB first and go through an outbox queue. If a tab closes halfway, the app recovers those writes on its own.

  • Rules before the model

    Deterministic validators and pre-generated content handle most exercises without calling Gemini live.

  • Voice that works offline

    Text-to-speech runs with Kokoro right in the browser, with no server involved.

  • Spaced repetition with FSRS (ts-fsrs)

    Mastery is calculated only from evaluated practice. Opening the app or keeping a streak doesn’t count as learning.

THE SOLUTION

Four pillars, one profile of your voice

Screenshot or video of sound lab
01

Sound Lab

Record yourself, see your waveform next to a native speaker’s and find the sound you keep missing.

Screenshot or video of essential words
02

Essential words

The 2,800 words that show up in almost everything you will hear, with their real weak forms.

Screenshot or video of your journal
03

Your journal

Write about your day and get corrections explained in Spanish. Your vocabulary comes from your life.

Screenshot or video of speaking missions
04

Speaking missions

Conversations with a goal: order a coffee, explain a problem, defend an idea.

RESULTS

By the numbers

~6,600

Automated tests

Unit, integration and end-to-end with Vitest and Playwright.

2,800

Essential words

Each with its real weak form and spaced review.

66

Mini lessons

From A1 to C2, plus 276 grammar pattern decks.

WHAT I LEARNED

An app that respects your time works on your device first and only uses the cloud when it needs to.
Technical takeaway:

Handling with your own rules whatever doesn’t need a language model makes AI cheaper and its answers more predictable.

Product takeaway:

Reading is exposure, saving is intent and practice is evidence. Mastery is earned over time, not through clicks or streaks.

Tell me about your idea

It doesn't need to be fully formed, and you don't need to know what it's called. Write to me like you'd write to a friend and I'll reply within 24 hours.

Replies within 24 hours