A full-stack expense tracking web application built with PostgreSQL, Express, React, and Node.js (PERN Stack).
- Features
- Technology Stack
- Database Schema
- Project Structure
- Getting Started
- API Documentation
- Environment Variables
- Development
- Deployment
- User Authentication: Secure JWT-based authentication with bcrypt password hashing
- Account Management: Multiple accounts (cash, bank, credit card) with balance tracking
- Transaction Tracking: Record income and expenses with categories, descriptions, and dates
- Category Management: Custom income and expense categories per user
- Budget Management: Set budget limits per category with date ranges
- Budget Alerts: Automatic alerts when approaching or exceeding budget limits
- Recurring Transactions: Automate regular income/expenses with configurable intervals (daily, weekly, monthly, yearly)
- Transaction Tags: Tag transactions for better organization and filtering
- Attachments: Upload and store receipts or related documents
- Dashboard: Overview of account balances, recent transactions, and budget status
- Reporting: Filter and analyze transactions by date range, category, account, and tags
- Runtime: Node.js
- Framework: Express.js 5.x
- Database: PostgreSQL
- Authentication: JWT (jsonwebtoken) + bcryptjs
- Security: Helmet, CORS, express-validator
- Logging: Morgan
- Environment: dotenv
- Cookie Parsing: cookie-parser
- Framework: React 19.x
- Build Tool: Vite 5.x
- Routing: React Router DOM 7.x
- HTTP Client: Axios 1.x
- Styling: CSS (customizable to Tailwind or Material-UI)
- Testing: Vitest
- Server: Nodemon for hot reloading
- Testing: Vitest (frontend), Jest-compatible
- Package Manager: npm
The application uses PostgreSQL with the following main tables:
Stores user account information with hashed passwords.
- Fields:
id,full_name,email,password_hash,created_at,updated_at
User's financial accounts (bank, cash, credit card) with balance tracking.
- Fields:
id,user_id,name,type,balance,created_at,updated_at
Income and expense categories customizable per user.
- Fields:
id,user_id,name,type(income/expense),created_at - Unique constraint on
user_id + name
All financial transactions linked to accounts and categories.
- Fields:
id,user_id,account_id,category_id,amount,type(income/expense),description,transaction_date,created_at - Indexed on
user_id,account_id,category_id
Scheduled recurring income/expenses with interval settings.
- Fields:
id,user_id,account_id,category_id,amount,type,interval(daily/weekly/monthly/yearly),next_run_date,description,created_at
Budget limits per category with start/end dates.
- Fields:
id,user_id,category_id,amount_limit,start_date,end_date,created_at
Alerts triggered when budgets reach certain thresholds.
- Fields:
id,budget_id,alert_type(50%, 75%, 100%),message,created_at
Custom tags for organizing transactions.
- Fields:
id,user_id,name,created_at - Unique constraint on
user_id + name
Many-to-many relationship between transactions and tags.
- Fields:
transaction_id,tag_id(composite primary key)
File uploads (receipts, documents) linked to transactions.
- Fields:
id,transaction_id,file_url,created_at - Indexed on
transaction_id
Full schema available in: expense.postgre.sql
Expense/
βββ client/ # React frontend (Vite)
β βββ public/ # Static assets
β βββ src/
β β βββ assets/ # Images, fonts, etc.
β β βββ components/ # Reusable components
β β βββ context/ # React context providers
β β βββ hooks/ # Custom React hooks
β β βββ pages/ # Page components
β β βββ routes/ # Route definitions
β β βββ services/ # API service layer
β β βββ utils/ # Utility functions
β β βββ App.js # Main app component
β β βββ App.css # App styles
β β βββ index.css # Global styles
β β βββ main.jsx # Entry point
β βββ index.html # HTML template
β βββ .env.example # Environment template
β βββ .gitignore
β βββ package.json
β βββ vite.config.js # Vite configuration
β
βββ server/ # Node.js backend (Express)
β βββ src/
β β βββ config/ # Configuration files
β β β βββ database.js # PostgreSQL connection pool
β β βββ controllers/ # Route controllers
β β βββ middleware/ # Custom middleware
β β β βββ auth.js # JWT authentication
β β β βββ errorHandler.js # Error handling
β β βββ models/ # Database models
β β βββ routes/ # API routes
β β βββ services/ # Business logic
β β βββ utils/ # Utility functions
β β βββ validations/ # Input validation schemas
β β βββ app.js # Express app setup
β βββ .env.example # Environment template
β βββ .gitignore
β βββ index.js # Server entry point
β βββ package.json
β
βββ expense.postgre.sql # PostgreSQL schema
βββ .gitignore
βββ README.md # This file
- Node.js (v18 or higher)
- PostgreSQL (v12 or higher)
- npm (comes with Node.js)
-
Clone the repository
git clone <repository-url> cd Expense
-
Setup PostgreSQL Database
# Create database createdb expense_tracker # Run schema psql -d expense_tracker -f expense.postgre.sql
-
Setup Server
cd server # Copy environment template cp .env.example .env # Edit .env with your database credentials # Then install dependencies npm install
-
Setup Client
cd ../client # Copy environment template cp .env.example .env # Install dependencies npm install
-
Start the backend server (from
server/directory)npm run dev
Server runs on http://localhost:5000
-
Start the frontend (from
client/directory, in a new terminal)npm run dev
Client runs on http://localhost:3000
-
Access the application
- Frontend: http://localhost:3000
- Backend API: http://localhost:5000
- Health Check: http://localhost:5000/api/health
http://localhost:5000/api
Most endpoints require JWT authentication. Include the token in the Authorization header:
Authorization: Bearer <your_jwt_token>
POST /api/auth/register- Register new user{ "full_name": "John Doe", "email": "john@example.com", "password": "secure123" }POST /api/auth/login- Login user{ "email": "john@example.com", "password": "secure123" }POST /api/auth/logout- Logout userPOST /api/auth/refresh- Refresh JWT token
GET /api/users/me- Get current user profilePUT /api/users/me- Update user profile
GET /api/accounts- Get all user accountsPOST /api/accounts- Create new account{ "name": "Main Bank", "type": "bank", "balance": 5000.0 }GET /api/accounts/:id- Get account by IDPUT /api/accounts/:id- Update accountDELETE /api/accounts/:id- Delete account
GET /api/categories- Get all categoriesPOST /api/categories- Create category{ "name": "Groceries", "type": "expense" }PUT /api/categories/:id- Update categoryDELETE /api/categories/:id- Delete category
GET /api/transactions- Get transactions (with filters)- Query params:
?from=2024-01-01&to=2024-12-31&category_id=1&account_id=1&type=expense
- Query params:
POST /api/transactions- Create transaction{ "account_id": 1, "category_id": 2, "amount": 150.5, "type": "expense", "description": "Weekly groceries", "transaction_date": "2024-11-29" }GET /api/transactions/:id- Get transaction by IDPUT /api/transactions/:id- Update transactionDELETE /api/transactions/:id- Delete transaction
GET /api/budgets- Get all budgetsPOST /api/budgets- Create budget{ "category_id": 2, "amount_limit": 500.0, "start_date": "2024-11-01", "end_date": "2024-11-30" }PUT /api/budgets/:id- Update budgetDELETE /api/budgets/:id- Delete budgetGET /api/budgets/:id/status- Check budget status
GET /api/recurring- Get recurring transactionsPOST /api/recurring- Create recurring transaction{ "account_id": 1, "category_id": 3, "amount": 1200.0, "type": "income", "interval": "monthly", "next_run_date": "2024-12-01", "description": "Monthly salary" }PUT /api/recurring/:id- Update recurring transactionDELETE /api/recurring/:id- Delete recurring transaction
GET /api/tags- Get all tagsPOST /api/tags- Create tagDELETE /api/tags/:id- Delete tag
GET /api/reports/summary- Get financial summary- Query params:
?start_date=2024-11-01&end_date=2024-11-30
- Query params:
GET /api/reports/by-category- Category breakdownGET /api/reports/by-account- Account-wise reportGET /api/reports/trends- Spending trends over time
POST /api/attachments- Upload attachment (receipt/document)DELETE /api/attachments/:id- Delete attachment
# Server Configuration
PORT=5000
NODE_ENV=development
# Database Configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=expense_tracker
DB_USER=postgres
DB_PASSWORD=your_password_here
# JWT Configuration
JWT_SECRET=your_jwt_secret_key_here
JWT_EXPIRE=7d
# CORS Configuration
CORS_ORIGIN=http://localhost:3000# API Configuration
VITE_API_URL=http://localhost:5000/api
# App Configuration
VITE_APP_NAME=Expense Trackernpm start # Start production server
npm run dev # Start development server with nodemon
npm test # Run testsnpm run dev # Start development server (Vite)
npm run build # Build for production
npm run preview # Preview production build
npm test # Run tests (Vitest)- Controllers: Handle HTTP requests/responses, call services
- Services: Contain business logic, interact with models
- Models: Database queries and data access layer
- Middleware: Request processing (auth, validation, error handling)
- Validations: Input validation schemas using express-validator
- Routes: Define API endpoints and connect to controllers
- Database: Add tables/columns in
expense.postgre.sql - Backend:
- Create model in
server/src/models/ - Create service in
server/src/services/ - Create controller in
server/src/controllers/ - Add routes in
server/src/routes/ - Add validation in
server/src/validations/
- Create model in
- Frontend:
- Create service in
client/src/services/ - Create components in
client/src/components/ - Create pages in
client/src/pages/ - Add routes in
client/src/routes/
- Create service in
- β Passwords hashed with bcryptjs (salt rounds: 10)
- β JWT tokens for stateless authentication
- β Helmet for security headers
- β CORS configured with specific origin
- β Input validation with express-validator
- β SQL injection prevention (parameterized queries)
- β Environment variables for secrets
- β Error handling middleware (no sensitive data exposed)
- β Cookie parsing with secure options
- β Morgan for request logging
- Set
NODE_ENV=production - Use strong, unique
JWT_SECRET(minimum 32 characters) - Configure PostgreSQL with strong credentials
- Enable HTTPS/SSL certificates
- Set up automated database backups
- Configure CORS with production domain
- Use process manager (PM2, Docker)
- Set up logging and monitoring (e.g., Winston, Sentry)
- Optimize database with proper indexes
- Build frontend for production (
npm run build) - Enable rate limiting for API endpoints
- Set up CDN for static assets
- Configure reverse proxy (Nginx)
- Railway (recommended for PostgreSQL + Node.js)
- Render
- Heroku
- DigitalOcean App Platform
- AWS EC2 + RDS
- Vercel (recommended for Vite/React)
- Netlify
- AWS S3 + CloudFront
- Cloudflare Pages
- Railway PostgreSQL
- Supabase
- AWS RDS PostgreSQL
- DigitalOcean Managed Databases
- ElephantSQL
# Build client
cd client
npm run build
# The build folder can be served by backend or deployed separately
# For separate deployment, upload 'build' folder to your hosting service
# Run server in production
cd ../server
NODE_ENV=production npm startcd server
npm testcd client
npm test- Unit tests for services and utilities
- Integration tests for API endpoints
- Component tests for React components
- E2E tests for critical user flows
This project is licensed under the ISC License.
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Database connection failed
- Verify PostgreSQL is running
- Check credentials in
.env - Ensure database exists (
createdb expense_tracker)
Port already in use
- Change
PORTin server.env - Kill process using the port
Frontend can't connect to API
- Verify backend is running
- Check
VITE_API_URLin client.env - Ensure CORS is properly configured
Vite build errors
- Delete
node_modulesand reinstall - Clear Vite cache:
rm -rf node_modules/.vite
For issues and questions:
- Open an issue in the repository
- Check existing issues for solutions
- Review the documentation
Future enhancements planned:
- Mobile responsive design
- Dark mode theme
- Export data to CSV/PDF
- Multi-currency support
- Shared household accounts
- Bank account integration (Plaid)
- Budget recommendations (ML)
- Mobile app (React Native)
- Email notifications
- Data visualization charts
- Scheduled reports
- Two-factor authentication
Happy Tracking! π°π