Smart Personal Expense Tracker & Financial Insights Platform
SpendSense is a production-ready, full-stack expense tracking application built with cutting-edge technologies. It empowers users to take control of their finances by providing intelligent expense tracking, real-time analytics, multi-currency support, and beautiful visual insights.
- β Type-Safe: End-to-end TypeScript with tRPC
- π Secure: OAuth2 authentication, rate limiting, server-side validation
- π Intelligent: Real-time analytics, spending patterns, category breakdowns
- π Multi-Currency: Support for 10+ currencies with automatic conversion
- β‘ Performance: Cursor-based pagination, Redis caching, optimized queries
- π¨ Beautiful: Dark/light mode, responsive design, modern UI components
- π Scalable: Cloud-ready with Vercel deployment
- Create, read, update, and delete expense/income transactions
- Categorize transactions with custom categories (25 max per user)
- Support for 9 payment methods (UPI, Cash, Card, Net Banking, Wallet, Bank Transfer, Cheque, EMI, Other)
- Multi-currency support (INR, USD, EUR, GBP, AUD, CAD, NZD, SGD, HKD, JPY)
- Add descriptions and attach categories for better organization
- Maximum 700 transactions per user (quota-based system)
- Summary Cards: Income & expense totals by currency
- Monthly Trends: Line chart showing cumulative balance over time
- Category Breakdown: Pie chart visualizing expense distribution
- Payment Methods: Bar chart analyzing spending patterns
- Net Worth Tracking: Running balance calculation and visualization
- Create custom expense categories with custom colors
- Edit category names and color codes
- Delete categories (transactions remain orphaned for historical data)
- Color-coded categorization for visual organization
- Date range filtering (from/to dates)
- Transaction type filtering (Expense/Income)
- Payment method filtering
- Category-based filtering
- Full-text description search (case-insensitive)
- Persistent filter state
- Export transactions as JSON format
- Timestamped export filenames
- Bulk transaction download
SpendSense follows a Next.js-based full-stack monorepo architecture with clear separation of concerns:
Client (Next.js App Router)
β
Frontend Components (React + TailwindCSS + shadcn/ui)
β
API Layer (tRPC + Next.js API Routes)
β
Authentication (NextAuth.js with OAuth2)
β
Business Logic (Drizzle ORM + Services)
β
PostgreSQL Database
β
Redis Cache (Upstash)
| Technology | Purpose | Version |
|---|---|---|
| Next.js | React framework with App Router | 15+ |
| React | UI library | 19+ |
| TypeScript | Type safety | 5.0+ |
| tRPC | Type-safe RPC | Latest |
| TanStack Query | Data fetching & caching | v5 |
| Zustand | State management | Latest |
| shadcn/ui | UI component library | Latest |
| TailwindCSS | Utility-first CSS | v4 |
| Recharts | Data visualization | Latest |
| Zod | Schema validation | Latest |
| Technology | Purpose | Version |
|---|---|---|
| Next.js | Node.js framework | 15+ |
| NextAuth.js | OAuth2 authentication | v5 |
| Drizzle ORM | Type-safe database access | Latest |
| PostgreSQL | Primary database | 14+ |
| Upstash Redis | Rate limiting & caching | Latest |
| Zod | Schema validation | Latest |
| Technology | Purpose |
|---|---|
| Vercel | Hosting & deployment |
| Docker | Containerization |
| Bun | Fast JavaScript runtime |
| ESLint | Code linting |
βββββββββββββββββββ
β Users β
ββββββοΏ½οΏ½ββββββββββββ€
β id (PK) ββββ¬βββββ¬βββββ¬βββββ
β name β β β β β
β email (UNIQUE) β β β β β
β emailVerified β β β β β
β image β β β β β
β role β β β β β
β createdAt β β β β β
β updatedAt β β β β β
βββββββββββββββββββ β β β β
β β β β
ββββββββββββββββββ β β β
β β β β
ββββββββββββββββββββββ β β β
β Transactions β β β β
ββββββββββββββββββββββ€ β β β
β id (PK) β β β β
β userId (FK) ββββββ β β
β categoryId (FK) βββββββββββ β
β txnType (ENUM) β ββ β
β amountPaise (INT) β ββ β
β currency (VARCHAR) β ββ β
β description β ββ β
β paymentMethod β ββ β
β createdAt β ββ β
β updatedAt β ββ β
ββββββββββββββββββββββ ββ β
ββ β
βββββββββββββ β
β β β
ββββββββββββββββ β
β β
ββββββββββββββββ ββββββββββββββββββ
β Categories β β NextAuth β
ββββββββββββββββ€ β Tables β
β id (PK) β ββββββββββββββββββ€
β userId (FK) ββββββ€ Accounts β
β name β β Sessions β
β color β β Verification β
β createdAt β β Authenticators β
β updatedAt β ββββββββββββββββββ
ββββββββββββββββ
CREATE TABLE "user" (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100),
email VARCHAR(255) UNIQUE NOT NULL,
emailVerified TIMESTAMP WITH TIMEZONE,
image TEXT,
role ENUM('ADMIN', 'USER') DEFAULT 'USER',
createdAt TIMESTAMP WITH TIMEZONE DEFAULT now(),
updatedAt TIMESTAMP WITH TIMEZONE DEFAULT now()
);CREATE TABLE "txn" (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
txn_type ENUM('EXPENSE', 'INCOME') NOT NULL,
category_id UUID REFERENCES "category"(id) ON DELETE SET NULL,
amount_paise INTEGER NOT NULL CHECK (amount_paise > 0),
currency VARCHAR(3) DEFAULT 'INR' NOT NULL,
description VARCHAR(400),
payment_method ENUM('UPI', 'CASH', 'CARD', 'NETBANKING', 'WALLET',
'BANK_TRANSFER', 'CHEQUE', 'EMI', 'OTHER') DEFAULT 'OTHER',
createdAt TIMESTAMP WITH TIMEZONE DEFAULT now(),
updatedAt TIMESTAMP WITH TIMEZONE DEFAULT now()
);
-- Indexes for performance
CREATE INDEX "txn_user_created_at_idx" ON "txn"(user_id, created_at, id);
CREATE INDEX "txn_user_type_idx" ON "txn"(user_id, txn_type);
CREATE INDEX "txn_user_payment_idx" ON "txn"(user_id, payment_method);
CREATE INDEX "txn_user_category_idx" ON "txn"(user_id, category_id);CREATE TABLE "category" (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
name VARCHAR(50) NOT NULL,
color VARCHAR(20),
createdAt TIMESTAMP WITH TIMEZONE DEFAULT now(),
updatedAt TIMESTAMP WITH TIMEZONE DEFAULT now(),
UNIQUE(user_id, name)
);
CREATE INDEX "category_user_idx" ON "category"(user_id);- accounts: OAuth2 provider account linkage
- sessions: User session management
- verificationTokens: Email verification tokens
- authenticators: Passkey/WebAuthn support
- GitHub - Social sign-in via GitHub
- Google - Social sign-in via Google
- Uses NextAuth.js v5 with
DrizzleAdapter - Database session strategy for persistent sessions
- OAuth providers configured in
auth.config.ts - Auth handlers exposed via
/api/auth/[...nextauth]route
- Password-free authentication (OAuth2 only)
- Session-based authorization via middleware
- Protected procedures in tRPC with
authMiddleware
Auth Config (auth.config.ts):
providers: [Google, Github]
session: { strategy: "database" }
adapter: DrizzleAdapter(db)SpendSense implements a multi-layer rate limiting system using Upstash Redis with sliding window algorithm:
limitsPerUser: {
categories: 25, // Max categories per user
txns: 700, // Max transactions per user
amount: 5000, // Max single transaction amount
loginAttempts: 10, // Login attempts per minute
createAttempts: 20, // Create operations per minute
updateAttempts: 10, // Update operations per minute
deleteAttempts: 10, // Delete operations per minute
fetchAttempts: 90 // Fetch/read operations per minute
}-
IP-Based Limiting (
ipRateLimitmiddleware):- Applied to all public endpoints
- Pre-request check using IP address
- 90 fetches per minute per IP
-
User-Based Limiting (
userRateLimitmiddleware):- Applied to authenticated routes
- Per-user per-minute limits
- Enforced after authentication
-
Authentication Endpoint Limiting (
proxy.ts):- Special rate limiting for sign-in endpoints
- 10 attempts per minute per IP+cookie combination
- Includes countdown feedback to users
-
Server Actions Limiting (
Guardfunction):- Two-stage validation in server actions
- Stage 1: IP-based pre-check (no DB required)
- Stage 2: User authentication + per-user rate limiting
- Graceful error handling with custom messages
const createLimiter = new Ratelimit({
redis,
limiter: Ratelimit.slidingWindow(20, "1m") // 20 per minute
});SpendSense uses tRPC (Type-safe RPC) as the primary data-fetching mechanism, providing end-to-end type safety from backend to frontend.
appRouter
βββ txn (Transaction Router)
β βββ list (paginated transactions with cursor)
β βββ getById (single transaction)
β βββ summary (income/expense summary by currency)
β βββ monthlyStats (monthly trends)
β βββ categoryBreakdown (expenses by category)
β βββ reportDashboard (comprehensive report data)
β βββ search (full-text description search)
βββ category (Category Router)
βββ list (paginated categories)
βββ getMany (get multiple by IDs)
1. Public Procedure (with IP rate limiting):
rateLimitedProcedure = publicProcedure.use(ipRateLimit)2. Protected Procedure (with auth + rate limiting):
protectedProcedure = rateLimitedProcedure
.use(authMiddleware)
.use(userRateLimit)Primary endpoint: /api/trpc/[trpc] (dynamic routing)
HTTP Methods: GET and POST (batch requests supported)
Response Format: SuperJSON serialization for complex types (Date, Map, Set, etc.)
// Frontend client
api.createClient({
links: [httpBatchLink({
transformer: superjson,
url: '/api/trpc'
})]
})- Create: Add expenses/income with categories, payment methods, currency
- Read: Paginated list with cursor-based pagination
- Update: Modify existing transactions
- Delete: Remove transactions
- Limits: Max 700 transactions per user
- Create: Custom expense categories with colors
- Update: Modify category names and colors
- Delete: Remove categories (transactions remain but orphaned)
- Limits: Max 25 categories per user
- Summary Cards: Total income/expense by currency
- Monthly Trends: Line chart showing cumulative balance over time
- Category Breakdown: Pie chart showing expense distribution
- Payment Methods: Bar chart showing spending by payment method
- Net Worth Tracking: Running balance calculation
- Date range filtering (from/to dates)
- Transaction type filtering (EXPENSE/INCOME)
- Payment method filtering
- Category filtering
- Description search (full-text ilike query)
- Currency selection
- Cursor-based pagination for efficient large datasets
- Supports bidirectional navigation (next/prev)
- Configurable page size (5-20 items)
- Maintains sort order and filters
- Support for multiple currencies per user
- INR as default
- Popular currencies: USD, EUR, GBP, AUD, CAD, NZD, SGD, HKD, JPY, INR
- Export transactions as JSON
- Timestamped download filenames
Layout Components:
Header.tsx- Navigation with auth button, theme toggleFooter.tsx- Social links and copyrightLandingPage.tsx- Public landing page with features showcase
Transaction Management:
txn-table/- Transaction CRUD operationscreate-txn.tsx- Add transaction form dialogupdate-txn.tsx- Edit transaction formdelete-txn.tsx- Delete confirmation dialogcolumns.tsx- Table column definitionstxn-table.tsx- Main table component
Filtering & Pagination:
txn-date-range-filter.tsx- Date pickertxn-limit-filter.tsx- Row count selectorpopular-currencies.ts- Currency selection
Reporting/Analytics:
reports/- Dashboard componentsreports-dashboard-client.tsx- Main dashboardtxn-monthly-chart.tsx- Monthly trends line charttxn-category-pie.tsx- Category breakdown pie charttxn-payment-bar.tsx- Payment method bar chartreport-networth-line.tsx- Net worth trackingtxn-summary-cards.tsx- Summary statistics
Category Management:
category-table/- Category CRUDcreate-cat.tsx- Add categoryupdate-cat.tsx- Edit categorydelete-cat.tsx- Delete category
Auth Components:
auth/- Authentication UIsign-in.tsx- Sign in formauth-button.tsx- Auth state button
Zustand Store (app/store/categories-store.ts):
useCategoryStore {
categories: Record<string, CategoryMeta>
categoriesArr: CategoryMeta[]
hydrate(cats) - Initialize from server
remove(id) - Delete category
upsert(cat) - Add/update category
clear() - Reset store
}Query Caching:
- TanStack React Query with 30s stale time
- SuperJSON serialization/deserialization
- Automatic refetching on window focus
Transaction Actions:
createTxnAction - Create expense/income
updateTxnAction - Modify transaction
deleteTxnAction - Remove transactionCategory Actions:
createCategoryAction - Create custom category
updateCategoryAction - Modify category
deleteCategoryAction - Remove categoryUser Actions:
deleteUserAction - Account deletionhandleAction()- Generic server action wrapper- FormData parsing
- Zod schema validation
- Error handling
- Cache revalidation
Guard()- Authentication + rate limiting wrapper- IP-based pre-check
- Optional authentication
- Per-user rate limiting
- Overloaded signatures for type safety
- Auto-generated from Drizzle schema via
drizzle-zod - Custom validation rules (amount limits, category limits)
- Nested object validation
# NextAuth
NEXTAUTH_SECRET=your-secret-key-here
NEXTAUTH_URL=http://localhost:3000
# OAuth Providers
AUTH_GITHUB_ID=your_github_oauth_id
AUTH_GITHUB_SECRET=your_github_oauth_secret
AUTH_GOOGLE_ID=your_google_oauth_id
AUTH_GOOGLE_SECRET=your_google_oauth_secret
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/spendsense
# Redis (Upstash)
UPSTASH_REDIS_REST_URL=your_upstash_redis_url
UPSTASH_REDIS_REST_TOKEN=your_upstash_token
# Deployment (optional)
VERCEL_URL=your_vercel_url
LOCAL_URL=http://localhost:3000dialect: "postgresql"
schema: "./lib/db/schema.ts"
out: "./migrations"- PostgreSQL service
- Volume persistence
- Environment configuration
GET/POST /api/auth/signin- Sign in endpointGET/POST /api/auth/callback/:provider- OAuth callbackGET/POST /api/auth/session- Get current sessionPOST /api/auth/signout- Sign out
GET/POST /api/trpc/[...trpc]- Dynamic tRPC routes- Batch request support
- Automatic type inference
- Full NextAuth v5 route handling
Drizzle ORM manages schema migrations with:
- SQL migration files in
/migrations - Version control for schema changes
- Type-safe schema definitions
Per-user resource limits enforce fair usage:
| Resource | Limit | Purpose |
|---|---|---|
| Categories | 25 | Organize expenses |
| Transactions | 700 | Track expenses |
| Transaction Amount | βΉ5,000 | Prevent data entry errors |
| Create Operations | 20/min | Rate limit mutations |
| Update Operations | 10/min | Rate limit mutations |
| Delete Operations | 10/min | Rate limit mutations |
| Fetch Operations | 90/min | Rate limit queries |
| Login Attempts | 10/min | Prevent brute force |
1. User fills form β React component state
β
2. Form submission β createTxnAction (server action)
β
3. Guard() checks: IP rate limit + Auth + User rate limit
β
4. Zod validation against txnInsertSchema
β
5. Check user transaction count vs. 700 limit
β
6. Insert into PostgreSQL via Drizzle ORM
β
7. Revalidate cache ("/")
β
8. Return result to client
β
9. Toast notification (success/error)
β
10. UI updates via TanStack Query re-fetch
| Library | Purpose |
|---|---|
next-auth |
OAuth2 authentication |
drizzle-orm |
Type-safe SQL ORM |
@trpc/server |
Backend RPC framework |
@trpc/react-query |
Frontend RPC client |
@tanstack/react-query |
Async state management |
zustand |
Client state management |
zod |
Schema validation |
@upstash/ratelimit |
Rate limiting with Redis |
@upstash/redis |
Redis client |
shadcn/ui |
Pre-built UI components |
tailwindcss |
Utility CSS framework |
recharts |
Charts and visualizations |
sonner |
Toast notifications |
superjson |
Complex type serialization |
- Type Safety: Full TypeScript with strict mode
- Validation: Zod schemas for all inputs
- Error Handling: Custom
AppErrorclasses with specific codes - Rate Limiting: Multi-layer protection (IP + User + Auth)
- Security: Server-only modules (
"use server"), middleware validation - Performance: Cursor-based pagination, query caching, index optimization
- Code Organization: Clear separation between routers, actions, schemas, and components
- Testing: ESLint configuration for code consistency
spendsense/
βββ app/ # Next.js App Router
β βββ page.tsx # Home page (landing/dashboard)
β βββ layout.tsx # Root layout with providers
β βββ api/
β β βββ auth/ # NextAuth routes
β β β βββ [...nextauth]/route.ts
β β βββ trpc/ # tRPC API route
β β βββ [trpc]/route.ts
β βββ actions/ # Server actions
β β βββ txn.actions.ts # Transaction mutations
β β βββ category.actions.ts # Category mutations
β β βββ user.actions.ts # User mutations
β β βββ action-helper.ts # Helper utilities
β βββ store/ # Client state
β βββ categories-store.ts # Zustand store
β
βββ components/ # React components
β βββ Header.tsx # Navigation header
β βββ Footer.tsx # Footer
β βββ LandingPage.tsx # Public landing page
β βββ config.ts # App configuration
β βββ auth/ # Auth components
β β βββ sign-in.tsx
β β βββ auth-button.tsx
β βββ txn-table/ # Transaction components
β β βββ txn-table.tsx
β β βββ create-txn.tsx
β β βββ update-txn.tsx
β β βββ delete-txn.tsx
β β βββ columns.tsx
β β βββ filters/
β βββ category-table/ # Category components
β β βββ cat-table.tsx
β β βββ create-cat.tsx
β β βββ update-cat.tsx
β β βββ delete-cat.tsx
β βββ reports/ # Analytics components
β β βββ reports-dashboard-client.tsx
β β βββ txn-monthly-chart.tsx
β β βββ txn-category-pie.tsx
β β βββ report-networth-line.tsx
β β βββ txn-summary-cards.tsx
β βββ ui/ # shadcn/ui components
β βββ button.tsx
β βββ dialog.tsx
β βββ select.tsx
β βββ ...
β
βββ lib/ # Utility & core logic
β βββ db/ # Database layer
β β βββ index.ts # Database client
β β βββ schema.ts # Drizzle schema
β β βββ relations.ts # Entity relations
β β βββ zod-schema.ts # Zod validation
β βββ trpc/ # tRPC configuration
β β βββ init.ts # tRPC initialization
β β βββ client.ts # Frontend client
β β βββ server.ts # Server caller
β β βββ provider.tsx # TRPCProvider
β β βββ procedures.ts # Custom procedures
β β βββ middleware/ # Custom middleware
β β β βββ auth-middleware.ts
β β β βββ rate-limit-middleware.ts
β β βββ routers/ # API routers
β β βββ _app.ts # Main router
β β βββ txn.router.ts # Transaction queries
β β βββ category.router.ts # Category queries
β βββ rate-limit/ # Rate limiting
β β βββ rate-limit.ts # Limiters
β β βββ redis.ts # Redis client
β βββ txn-service/ # Transaction utilities
β β βββ txn.service.ts
β β βββ txn.pagination.schema.ts
β βββ category-service/ # Category utilities
β β βββ category.service.ts
β β βββ category.pagination.schema.ts
β βββ AppError.ts # Custom error classes
β βββ formDataUtils.ts # Form utilities
β
βββ auth.ts # NextAuth configuration
βββ auth.config.ts # OAuth providers
βββ proxy.ts # Middleware
βββ middleware.ts # Next.js middleware (if exists)
β
βββ migrations/ # Database migrations
βββ public/ # Static assets
βββ scripts/ # Build scripts
β
βββ package.json
βββ tsconfig.json
βββ next.config.ts
βββ drizzle.config.ts
βββ docker-compose.yml
βββ .env.example
// Queries
api.txn.list.useQuery(input) // Paginated transactions
api.txn.getById.useQuery({ id }) // Single transaction
api.txn.summary.useQuery(options) // Income/expense summary
api.txn.monthlyStats.useQuery() // Monthly trends
api.txn.categoryBreakdown.useQuery() // Expense by category
api.txn.reportDashboard.useQuery() // Full dashboard data
api.txn.search.useQuery({ q }) // Description search// Queries
api.category.list.useQuery(input) // Paginated categories
api.category.getMany.useQuery(ids) // Multiple categories// Transactions
await createTxnAction(formData)
await updateTxnAction(formData)
await deleteTxnAction(formData)
// Categories
await createCategoryAction(formData)
await updateCategoryAction(formData)
await deleteCategoryAction(formData)
// Users
await deleteUserAction(formData){
"items": [
{
"id": "uuid",
"userId": "uuid",
"txnType": "EXPENSE",
"categoryId": "uuid",
"amountPaise": 50000,
"currency": "INR",
"description": "Grocery shopping",
"paymentMethod": "UPI",
"createdAt": "2026-02-05T10:30:00Z",
"updatedAt": "2026-02-05T10:30:00Z"
}
],
"nextCursor": {
"createdAt": "2026-02-05T10:30:00Z",
"id": "uuid",
"direction": "next"
},
"prevCursor": null,
"hasMore": true
}{
"summary": {
"income": 50000,
"expense": 30000
},
"trend": [
{ "date": "2026-02-05", "income": 0, "expenses": 30000, "balance": -30000 }
],
"categories": [
{ "name": "Food", "value": 25000, "fill": "#ef4444" }
],
"payments": [
{ "method": "UPI", "total": 30000 }
]
}- Color Scheme: Dark-first with light mode support
- Typography: Clear hierarchy with accessible font sizes
- Spacing: Consistent spacing scale (4px base)
- Components: 20+ pre-built shadcn/ui components
- Hero section with CTA buttons
- Feature highlights (3 main features)
- Social proof section
- Call-to-action buttons
- Responsive grid layout
- Transaction management table
- Sortable columns (date, amount, category, payment method)
- Inline actions (edit, delete)
- Pagination controls
- Export functionality
- Analytics charts
- Monthly trend line chart
- Category pie chart
- Payment method bar chart
- Net worth line chart
- Summary cards
- Total income
- Total expense
- Net balance
- Add/Edit transaction modal
- Add/Edit category modal
- Delete confirmation dialogs
- Field validation with error messages
- Mobile-first approach
- Breakpoints: sm, md, lg, xl, 2xl
- Touch-friendly button sizes (min 44px)
- Collapsible navigation on mobile
# Development
bun run dev # Start dev server
# Database
bun run db:push # Push schema to DB
bun run db:migrate # Run migrations
bun run db:studio # Open Drizzle Studio
# Building
bun run build # Build for production
bun start # Start production server
# Linting
bun run lint # Run ESLint- Server Components (default): Database queries, auth checks
- Client Components: (
"use client") Interactivity, state - Server Actions (
"use server"): Form submissions, mutations
- Schema Validation: Zod schemas for all inputs
- Database Types: Auto-generated from Drizzle schema
- API Types: Inferred from tRPC routers
- Component Props: Strict TypeScript interfaces
try {
const session = await auth()
if (!session?.user?.id) throw new UnauthorizedError()
// ... operation
} catch (err) {
if (err instanceof AppError) {
return { ok: false, message: err.message }
}
}- Indexes: On userId, createdAt, txnType, paymentMethod, categoryId
- Query Optimization: Only fetch required fields
- Connection Pooling: Max 5 connections per instance
- Code Splitting: Automatic route-based splitting
- Image Optimization: Next.js Image component
- CSS: Tailwind's tree-shaking
- Caching: 30-second stale time for queries
- Sliding Window Algorithm: Smooth rate enforcement
- IP-based Pre-check: No DB lookup for initial check
- User-based Limiting: Per-user per-minute quotas
User visits app
β
Checks session (auth())
β
No session? β Show Landing Page
β
User clicks "Sign In"
β
Redirects to /api/auth/signin
β
OAuth Provider Selection (GitHub/Google)
β
User authenticates with provider
β
Provider callback β /api/auth/callback/[provider]
β
Create user in DB (if new)
β
Create session
β
Redirect to dashboard
β
Show authenticated UI
- Push to GitHub
git add .
git commit -m "Initial commit"
git push origin main- Connect to Vercel
- Visit https://vercel.com/import
- Select repository
- Set environment variables
- Configure environment variables in Vercel:
NEXTAUTH_SECRET
NEXTAUTH_URL
AUTH_GITHUB_ID & SECRET
AUTH_GOOGLE_ID & SECRET
DATABASE_URL
UPSTASH_REDIS_REST_URL & TOKEN
- Deploy
# Automatic on push to main
# Or manual from Vercel dashboarddocker run -p 3000:3000 \
-e DATABASE_URL=postgresql://... \
-e UPSTASH_REDIS_REST_URL=... \
spendsense
git clone https://github.com/YOUR_USERNAME/spendsense.git
cd spendsense# Check DATABASE_URL
echo $DATABASE_URL
# Verify PostgreSQL is running
psql -U postgres -h localhost -d spendsense# Check Upstash credentials
echo $UPSTASH_REDIS_REST_URL
# Test Redis connection
curl $UPSTASH_REDIS_REST_URL/ping- Ensure redirect URI matches
NEXTAUTH_URL - Check OAuth credentials are correct
- Verify provider apps are active
# Clear cache and reinstall
rm -rf .next node_modules
bun install
bun run buildDhruv Charne
- GitHub: @DHRUVCHARNE
- Twitter/X: @Dhruv4ne
- LinkedIn: Dhruv Charne
- Portfolio: dhruv4ne-portfolio.vercel.app
This project is licensed under the MIT License - see the LICENSE file for details.
You are free to:
- β Use commercially
- β Modify the code
- β Distribute the software
- β Use privately
- Vercel - Hosting platform
- Next.js - React framework
- Shadcn/ui - UI components
- Drizzle Team - ORM library
- tRPC - Type-safe RPC
- Open source community
- Lines of Code: ~5,000+
- Components: 20+
- API Endpoints: 10+
- Database Tables: 5+ (including NextAuth)
- Build Time: ~2 minutes
- Lighthouse Score: 95+
---
| Link | URL |
|---|---|
| Live Demo | https://spendsense-sepia.vercel.app/ |
| GitHub Repo | https://github.com/DHRUVCHARNE/spendsense |
| Issue Tracker | https://github.com/DHRUVCHARNE/spendsense/issues |
| Discussions | https://github.com/DHRUVCHARNE/spendsense/discussions |
SpendSense - Take control of your money π°
Made with β€οΈ by Dhruv Charne






