Real-time invoice processing demo with Convex and Nuxt. Upload PDF invoices and watch AI extract structured data in the background.
Live demo: https://invoice-processor-gerts.vercel.app/
User Upload -> Convex Storage -> Scheduler -> Background Action -> AI Extraction -> Database Update
-
Upload (Client): User drops a PDF. The client requests a signed upload URL via
generateUploadUrlmutation, uploads directly to Convex storage, then callscreateInvoicewith thestorage_id. -
Instant Feedback (Mutation):
createInvoiceinserts a record withstatus: 'processing'and immediately returns. The invoice appears in the reactive list within milliseconds. -
Background Processing (Scheduler): Before returning,
createInvoicecallsctx.scheduler.runAfter(0, processInvoice, { invoiceId }). This schedules the heavy AI work to run asynchronously after the mutation commits--keeping the user's upload fast. -
AI Extraction (Action):
processInvoiceis a Node.js action that:- Reads the PDF blob from storage
- Extracts text using
unpdf - Sends text to Gemini via
@convex-dev/agentwith a Zod schema - Validates the response (YYYY-MM-DD date, numeric amounts, line items)
-
Database Update (Internal Mutation): On success,
updateInvoicesetsstatus: 'complete'with extracted fields. On failure, it setsstatus: 'failed'witherror_message. -
Real-Time UI: The frontend subscribes to
listInvoicesvia Convex's reactive queries. When the action updates the database, the UI reflects changes instantly--no polling or refresh.
| Pattern | Why |
|---|---|
ctx.scheduler.runAfter(0, ...) |
Decouples slow AI work from the fast mutation, ensuring instant user feedback |
| Internal action + mutations | Actions can call external APIs (AI); mutations handle DB writes atomically |
| Zod validation | Ensures AI output conforms to schema before persistence--no raw JSON blobs |
| Convex reactive queries | Eliminates polling; UI updates automatically on any database change |
# Install dependencies
pnpm install
# Copy environment template
cp .env.local.example .env.local
# Fill in: CONVEX_DEPLOYMENT, CONVEX_URL
# GOOGLE_GENERATIVE_AI_API_KEY should be set up in Convex dashboard (env)
# Start Convex dev server (separate terminal)
pnpm run convex:dev
# Start Nuxt dev server
pnpm run dev| Command | Description |
|---|---|
pnpm dev |
Start Nuxt dev server |
pnpm convex:dev |
Start Convex dev server |
pnpm typecheck |
Run TypeScript checks |
pnpm test:once |
Run tests once |
pnpm lint |
Run ESLint |
- Frontend: Nuxt 3, Vue 3, Tailwind CSS
- Backend: Convex (database, storage, functions)
- AI: Google Gemini via
@convex-dev/agent - PDF Parsing:
unpdf - Validation: Zod
