Skip to content
← All work

Lexora AI

Essay feedback that refuses to guess

Framework

Next.js 15 · React 19 · TypeScript

Data

PostgreSQL · Supabase

Model

Groq · llama-3.3-70b-versatile

Validation

Zod

01The problem

Useful essay feedback is specific: this sentence, this claim. That takes a teacher hours, so most students rarely get it.

How much of grading can you take away from the model without making it useless?

02The solution

Let the model do the judging. Everything after the judgement is plain code that can be tested.

Live on Vercel. The model only judges; routing, taxonomy and storage are all deterministic.

03Architecture

Next.js 15 on Vercel, Postgres on Supabase, and Groq's llama-3.3-70b. Four stages, each with a countable number of model calls.

laterdedup firstaggregatesNext.js 15App Router · VercelStage 1 · Groqgrade + extract · 1 callStage 2 · Groqgroup + generate · 1 batchedStage 3 · Groqgrade answers · on demandZod gatesafeParse, every boundaryOne transactionall of it or nonePostgreSQLSupabase · CHECK on 8Stage 4class-wide questions

Four stages, a Zod gate after every model call, and one database transaction that either takes the whole result or none of it. Connections: Next.js 15 to Stage 1 · Groq; Next.js 15 to Stage 3 · Groq (later); Stage 1 · Groq to Zod gate; Stage 2 · Groq to Zod gate; Stage 3 · Groq to Zod gate; Zod gate to Stage 2 · Groq (dedup first); Zod gate to One transaction; One transaction to PostgreSQL; PostgreSQL to Stage 4 (aggregates).

scroll the diagram sideways →

BrowserServiceGate / cacheDataExternaldashed = on a timer

04Technical depth

  • Zod checks every model response. Groq's JSON mode isn't schema-validated, so this is the real gate.
  • The first two stages commit in one transaction: a student sees the whole analysis or none of it.
  • Eight mistake categories, enforced by a Postgres constraint, a TypeScript union and the prompt.
  • Routing is plain code: grammar mistakes get multiple choice, structural ones get a short answer.
The real question isn't how good the model is. It's what the system believes without checking.