Ezen IELTS AI — Your Personal IELTS Coach, Built for Everyone

Inspiration

In Vietnam, IELTS is a lifelong gatekeeper.

Students need it for university, professionals need it for careers, and families need it for immigration.

Yet quality preparation remains expensive, with private tutors often charging $20–50/hour. Meanwhile, most online tools are built in English, for English-fluent users.

We observed real learners — people with limited English proficiency and limited technical experience — struggling to navigate the very platforms designed to help them.

That became our founding constraint, written into our codebase as a hard rule:

Every screen must be understandable in simple Vietnamese, a first-time user must complete a core task in under 3 minutes, and every feature must map to a measurable band-score improvement.

If a feature passes all tests but fails that standard, it is not finished.

This project also started as a one-person project.

As the scope kept growing — AI grading, payments, quota systems, speech recognition — it became clear that one pair of hands was not enough.

Old university classmates joined first, then students from other universities.

What began as a solo side project became a team united by the same goal:

Making IELTS preparation accessible to every Vietnamese learner.


What It Does

Ezen IELTS AI is a full-stack IELTS practice platform powered by an AI examiner.

Writing Practice

Users can submit essays and receive instant AI grading with detailed band-aligned feedback.

The system evaluates writing criterion-by-criterion and then synthesizes the result into a final report.

Speaking Practice

Users can record answers directly in the browser using the Web Speech API and MediaRecorder.

No plugins are required, and no uploads to third-party services are needed.

The AI examiner grades the transcript across IELTS criteria, with a manual transcript fallback for unsupported browsers.

Listening Practice

Users can practice with AI-generated listening exercises, guided questions, and structured feedback flows.

Audio tracks are served from Cloudflare R2 object storage.

Quick Test

A 5-minute no-signup assessment that allows users to experience value before creating an account.

AI Chat

A streaming IELTS assistant built on a LangGraph agent pipeline, including:

  • Keyword-first intent routing
  • LLM fallback only when the intent is ambiguous
  • Prompt-injection guardrails
  • Streaming sanitizer that scrubs model/provider leaks
  • Protection even when a forbidden term is split across two stream chunks

Knowledge Ingestion API

A stateless document-ingestion service that chunks content and returns 1024-dimensional Mistral embeddings directly.

No vector database is required to maintain.

Personalized Learning Roadmap

Daily study plans tailored to the user's current level and target IELTS band score.

Fair Usage System

Transparent Guest → Free → Student plans featuring:

  • Usage tracking
  • Remaining quota visibility
  • Reset countdowns
  • PayOS payment integration
  • Webhook checksum verification
  • Async plan activation via Pub/Sub
  • Daily quota resets at 5:00 AM Vietnam Time

Vietnamese-First Experience

The entire product is designed in plain Vietnamese, with full English i18n via next-intl.

We actively rewrote technical phrases such as:

AI định hướng việc học

into:

Học đúng bài, đúng lúc — AI lo cho bạn

We also enforced a strict UX principle:

One primary action per screen.


How We Built It

Layer Technology
Frontend Next.js 16 + React 19, App Router, Server Components, Server Actions, React Compiler
Backend Encore.dev + TypeScript microservice-style services
Database PostgreSQL + Drizzle ORM
AI Mistral API, SSE streaming via api.streamOut, LangChain/LangGraph agent pipeline
Speech Web Speech API, SpeechRecognition, SpeechSynthesis, MediaRecorder
Payments PayOS + Encore Pub/Sub
Storage Cloudflare R2 for audio tracks and writing task images
Styling Tailwind CSS v4 + shadcn/ui
Authentication Custom JWT with HS512 + bcrypt
Testing & Quality Vitest + Playwright E2E + Biome

Architecture

The backend is organized as independent Encore services, with each service owning a specific business domain:

  • Authentication
  • AI Chat with LangGraph agent
  • Writing Evaluation
  • Speaking Evaluation
  • Listening Practice
  • Quick Test
  • Pricing & Quotas
  • Payments with PayOS + Pub/Sub
  • Learning Roadmap
  • Knowledge Ingestion

On the frontend:

  • Server Components render by default
  • Mutations are handled through Server Actions
  • No ad-hoc API routes are used

Usage tracking, rate limiting, and plan enforcement are centralized in a dedicated pricing service.

This ensures every AI feature shares a consistent quota system.


Challenges We Ran Into

1. Metering AI Usage Without Token Data

Mistral's streaming API does not return token counts, yet our pricing model depends on usage tracking.

We built a custom estimation strategy:

tokens ≈ response_length / 4

This was integrated into a centralized checkAndIncrementUsage service with:

  • Daily token limits
  • Hourly request windows
  • Automatic resets at 05:00 Vietnam Time

2. Defending the AI Examiner Against Prompt Injection

Users will try to make the AI reveal its system prompt, its model name, or grade them a Band 9 for free.

We built a deterministic guardrail layer instead of relying on the model to refuse.

This includes:

  • A keyword-based injection detector that short-circuits inside the agent graph
  • Refusal responses that stream back without ever calling the LLM
  • A stateful stream sanitizer that scrubs provider/model names from responses
  • A carry-over window that catches forbidden terms split across stream chunks, such as "Mist" + "ral"
  • A circuit breaker around Mistral:
    • 5 failures within 60 seconds
    • Open state
    • Half-open recovery
  • An LRU plan cache to absorb rapid retries

3. Streaming That Freezes

Chat streams occasionally stalled when WebSocket connections closed mid-response.

To solve this, we added:

  • Explicit close-event handling
  • Recovery logic
  • Frontend logging
  • Backend logging

This significantly improved long-response reliability.


4. Server Components Are Unforgiving

A single thrown exception during data fetching could crash an entire server-rendered page.

We redesigned our API layer around safer behavior:

  • apiFetch never throws
  • Typed error responses are returned everywhere
  • Token and cookie retrieval are explicit

This eliminated an entire class of dashboard crashes.


5. Embeddings Without Database Bloat

Our first knowledge-base implementation stored embeddings with pgvector.

The database grew rapidly and became costly to maintain.

We replaced it with a completely stateless /knowledge ingestion API that chunks documents and returns embeddings directly.

The result:

  • Lower costs
  • Simpler architecture
  • One less stateful system to operate

6. Designing for Non-Technical Users

The biggest UX problem was not aesthetics.

Users consistently struggled to answer:

What am I doing, and how does this help me improve my IELTS score?

We responded by:

  • Reducing copy density by around 30%
  • Removing unnecessary English terminology
  • Showing meaningful progress within the first 60 seconds

7. Testing AI End-to-End

Real JWT authentication plus non-deterministic AI responses made E2E testing fragile.

We built a dedicated testing mode:

E2E_MOCK_AUTH=1

This mode is only activatable when:

NODE_ENV === "test"

It allows Playwright to execute complete user journeys:

Login
 → Generate Practice
 → Receive Feedback
 → View Results

This works without requiring real credentials and without any mock path ever shipping to production.


What We Learned

User Outcomes Beat Feature Count

Our definition of "done" now includes validation from non-technical users, not just passing automated tests.

Streaming AI Products Need Cost Infrastructure

If your AI provider does not meter usage, you must build that capability yourself:

  • Idempotently
  • Transactionally
  • Transparently

Guardrails Must Be Deterministic

A model can be talked out of its instructions.

A regex cannot.

Putting injection defense and leak sanitization outside the LLM was the only approach that survived real users.

Stateless Beats Clever

Both our embedding-service redesign and our never-throw API strategy reinforced the same lesson:

Predictable systems outperform clever systems in production.

Plain Language Is a Product Feature

Changing:

Band Score

to:

Điểm IELTS mục tiêu

had a bigger impact on user activation than several visual redesigns combined.

A Growing Scope Needs a Growing Team

Starting solo forced ruthless prioritization.

Growing into a team — old classmates and students from different universities — forced something harder:

Writing rules down.

Our founding constraint went from a habit in one person's head to a documented standard every contributor builds against.

That transition, more than any framework, is what allowed the project to scale.

Built With

  • cloudflare-r2
  • drizzle-orm
  • encore.dev
  • langchain
  • langgraph
  • mistral-ai
  • next.js
  • payos
  • playwright
  • postgresql
  • python
  • react
  • shadcn-ui
  • tailwindcss
  • typescript
  • vercel
  • vitest
  • web-speech-api
  • zod
  • zustand
Share this project:

Updates