InvoScope lets you upload, view, and analyze PDF invoices directly in the browser. With features like real-time PDF viewing, AI-powered invoice parsing, search, and invoice management, InvoScope is designed to simplify handling financial documents end-to-end.
- π View PDFs in the browser using
react-pdfwith zoom, rotate, pagination - β¬οΈ Upload PDFs and persist metadata
- π€ Extract structured invoice data via Gemini with retry & fallback
- π Search and manage invoices (list, get, update, delete)
- Frontend: Next.js (App Router), TypeScript, Tailwind, react-pdf
- Backend: Node.js/Express, TypeScript, Mongoose/MongoDB, Google Gemini (for extraction)
- Node.js 20+
- npm 10+
- MongoDB (local or remote)
- Google Gemini API key
git clone https://github.com/AmanKrSahu/pdf-review-app.git
cd pdf-review-app
# install server deps
cd server && npm i
# install client deps
cd ../client && npm i- Server requires a
.envfile (see below). - Client just needs the API base URL via
NEXT_PUBLIC_API_BASE.
Create server/.env:
# Express
PORT=8000
NODE_ENV=development
# Mongo
MONGO_URI=mongodb://localhost:27017/pdf_review_app
# CORS
FRONTEND_ORIGIN=http://localhost:3000
# Google Gemini
GEMINI_API_KEY=YOUR_API_KEY
# Uploads
MAX_FILE_SIZE=26214400# Terminal A
cd server
npm run build && npm start # or: npm run dev
# Terminal B
cd client
npm run devFrontend β http://localhost:3000
Backend β http://localhost:8000 (base path /api)
- React 19, Next 15 (App Router).
- PDF viewing powered by
react-pdf.
Worker setup (must match pdf.js version):
// client/src/components/pdf/PdfViewer.tsx
pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;- If CDN use is disallowed, map the worker locally via Next config.
- Options passed to
<Document />are memoized to prevent reloads.
Base URL: http://localhost:8000/api
GET /β health checkPOST /uploadβ upload a PDFGET /files/:fileIdβ fetch PDF file (or metadata)POST /extractβ run Gemini extraction on uploaded PDF textGET /invoicesβ list invoices (?q=...&page=1&limit=10)GET /invoices/:idβ get invoice by id ORfileId/fileNamePOST /invoicesβ create invoicePUT /invoices/:idβ update by id ORfileId/fileNameDELETE /invoices/:idβ delete by id ORfileId/fileName
-
Exponential backoff retries for transient errors (429, 503, overload, timeout).
-
Fallback model sequence:
gemini-2.5-flash-litegemini-2.5-flashgemini-1.5-flash
export interface LineItem {
description: string;
unitPrice: number;
quantity: number;
total: number;
}
export interface Invoice {
_id?: string;
fileId: string;
fileName: string;
vendor: {
name: string;
address?: string;
taxId?: string;
};
invoice: {
number: string;
date: string;
currency?: string;
subtotal?: number;
taxPercent?: number;
total?: number;
poNumber?: string;
poDate?: string;
lineItems: LineItem[];
};
createdAt: string;
updatedAt?: string;
}- Home Page
- Invoice Page
- Upload Invoice Dialog
- PDF Reviewer Page
- CORS: set
FRONTEND_ORIGINto your client URL. - ObjectId vs file identifiers: API accepts both.
- PDF worker mismatch: ensure
pdfjs.versionmatches worker file. - React hooks: keep them at the top of components.
- Ensure
MONGO_URI,GEMINI_API_KEY,FRONTEND_ORIGINare configured. - Serve client behind HTTPS if using
react-pdfwith credentials.
- Worker version mismatch β use
pdfjs.versionworker URL or pinpdfjs-dist. - 503/overloaded from Gemini β server retries/fallback automatically (check logs).
- CastError for ObjectId β use filename or
fileId; server resolves automatically.
Feel free to contact me on Linkedin