
An AI-powered personal finance assistant that forensically analyzes spending habits, tracks income and expenses across custom categories, and delivers Gemini-generated behavioral insights — built with Next.js 16, Prisma, and MongoDB.
SpendWise is a premium, AI-powered personal finance assistant built to give individuals a forensic-level understanding of their money. The project was conceived around a simple but powerful idea: most expense trackers show you numbers, but none of them explain your behavior. SpendWise changes that.
At its core, SpendWise combines three layers of intelligence. The first is real-time transaction tracking — users can log income and expenses across a hierarchical category system (system-defined categories with user-customizable subcategories), with full CRUD operations, date filtering, and period comparisons. The second is a smart budget engine that tracks monthly spending against a configurable limit, supports a no-limit free-tracking mode, and preserves historical budget records so that old reports remain accurate even when limits change. The third and most distinctive layer is the Forensic AI Analysis engine, powered by Google Gemini, which processes a user's full financial history and returns a structured report covering spending patterns, budget intelligence scores, behavioral insights, and hypothetical scenario planning.
The application is built as a full-stack Next.js 16 project using the App Router architecture, with TypeScript throughout, Prisma ORM connecting to a MongoDB Atlas cluster, and NextAuth.js handling Google OAuth authentication. Security is reinforced with optional email-based two-factor authentication via Nodemailer. The frontend is styled with Tailwind CSS 4, animated with Framer Motion, and visualized with Recharts. Reports can be exported to PDF via html2canvas and jsPDF, and the app ships as a Progressive Web App installable on any device.
Building SpendWise surfaced several non-trivial engineering challenges that shaped the architecture of the final product.
The first and most complex challenge was taming the Gemini AI response layer. Large language model outputs are inherently unpredictable — a raw Gemini response might return narrative prose when the frontend needs structured chart data. The solution required designing a strict JSON schema that the API prompt enforces, covering every field the frontend consumes: spending scores, category breakdowns, scenario deltas, and insight paragraphs. Any schema drift causes a silent render failure, so the schema validation layer had to be robust and the prompt carefully constrained.
The second challenge was budget historical integrity. Users change their monthly budget limit over time. A naive implementation that reads the current limit when rendering historical reports would produce misleading data — a report from three months ago would show the wrong budget context. SpendWise solves this by persisting a separate Budget model that records the limit for every month independently, so each historical AI report is always rendered against the budget that was active when it was generated.
The third challenge was category caching. Global categories (the system-defined list used by the expense form across all users) are expensive to re-fetch on every request. Using Next.js unstable_cache dramatically reduces database load, but it introduces a coherence problem: when an admin edits a category, the cache must be explicitly invalidated or users will see stale options. Building a reliable cache invalidation flow — and surfacing it visibly in the admin panel — required careful coordination between the data layer and the cache control layer.
The fourth challenge was the two-factor authentication flow. Implementing OTP via email with proper expiry, rate limiting, attempt tracking, and graceful fallback required building a complete mini-auth system on top of NextAuth's session model — including the edge case where a user enables 2FA and then loses access to their email.
The Solution
Each challenge was resolved through a set of deliberate architectural decisions that prioritize data integrity, developer predictability, and user trust.
For the Gemini AI schema problem, the solution was to treat the AI layer as a typed data pipeline rather than a text generator. The Gemini API is called with a prompt that contains the complete expected JSON structure, annotated field descriptions, and explicit instructions to return nothing outside the schema. The response is parsed against a TypeScript interface before any rendering occurs. If parsing fails, the error is surfaced to the user with a retry option rather than silently rendering partial data. This approach makes the AI feature as predictable as any other API endpoint in the system.
For budget historical integrity, the Budget model stores one record per user per month, created or updated whenever the user changes their limit. The Report model stores a snapshot of the budget context at generation time, so the AI report renderer always reads from the report record itself rather than the current user settings. This decoupling means historical reports are immutable and accurate regardless of future budget changes.
For category caching, the global categories fetch is wrapped in Next.js unstable_cache with a named cache tag. The admin panel exposes a manual cache invalidation endpoint (POST /api/admin/cache/invalidate) that calls revalidateTag() with the matching tag. This gives administrators explicit control over cache freshness and makes the invalidation action visible in the audit log. The cache hit rate is also surfaced in the admin settings panel so the performance benefit is measurable.
For the 2FA system, a dedicated OTP model stores the generated code, the associated user, the expiry timestamp, and the attempt count. The verification endpoint checks all three conditions (code match, expiry, attempt limit) atomically before marking the session as verified. Brute-force protection is enforced by locking further OTP attempts after three failures within a 10-minute window. Administrators can force-reset 2FA for any user account, with the action logged to the immutable audit trail.
SpendWise delivers measurable value across three dimensions: user experience, technical architecture, and portfolio signal.
From a user perspective, SpendWise transforms personal finance from passive record-keeping into active behavioral analysis. Users receive not just summaries of what they spent, but AI-generated explanations of why their spending patterns look the way they do, which categories represent structural overspending versus one-off events, and concrete scenario projections — for example, reducing entertainment spend by 20% would unlock an additional ₹840 per month in savings. The 50/30/20 radar chart gives users a visual benchmark against a widely-accepted budgeting framework, making the gap between current behavior and optimal allocation immediately legible.
From a technical architecture perspective, the project demonstrates full production-grade engineering discipline. The AI integration goes beyond simple API calls to implement schema enforcement, error handling, historical caching, and rate control. The authentication system layers OAuth with optional 2FA and preserves session integrity across both mechanisms. The data model handles temporal complexity — budget limits that change over time — correctly. The caching strategy balances performance with consistency through explicit invalidation rather than time-based expiry. These are the kinds of decisions that distinguish a production system from a prototype.
From a portfolio perspective, SpendWise occupies a rare position: a solo-built, publicly deployed application that integrates a modern AI API in a non-trivial way, handles real user data with appropriate security practices, and solves a genuine everyday problem. It demonstrates command of the full Next.js 16 App Router paradigm, Prisma with a document database, Google OAuth, transactional email, PDF generation, and PWA delivery — a technology surface broad enough to be relevant across a wide range of engineering roles.