Skip to content

gertsio/invoice-processor-gerts

Repository files navigation

AI-Powered Invoice Processor

Real-time invoice processing demo with Convex and Nuxt. Upload PDF invoices and watch AI extract structured data in the background.

Invoice Processor UI

Live demo: https://invoice-processor-gerts.vercel.app/

Architecture Note

Data Flow

User Upload -> Convex Storage -> Scheduler -> Background Action -> AI Extraction -> Database Update

How It Works

  1. Upload (Client): User drops a PDF. The client requests a signed upload URL via generateUploadUrl mutation, uploads directly to Convex storage, then calls createInvoice with the storage_id.

  2. Instant Feedback (Mutation): createInvoice inserts a record with status: 'processing' and immediately returns. The invoice appears in the reactive list within milliseconds.

  3. Background Processing (Scheduler): Before returning, createInvoice calls ctx.scheduler.runAfter(0, processInvoice, { invoiceId }). This schedules the heavy AI work to run asynchronously after the mutation commits--keeping the user's upload fast.

  4. AI Extraction (Action): processInvoice is a Node.js action that:

    • Reads the PDF blob from storage
    • Extracts text using unpdf
    • Sends text to Gemini via @convex-dev/agent with a Zod schema
    • Validates the response (YYYY-MM-DD date, numeric amounts, line items)
  5. Database Update (Internal Mutation): On success, updateInvoice sets status: 'complete' with extracted fields. On failure, it sets status: 'failed' with error_message.

  6. Real-Time UI: The frontend subscribes to listInvoices via Convex's reactive queries. When the action updates the database, the UI reflects changes instantly--no polling or refresh.

Why These Convex Patterns?

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

Local Setup

# 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

Scripts

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

Tech Stack

  • Frontend: Nuxt 3, Vue 3, Tailwind CSS
  • Backend: Convex (database, storage, functions)
  • AI: Google Gemini via @convex-dev/agent
  • PDF Parsing: unpdf
  • Validation: Zod

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors