Skip to content

rgaspary/PennyWise

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PennyWise - Expense Tracker

A comprehensive full-stack expense tracker application built with React, TypeScript, Express.js, and SQLite. Track your finances, set budgets, visualize spending patterns, and export your data.

Tech Stack TypeScript Express SQLite

Features

Core Functionality

  • Transaction Management: Add, edit, and delete income/expense transactions
  • Category System: Predefined and custom categories for better organization
  • Budget Tracking: Set budgets by category or overall spending
  • Data Visualization: Interactive charts showing spending trends and patterns
  • Monthly Comparisons: Compare income and expenses across multiple months
  • Export Functionality: Export transaction data to CSV or JSON formats
  • Theme Toggle: Light/Dark mode with automatic system preference detection

Technical Highlights

  • Monorepo Architecture: Unified codebase with shared types between frontend and backend
  • Type Safety: End-to-end TypeScript for better developer experience
  • RESTful API: Well-structured API endpoints following REST principles
  • Component Organization: Structured folders with separated concerns (logic vs. styling)
  • Theme Support: Light/Dark mode with system preference detection and session persistence
  • Responsive Design: Mobile-friendly interface using Styled Components
  • State Management: React Context API for efficient state handling
  • Data Validation: Zod schemas for consistent validation across the stack

Tech Stack

Frontend

  • React 18 - UI library
  • TypeScript - Type safety
  • Vite - Build tool and dev server
  • Styled Components - CSS-in-JS styling
  • React Router - Client-side routing
  • Recharts - Data visualization
  • Axios - HTTP client

Backend

  • Express.js - Web framework
  • TypeScript - Type safety
  • SQLite - Database
  • better-sqlite3 - SQLite driver
  • Zod - Schema validation
  • csv-stringify - CSV export

Project Structure

PennyWise/
├── packages/
│   ├── client/          # React frontend
│   │   ├── src/
│   │   │   ├── components/
│   │   │   │   ├── common/           # Reusable UI components
│   │   │   │   │   ├── Button/
│   │   │   │   │   │   ├── index.tsx    # Button component
│   │   │   │   │   │   └── styled.ts    # Button styled components
│   │   │   │   │   ├── Card/
│   │   │   │   │   │   ├── index.tsx    # Card component
│   │   │   │   │   │   └── styled.ts    # Card styled components
│   │   │   │   │   ├── Input/
│   │   │   │   │   │   ├── index.tsx    # Input components
│   │   │   │   │   │   └── styled.ts    # Input styled components
│   │   │   │   │   ├── Modal/
│   │   │   │   │   │   ├── index.tsx    # Modal component
│   │   │   │   │   │   └── styled.ts    # Modal styled components
│   │   │   │   │   ├── ThemeToggle/
│   │   │   │   │   │   ├── index.tsx    # Theme toggle component
│   │   │   │   │   │   └── styled.ts    # Toggle styled components
│   │   │   │   │   └── index.tsx        # Common components exports
│   │   │   │   ├── layout/           # Layout components
│   │   │   │   │   ├── Header/
│   │   │   │   │   │   ├── index.tsx    # Header component
│   │   │   │   │   │   └── styled.ts    # Header styled components
│   │   │   │   │   └── index.tsx        # Layout exports
│   │   │   │   └── index.tsx         # All components exports
│   │   │   ├── context/              # React Context providers
│   │   │   │   ├── AppContext.tsx
│   │   │   │   ├── BudgetContext.tsx
│   │   │   │   ├── ThemeContext.tsx
│   │   │   │   └── TransactionContext.tsx
│   │   │   ├── pages/                # Page components
│   │   │   │   ├── Dashboard/
│   │   │   │   │   ├── index.tsx        # Dashboard page
│   │   │   │   │   └── styled.ts        # Dashboard styled components
│   │   │   │   ├── Transactions/
│   │   │   │   │   ├── index.tsx        # Transactions page
│   │   │   │   │   └── styled.ts        # Transactions styled components
│   │   │   │   ├── Budgets/
│   │   │   │   │   ├── index.tsx        # Budgets page
│   │   │   │   │   └── styled.ts        # Budgets styled components
│   │   │   │   ├── Analytics/
│   │   │   │   │   ├── index.tsx        # Analytics page
│   │   │   │   │   └── styled.ts        # Analytics styled components
│   │   │   │   └── index.tsx         # All pages exports
│   │   │   ├── services/             # API client services
│   │   │   │   ├── api.ts
│   │   │   │   ├── analyticsService.ts
│   │   │   │   ├── budgetService.ts
│   │   │   │   ├── categoryService.ts
│   │   │   │   ├── exportService.ts
│   │   │   │   └── transactionService.ts
│   │   │   ├── styles/               # Global styles & shared styled components
│   │   │   │   ├── GlobalStyles.ts
│   │   │   │   ├── styled.ts         # Shared styled components (Container, Grid, etc.)
│   │   │   │   └── theme.ts          # Light/Dark theme definitions
│   │   │   ├── App.tsx
│   │   │   └── main.tsx
│   │   └── package.json
│   │
│   ├── server/          # Express backend
│   │   ├── src/
│   │   │   ├── config/              # Configuration
│   │   │   ├── controllers/         # Route handlers
│   │   │   ├── services/            # Business logic
│   │   │   ├── repositories/        # Data access layer
│   │   │   ├── routes/              # API routes
│   │   │   ├── middleware/          # Express middleware
│   │   │   └── database/            # Migrations & seeds
│   │   └── package.json
│   │
│   └── shared/          # Shared types & validators
│       ├── src/
│       │   ├── types/               # TypeScript interfaces
│       │   ├── validators/          # Zod schemas
│       │   └── constants/           # Shared constants
│       └── package.json
│
└── package.json         # Root package with workspaces

Component Structure Pattern

Each component follows a consistent structure:

ComponentName/
├── index.tsx    # Component logic and exports
└── styled.ts    # Styled-components for this component

This pattern provides:

  • Clear separation between logic and styling
  • Easy navigation with consistent naming
  • Reusability through centralized exports
  • Maintainability with isolated concerns

Getting Started

Prerequisites

  • Node.js >= 18.0.0
  • npm >= 9.0.0

Installation

Important for WSL Users: This project requires native Linux Node.js. If you're using WSL with Windows npm, you'll encounter symlink errors. Follow the installation steps below to set up Node.js properly in WSL.

  1. Install Node.js in WSL using nvm

    If you don't have nvm installed:

    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

    Load nvm and install Node.js:

    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
    nvm install 20
    nvm use 20

    Add nvm to your ~/.bashrc for future sessions:

    echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.bashrc
    echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> ~/.bashrc
    source ~/.bashrc
  2. Navigate to the project directory

    cd PennyWise
  3. Install dependencies

    Install dependencies for each package:

    # Install shared package dependencies
    cd packages/shared && npm install && cd ../..
    
    # Install server dependencies
    cd packages/server && npm install && cd ../..
    
    # Install client dependencies
    cd packages/client && npm install && cd ../..
    
    # Install root dependencies
    npm install
  4. Build the shared package

    cd packages/shared && npm run build && cd ../..
  5. Set up environment variables

    The .env file should already exist in packages/server/ with these values:

    PORT=3000
    NODE_ENV=development
    CORS_ORIGIN=http://localhost:5173
    

Running the Application

Development Mode (Recommended)

Run both frontend and backend concurrently:

npm run dev

This will start:

For WSL users: Make sure you've loaded nvm in your current session:

export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

Run Separately

Backend only:

npm run server

Frontend only:

npm run client

Access the Application

Once running, open your browser and navigate to:

Building for Production

Build all packages (shared package is built first automatically):

npm run build

Build specific packages:

# Build shared package (must be built first)
cd packages/shared && npm run build

# Build server
npm run build:server

# Build client
npm run build:client

Note: Always build the shared package before building server or client packages.

API Documentation

Base URL

http://localhost:3000/api/v1

Endpoints

Transactions

  • GET /transactions - Get all transactions (with filters)
  • POST /transactions - Create a transaction
  • PUT /transactions/:id - Update a transaction
  • DELETE /transactions/:id - Delete a transaction
  • GET /transactions/summary - Get transaction summary
  • GET /transactions/by-category - Get spending by category

Categories

  • GET /categories - Get all categories
  • POST /categories - Create custom category
  • PUT /categories/:id - Update custom category
  • DELETE /categories/:id - Delete custom category

Budgets

  • GET /budgets - Get all budgets
  • POST /budgets - Create a budget
  • PUT /budgets/:id - Update a budget
  • DELETE /budgets/:id - Delete a budget
  • GET /budgets/current - Get active budgets with progress

Analytics

  • GET /analytics/monthly-comparison - Monthly comparison data
  • GET /analytics/trends - Spending trends

Export

  • GET /export/csv - Export transactions as CSV
  • GET /export/json - Export transactions as JSON

Database

Schema

The application uses SQLite with the following tables:

categories

  • Default categories: Food & Dining, Transportation, Shopping, Entertainment, Bills & Utilities, Healthcare, Housing, Personal (expenses)
  • Income categories: Salary, Freelance, Investments, Other Income
  • Support for custom user-created categories

transactions

  • Links to categories
  • Stores amount, type (income/expense), description, and date
  • Indexed for performance

budgets

  • Can be category-specific or overall
  • Supports weekly, monthly, and yearly periods
  • Tracks progress automatically

Migrations & Seeds

On first run, the server will automatically:

  1. Create the database schema
  2. Seed default categories

The database file is created at: packages/server/src/database/pennywise.db

Features in Detail

Dashboard

  • Real-time summary of total income, expenses, and net balance
  • Active budget progress bars with visual indicators
  • Color-coded metrics (green for income, red for expenses)

Transactions

  • Full CRUD operations
  • Filter by date range, category, and type
  • Pagination support for large datasets
  • Quick add with modal form

Budgets

  • Create budgets for specific categories or overall spending
  • Real-time progress tracking
  • Visual alerts when budgets are exceeded
  • Support for different time periods (weekly, monthly, yearly)

Analytics

  • Monthly Comparison: Bar chart showing income vs expenses over 6 months
  • Spending Trends: Line chart visualizing financial trends
  • Category Breakdown: Pie chart showing expense distribution
  • Export Options: Download data in CSV or JSON format

Development

Code Organization

The project follows a clean architecture pattern:

Backend

  • Controllers: Handle HTTP requests/responses
  • Services: Business logic and orchestration
  • Repositories: Data access and database operations
  • Middleware: Request validation and error handling

Frontend

  • Components: Organized by feature/purpose with separation of concerns
    • Each component has its own folder with index.tsx (logic) and styled.ts (styles)
    • Common: Reusable UI components (Button, Card, Input, Modal, ThemeToggle)
    • Layout: Structural components (Header)
  • Context: React Context providers for global state management
  • Pages: Route-level components following the same folder structure
  • Services: API client functions for backend communication
  • Styles: Shared styled-components and theme configuration

Adding New Features

Backend:

  1. Add types in packages/shared/src/types/
  2. Add validation in packages/shared/src/validators/
  3. Create repository in packages/server/src/repositories/
  4. Create service in packages/server/src/services/
  5. Create controller in packages/server/src/controllers/
  6. Add routes in packages/server/src/routes/

Frontend:

  1. Create component folder in packages/client/src/components/common/ComponentName/
  2. Add component logic in index.tsx
  3. Add styled components in styled.ts
  4. Export component in the parent index.tsx
  5. Create frontend service (if needed) in packages/client/src/services/
  6. Use component in pages or other components

Example: Adding a new Button variant

# Component already exists, just update styled.ts
packages/client/src/components/common/Button/styled.ts

Example: Adding a new component

# Create folder and files
mkdir packages/client/src/components/common/NewComponent
touch packages/client/src/components/common/NewComponent/index.tsx
touch packages/client/src/components/common/NewComponent/styled.ts
# Export in parent index.tsx
echo "export { NewComponent } from './NewComponent';" >> packages/client/src/components/common/index.tsx

Troubleshooting

WSL Symlink Errors

If you see errors like EISDIR: illegal operation on a directory, symlink:

  • Cause: Using Windows npm in WSL instead of native Linux npm
  • Solution: Follow the nvm installation steps in the Installation section above

Node.js Command Not Found

If you see node: command not found:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

To make this permanent, add to ~/.bashrc:

echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.bashrc
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> ~/.bashrc

Module '@pennywise/shared' Not Found

If the server can't find the shared module:

cd packages/shared
npm run build
cd ../..

Port Already in Use

If port 3000 or 5173 is in use:

  • Backend: Change PORT in packages/server/.env
  • Frontend: Change port in packages/client/vite.config.ts

Database Errors

Delete the database file and restart the server:

rm packages/server/src/database/pennywise.db
npm run server

TypeScript Compilation Errors

If you see TypeScript errors about unused variables:

cd packages/server
npm install

Clean Install

To perform a complete clean reinstall:

# Remove all node_modules and build artifacts
rm -rf node_modules packages/*/node_modules packages/*/dist

# Reinstall dependencies
cd packages/shared && npm install && npm run build && cd ../..
cd packages/server && npm install && cd ../..
cd packages/client && npm install && cd ../..
npm install

Future Enhancements

  • User authentication and multi-user support
  • Recurring transactions
  • Receipt upload and OCR
  • Multi-currency support
  • Bank account integration (Plaid API)
  • Mobile app (React Native)
  • Budget recommendations using ML
  • Bill payment reminders
  • Spending insights and trends
  • Data backup and sync

License

MIT License - feel free to use this project for learning or portfolio purposes.

Contributing

This is a portfolio project, but suggestions and feedback are welcome! Feel free to open an issue or submit a pull request.


Built with ❤️ using React, TypeScript, and Express.js

About

A budgeting application

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors