Actual is an AI-powered personal finance analytics platform that helps users track expenses, manage budgets, analyze spending habits, and receive intelligent financial insights for better money decisions.
Please try the demo first.
π https://actual.debarghya.org
This project was inspired by my diploma college life, when I moved away from home and struggled to manage daily expenses like food, rent, travel, bills, fees, and emergencies. Even with monthly support from my family, it was difficult to understand where the money was going.
I realized many students face the same problem because they lack simple tools for budgeting, expense tracking, and financial planning. Actual was built to solve this by helping users track expenses, analyze spending habits, manage budgets, and get AI-powered financial insights for better daily money decisions.
- π Secure authentication with Clerk
- π Personal finance dashboard
- π¦ Account management with default account support
- πΈ Income and expense tracking
- π§Ύ AI receipt scanning
- π Recurring transaction support
- π― Budget planning and category targets
- π Analytics, reports, and financial health score
- π€ AI finance assistant, Kubera
- π§ Budget alerts and monthly report emails
- π§ͺ Demo mode for quick exploration
Actual uses an authenticated client-server flow for personal finance management.
AUTHENTICATED MODE
User
β
Clerk Login / Sign Up
β
Protected Next.js Dashboard
β
Server Actions / API Routes
β
Prisma ORM
β
PostgreSQL Database
- Client Layer: Next.js pages and React components render the landing page, demo dashboard, authenticated dashboard, forms, charts, reports, and AI workspace.
- Server Layer: Server Actions, API routes, Clerk authentication, Arcjet rate limiting, and Inngest background jobs handle secure business logic.
- Database Layer: PostgreSQL stores real user data such as accounts, transactions, budgets, and dashboard preferences through Prisma ORM.
flowchart TB
USER([User]) --> LANDING[Actual Landing Page]
LANDING --> LOGIN[Sign In or Sign Up]
LOGIN --> CLERK[Clerk Authentication]
CLERK --> ACCESS{Authenticated?}
ACCESS -->|No| LOGIN
ACCESS -->|Yes| PROXY[Next.js Proxy Route Protection]
PROXY --> DASHBOARD[Protected Dashboard]
DASHBOARD --> MODULES[Finance Modules]
MODULES --> ACCOUNTS[Accounts and Transactions]
MODULES --> BUDGETS[Budgets and Planning]
MODULES --> ANALYTICS[Analytics, Reports and Health Score]
MODULES --> AI[AI Insights and Receipt Scanner]
ACCOUNTS --> SERVER[Server Components, Actions and API Routes]
BUDGETS --> SERVER
ANALYTICS --> SERVER
AI --> SERVER
SERVER --> AUTHZ[User Sync, Authentication and Ownership Checks]
AUTHZ --> LOGIC[Finance Business Logic]
AUTHZ -. Rate-limited operations .-> ARCJET[Arcjet Rate Limiting]
ARCJET --> LOGIC
LOGIC --> PRISMA[Prisma ORM]
PRISMA --> DATABASE[(PostgreSQL Database)]
LOGIC -->|Kubera and financial insights| GEMINI[Gemini API]
LOGIC -->|Receipt image extraction| GROQ[Groq Vision API]
INNGEST[Inngest Scheduler] --> RECURRING[Process Recurring Transactions]
INNGEST --> ALERTS[Check Budget Alerts]
INNGEST --> REPORTS[Generate Monthly Reports]
RECURRING --> PRISMA
ALERTS --> PRISMA
REPORTS --> PRISMA
REPORTS --> GEMINI
ALERTS --> RESEND[Resend Email]
REPORTS --> RESEND
The context diagram shows the system boundary and the external services that exchange data with Actual.
flowchart TB
USER[User] -->|Identity details, finance records, budgets, receipts and questions| SYSTEM([0.0 Actual Personal Finance Analytics])
SYSTEM -->|Dashboard views, charts, reports, health score and guidance| USER
SYSTEM <-->|Identity and session data| CLERK[Clerk]
SYSTEM <-->|Finance records, preferences and site metrics| DATABASE[(PostgreSQL)]
SYSTEM <-->|Finance prompts and generated insights| GEMINI[Gemini API]
SYSTEM <-->|Receipt images and extracted receipt data| GROQ[Groq Vision API]
INNGEST[Inngest] -->|Scheduled job triggers| SYSTEM
SYSTEM -->|Budget alerts and monthly report content| RESEND[Resend]
RESEND -->|Email notifications and reports| USER
The detailed diagrams separate user-driven activity from scheduled automation so each data path remains readable.
flowchart TB
USER[User] <-->|Pages, forms, filters and results| UI([Next.js Application UI])
UI -->|Sign-in or sign-up request| AUTH([1.0 Authenticate and Sync User])
AUTH <-->|Identity and session data| CLERK[Clerk]
AUTH <-->|Create or retrieve application user| D1[(D1 Users)]
UI <-->|Account details and balances| ACCOUNT([2.0 Manage Accounts])
ACCOUNT <-->|Account records and default account| D2[(D2 Accounts)]
UI <-->|Create, edit, filter or delete transactions| TRANSACTION([3.0 Manage Transactions])
TRANSACTION <-->|Income, expenses and recurrence data| D3[(D3 Transactions)]
TRANSACTION -->|Apply balance changes| D2
UI -->|Receipt image| TRANSACTION
TRANSACTION -->|Image extraction request| GROQ[Groq Vision API]
GROQ -->|Amount, date, merchant and category| TRANSACTION
UI <-->|Budget and planning settings| BUDGET([4.0 Manage Budgets and Preferences])
BUDGET <-->|Budget and dashboard preferences| D4[(D4 Budgets and Preferences)]
D3 -->|Current spending totals| BUDGET
UI <-->|Charts, reports and financial health| ANALYTICS([5.0 Analyze Financial Health])
D2 -->|Balances and account totals| ANALYTICS
D3 -->|Income, expenses and categories| ANALYTICS
D4 -->|Budget targets and goals| ANALYTICS
UI -->|Finance question and recent chat| KUBERA([6.0 Generate AI Finance Guidance])
D2 -->|Total account balance| KUBERA
D3 -->|Current month and 90-day activity| KUBERA
KUBERA <-->|Financial context and generated answer| GEMINI[Gemini API]
KUBERA -->|Personalized guidance| UI
UI -->|Landing-page visit| METRICS([7.0 Record Site View])
METRICS <-->|Read or increment view count| D5[(D5 Site Metrics)]
METRICS -->|Current view count| UI
flowchart TB
INNGEST[Inngest Scheduler] -->|Daily trigger| RECURRING([8.0 Process Recurring Transactions])
D3[(D3 Transactions)] -->|Due recurring transaction| RECURRING
RECURRING -->|Create completed occurrence and schedule next date| D3
RECURRING -->|Adjust account balance| D2[(D2 Accounts)]
INNGEST -->|Every six hours| ALERTS([9.0 Check Budget Alerts])
D1[(D1 Users)] -->|Recipient name and email| ALERTS
D3 -->|Current-month expenses| ALERTS
D4[(D4 Budgets and Preferences)] -->|Budget amount and last alert time| ALERTS
ALERTS -->|Update last alert time| D4
ALERTS -->|Budget warning email| RESEND[Resend]
INNGEST -->|First day of each month| REPORTS([10.0 Generate Monthly Reports])
D1 -->|User and email details| REPORTS
D2 -->|Account count and total balance| REPORTS
D3 -->|Previous-month income and expenses| REPORTS
REPORTS <-->|Monthly statistics and generated insights| GEMINI[Gemini API]
REPORTS -->|Personalized monthly report| RESEND
RESEND -->|Budget alert or monthly report| USER[User Email Inbox]
| Data store | Information stored |
|---|---|
D1 Users |
Clerk user ID, email, name, and profile image |
D2 Accounts |
Account name, type, balance, and default-account state |
D3 Transactions |
Income, expenses, categories, dates, status, and recurring schedules |
D4 Budgets and Preferences |
Monthly budget, savings goals, category targets, and dashboard visibility settings |
D5 Site Metrics |
Persistent landing-page view count |
All authenticated finance processes validate the Clerk user and data ownership before accessing PostgreSQL. Arcjet rate limits sensitive operations such as account creation, transaction creation, budget updates, receipt scanning, and Kubera requests.
actual/
βββ app/ # Next.js App Router application
β βββ (auth)/ # Clerk authentication route group
β β βββ sign-in/[[...sign-in]]/ # Sign-in page
β β βββ sign-up/[[...sign-up]]/ # Sign-up page
β βββ (main)/ # Authenticated application route group
β β βββ account/[id]/ # Account route and account UI components
β β βββ dashboard/ # Main dashboard and shared dashboard layout
β β β βββ _components/ # Overview, budget, report, and AI workspaces
β β β βββ ai-insights/ # Kubera finance assistant
β β β βββ analytics/ # Income and expense analytics
β β β βββ budgets/ # Budget planning and savings goals
β β β βββ financial-health/ # Financial health score
β β β βββ reports/ # Monthly financial reports
β β β βββ transaction/create/ # Dashboard transaction creation route
β β βββ transaction/ # Transaction list, form, scanner, and create route
β βββ actions/ # Account, transaction, budget, AI, seed, and email actions
β βββ api/
β β βββ financial-health/ # Financial health JSON endpoint
β β βββ inngest/ # Inngest serve endpoint
β β βββ seed/ # Guarded transaction seed endpoint
β β βββ views/ # Persistent site-view counter
β βββ demo/dashboard/ # Static dashboard preview routes
β βββ lib/schema.ts # Zod form-validation schemas
β βββ globals.css # Global Tailwind styles
β βββ layout.tsx # Root providers, header, footer, and toaster
β βββ page.tsx # Public landing page
βββ components/ # Shared layout, navigation, and showcase components
β βββ ui/ # Reusable shadcn/Radix UI primitives
βββ data/ # Transaction categories and landing-page content
βββ emails/template.tsx # Budget alert and monthly report email templates
βββ hooks/use-fetch.ts # Async action state hook
βββ lib/
β βββ inngest/ # Inngest client and scheduled/background functions
β βββ generated/prisma/ # Generated Prisma client; not committed
β βββ arcjet.ts # Per-user rate limiting
β βββ checkUser.ts # Clerk-to-database user synchronization
β βββ dashboard-preferences.ts # Dashboard preference persistence
β βββ demo-data.ts # Static data used by demo routes
β βββ financial-health.ts # Financial health scoring logic
β βββ prisma.ts # PostgreSQL Prisma client
βββ prisma/
β βββ migrations/ # Versioned PostgreSQL schema migrations
β βββ schema.prisma # Database models, relations, enums, and indexes
βββ public/ # Logos and feature screenshots grouped by feature
β βββ ai/
β βββ analysis/
β βββ budget/
β βββ overview/
β βββ report/
β βββ transaction/
βββ proxy.ts # Clerk middleware and protected-route matching
βββ next.config.ts # Next.js and Server Action configuration
βββ prisma.config.ts # Prisma configuration and database URL loading
βββ tsconfig.json # Strict TypeScript configuration
βββ package.json # Scripts and application dependencies
Generated and machine-local directories such as .next/, node_modules/, and lib/generated/prisma/, along with .env* files, are intentionally excluded from version control.
The database uses PostgreSQL through Prisma ORM. Five related models store identities and user-owned finance data, while SiteMetric independently stores application-wide counters.
| Prisma model | PostgreSQL table | Purpose |
|---|---|---|
User |
users |
Maps a Clerk identity to the user's finance data |
Account |
accounts |
Stores current and savings accounts, balances, and default-account state |
Transaction |
transactions |
Stores income, expenses, categories, receipt references, and recurring schedules |
Budget |
budgets |
Stores one monthly budget and its most recent alert time per user |
DashboardPreferences |
dashboard_preferences |
Stores month-specific budgets, savings goals, category targets, and visibility settings |
SiteMetric |
site_metrics |
Stores independent application counters such as total site views |
erDiagram
USER ||--o{ ACCOUNT : owns
USER ||--o{ TRANSACTION : records
USER ||--o| BUDGET : sets
USER ||--o| DASHBOARD_PREFERENCES : configures
ACCOUNT ||--o{ TRANSACTION : contains
USER {
string id PK
string clerkUserId UK
string email UK
string name "nullable"
string imageUrl "nullable"
datetime createdAt
datetime updatedAt
}
ACCOUNT {
string id PK
string name
AccountType type
decimal balance
boolean isDefault
string userId FK
datetime createdAt
datetime updatedAt
}
TRANSACTION {
string id PK
TransactionType type
decimal amount
string description "nullable"
datetime date
string category
string receiptUrl "nullable"
boolean isRecurring
RecurringInterval recurringInterval "nullable"
datetime nextRecurringDate "nullable"
datetime lastProcessed "nullable"
TransactionStatus status
string userId FK
string accountId FK
datetime createdAt
datetime updatedAt
}
BUDGET {
string id PK
decimal amount
datetime lastAlertSent "nullable"
string userId FK, UK
datetime createdAt
datetime updatedAt
}
DASHBOARD_PREFERENCES {
string userId PK, FK
json monthlyBudgetTargets
json savingsGoalTargets
json categoryTargetsByMonth
json visibleCategoryIdsByMonth
datetime createdAt
datetime updatedAt
}
SITE_METRIC {
string key PK
int value
datetime updatedAt
}
DashboardPreferences.userId is both its primary key and a foreign key to User. Budget.userId is unique, so a user can have at most one budget record. SiteMetric has no user relationship because it stores global counters.
| Enum | Allowed values |
|---|---|
AccountType |
CURRENT, SAVINGS |
TransactionType |
INCOME, EXPENSE |
TransactionStatus |
PENDING, COMPLETED, FAILED |
RecurringInterval |
DAILY, WEEKLY, MONTHLY, YEARLY |
Deleting a user cascades to their accounts, transactions, budget, and dashboard preferences. Deleting an account also cascades to its transactions. Database indexes support user transaction history, recurring-transaction processing, and default-account lookup; a partial unique index ensures that each user has at most one default account.
| Dashboard | Account Summary |
|---|---|
![]() |
![]() |
| Transaction List | Create Transaction |
|---|---|
![]() |
![]() |
| Transaction Form |
|---|
![]() |
| Budget Planning | Category Targets |
|---|---|
![]() |
![]() |
| Budget Alert Email |
|---|
![]() |
| Reports | Analytics |
|---|---|
![]() |
![]() |
| Monthly Report Email |
|---|
![]() |
| Kubera AI Assistant | AI Insights |
|---|---|
![]() |
![]() |
| Category | Technologies |
|---|---|
| Frontend | Next.js, React, TypeScript |
| Styling | Tailwind CSS, shadcn-style UI, Radix UI |
| Authentication | Clerk |
| Database | PostgreSQL, Prisma ORM |
| Background Jobs | Inngest |
| AI / ML | Google Gemini API, Groq Vision API |
| Resend, React Email | |
| Charts & Analytics | Recharts |
| Animations | Framer Motion |
| Security | Arcjet rate limiting |
| Icons & UI Feedback | lucide-react, Sonner |
- Clone the repository.
git clone https://github.com/debarghya131/Actual.git
cd Actual- Install dependencies.
npm install- Set up environment variables.
cp .env.example .env.local- Generate Prisma client.
npx prisma generate- Run database migrations.
npx prisma migrate dev- Start the development server.
npm run devCreate a .env.local file in the root directory and add the following variables:
DATABASE_URL=
DIRECT_URL=
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
ARCJET_KEY=
RESEND_API_KEY=
GEMINI_API_KEY=
GROQ_API_KEY=
GROQ_MODEL=Never commit real API keys or database credentials to GitHub.
- Managing student-style daily expenses in a simple and understandable way
- Keeping account balances accurate after transaction create, update, and delete actions
- Handling recurring transactions without duplicate processing
- Building a useful budget system with monthly and category-wise planning
- Extracting receipt details from images using AI
- Giving personalized AI finance insights without exposing user data publicly
- Protecting authenticated dashboard routes and user-specific data
- Preventing abuse of AI, receipt scanning, and transaction actions
- Sending useful budget alerts and monthly reports automatically
- Keeping the landing page and dashboard visually rich but still lightweight
- Built a clean dashboard for income, expenses, savings, budgets, reports, and analytics
- Used Prisma transactions to update transactions and account balances safely
- Added Inngest background jobs for recurring transactions, budget alerts, and monthly reports
- Used Groq Vision API for AI-powered receipt scanning
- Used Gemini API for Kubera AI finance guidance and monthly insights
- Added Clerk authentication and protected routes through
proxy.ts - Applied Arcjet rate limiting for sensitive actions like AI chat, receipt scan, account creation, and budget updates
- Stored dashboard preferences in PostgreSQL using Prisma and JSON fields
- Added demo mode so users can explore the app without creating an account
- Compressed large images and replaced heavy PNG assets with optimized WebP files
- ESLint is configured for code quality checks.
- Server Actions include validation for authentication, required fields, invalid amounts, missing accounts, and invalid recurring transaction data.
- Receipt scanning validates file type and file size before sending images to the AI service.
- Demo mode helps test the main dashboard experience without using real user data.
- Prisma migrations keep the database structure version-controlled and reproducible.
Run linting with:
npm run lint- Large images were compressed and replaced with lightweight WebP assets.
- Heavy dashboard sections use focused components to keep the UI organized.
- Prisma indexes are added for frequently queried fields like
userId,accountId, transaction status, date, and recurring transaction data. - Server-side data fetching is used for authenticated dashboard pages.
Promise.allis used where multiple independent database queries can run together.- Prisma client is reused in development to avoid creating too many database connections.
- Background work like recurring transactions, budget alerts, and monthly reports is handled by Inngest instead of blocking user interactions.
- Clerk handles authentication and user session management.
- Protected routes are guarded through
proxy.ts. - Database queries are filtered by the authenticated user to prevent cross-user data access.
- Arcjet rate limiting protects sensitive actions such as AI chat, receipt scanning, account creation, transaction creation, and budget updates.
- Environment variables store API keys and database credentials outside the codebase.
.env*, generated files, local tool folders, and build outputs are ignored by Git.- Receipt uploads are restricted to image files under 5MB.
- Server-side validation is used before creating or updating financial records.
- Add bank API integration for automatic transaction syncing
- Add CSV import and export for transactions
- Add more advanced AI-based spending predictions
- Add multi-currency support
- Add custom financial goals and goal progress tracking
- Add downloadable PDF reports
- Add more automated tests for Server Actions and financial calculations
- Add PWA support for a better mobile experience
- Add dark mode for the full dashboard
- Add more detailed admin and user activity logs
- Learned how to build a full-stack finance dashboard with Next.js App Router
- Learned how to design relational database models with Prisma and PostgreSQL
- Learned how to protect user-specific financial data with authentication and server-side checks
- Learned how to manage financial calculations like balances, budgets, savings, and recurring transactions
- Learned how to integrate AI APIs for receipt scanning and finance insights
- Learned how to use background jobs for scheduled reports and alerts
- Learned how to optimize large assets for faster landing page performance
- Learned how to structure a real-world project with reusable components, server actions, and clean folder organization
Debarghya Bandyopadhyay
I always like to make new friends. Follow me on:














