- Python 50.1%
- JavaScript 23.1%
- CSS 14.4%
- HTML 10.4%
- Shell 1.9%
- Other 0.1%
| backend | ||
| cli | ||
| completions | ||
| frontend | ||
| .gitignore | ||
| ChangeLog | ||
| cli.py | ||
| CLI_README.md | ||
| install.sh | ||
| README.md | ||
| requirements.txt | ||
| V2.4.4 | ||
| wis.aleksi.systems.har | ||
What I Spend
A modern, self-hosted personal expense tracking application with a beautiful interface, powerful analytics, and multi-user data sharing capabilities.
Table of Contents
- Features
- Screenshots
- Quick Start
- Installation
- Configuration
- Usage
- Multi-User Data Sharing
- API Reference
- CLI (Command Line Interface)
- Project Structure
- Security
- Data Management
- Troubleshooting
- Development
Features
💰 Expense Management
- Add, edit, and delete expenses with descriptions
- Categorize expenses with nested subcategories
- Track payment methods (Cash, Card, Transfer, etc.)
- Filter by month and export to CSV or Excel (XLSX)
- Category is required for expenses; subcategory remains optional
📊 Analytics Dashboard
- Total spent for the month
- Transaction count and average per transaction
- Highest expense tracking
- Daily evolution chart (line graph)
- Category distribution (pie chart)
- Weekly comparison (bar chart)
- Payment method breakdown (horizontal bar chart)
- Top 5 expenses list
🔗 Multi-User Data Sharing
- Link user accounts without merging them
- Share expenses, categories, and payment methods between linked accounts
- Each account remains independent with its own credentials
- Link and unlink accounts at any time
- Perfect for couples or roommates tracking shared expenses
🌍 Geolocation
- Automatic GPS capture for expense locations
- Suggestions based on frequently visited places
- Smart location-based expense tracking
🌙 Dark Mode
- Full dark mode support with toggle in settings
- Persistent theme preference across sessions
🔒 Security
- Argon2id password hashing
- Session-based authentication
- Rate limiting (configurable, default 50 req/s)
- Optional French IP filtering (GeoIP)
- API key protection for all endpoints
🔄 Automatic Updates
In-App Update System
- One-click update from Settings menu
- No CLI required - updates directly from the web interface
- Automatic backup before any changes
- Real-time progress visualization
- Automatic rollback on failure
- Server restart after successful update
🎨 Modern UI
- Clean, professional design with Indigo/Violet theme
- Fully responsive (mobile, tablet, desktop)
- Interactive charts powered by Chart.js
- Toast notifications and modal dialogs
- Smooth animations and transitions
- Interactive setup wizard for first-time users
Quick Start
# Clone or navigate to the project
cd WhatISpend
# Run the automated installation
sudo ./install.sh
The installation script will:
- Create a Python virtual environment
- Install all dependencies
- Generate an API key
- Initialize the database
- Start the server with a setup wizard
Access the application: http://localhost:3000
Installation
Prerequisites
- Python 3.10+
- pip (Python package manager)
- Linux/macOS (Ubuntu/Debian recommended)
Manual Installation
-
Create virtual environment
python3 -m venv venv source venv/bin/activate -
Install dependencies
pip install -r requirements.txt -
Generate API key
python3 -c "import secrets; print(secrets.token_hex(16))" -
Configure the application
Create a
config.envfile at the project root:# Expense Tracker Configuration # API Keys (generate with the command above) API_KEY=your_api_key_here API_KEY_SALT=your_salt_secret_here # Server Configuration HOST=0.0.0.0 PORT=3000 # Session Configuration (in hours) SESSION_DURATION=24 # Rate Limiting (requests per second) RATE_LIMIT=50 # GeoIP (optional) GEOIP_ENABLED=false GEOIP_LICENSE_KEY= -
Initialize data directory
mkdir -p data echo '{}' > data/users.json echo '{}' > data/expenses.json echo '{}' > data/categories.json echo '{}' > data/payment_methods.json -
Create an admin user
python cli.py user create --username admin --password your_secure_password -
Start the server
uvicorn backend.main:app --host 0.0.0.0 --port 3000 -
Access the application
- Open your browser to:
http://localhost:3000 - Login with your credentials
- Open your browser to:
Configuration
Edit config.env to customize your installation:
| Variable | Description | Default | Required |
|---|---|---|---|
API_KEY |
API authentication key | (generated) | ✅ |
API_KEY_SALT |
Salt for user API keys | (generated) | ✅ |
HOST |
Server bind address | 0.0.0.0 |
✅ |
PORT |
Server port | 3000 |
✅ |
SESSION_DURATION |
Session lifetime (hours) | 24 |
✅ |
RATE_LIMIT |
Requests per second | 50 |
✅ |
GEOIP_ENABLED |
Enable French IP filtering | false |
❌ |
GEOIP_LICENSE_KEY |
MaxMind GeoIP license | - | ❌ |
Usage
First Login
- Navigate to
http://localhost:3000 - Enter your username and password
- You'll be redirected to the Dashboard
Dashboard
The main dashboard displays:
- Key Metrics: Total spent, transaction count, average, highest expense
- Charts: Daily evolution, category distribution, weekly comparison, payment methods
- Top Expenses: Your 5 largest expenses for the month
Managing Expenses
- Go to the Expenses page
- Click Add Expense to create a new entry
- Fill in amount, date, category, payment method, and optional description
- Optionally add GPS coordinates for location tracking
- Edit or delete existing expenses as needed
- Use the month filter to view different periods
- Export to CSV or Excel for external analysis
Managing Categories
- Go to the Categories page
- Create parent categories and subcategories
- Edit or delete categories (deletion requires no associated expenses)
Managing Payment Methods
- Go to the Payment Methods page
- Create custom payment methods (Cash, Card, etc.)
- Edit or delete as needed
Multi-User Data Sharing
What I Spend supports linking user accounts to share data while keeping accounts independent.
Linking Users
# Link two user accounts
python cli.py user link --user1 username1 --user2 username2
# Unlink accounts
python cli.py user unlink --user1 username1 --user2 username2
How It Works
- Shared Data: Expenses, categories, and payment methods are shared between linked accounts
- Independent Accounts: Each user maintains their own login credentials and preferences
- Flexible: Link and unlink accounts at any time without data loss
- Storage: Links are stored in
data/user_links.json
Use Cases
- Couples: Track shared household expenses while maintaining individual accounts
- Roommates: Share rent and utility expenses without merging accounts
- Family: Parents and children can share certain expense categories
API Reference
All API endpoints require the API key as a query parameter: ?key=YOUR_API_KEY
Authentication
| Endpoint | Method | Description |
|---|---|---|
/sysapi/login |
POST | Login (form: username, password) |
/sysapi/logout |
POST | Logout |
/sysapi/session |
GET | Check session validity |
Expenses
| Endpoint | Method | Description |
|---|---|---|
/sysapi/expenses |
GET | List expenses (?month=YYYY-MM) |
/sysapi/expense_create |
POST | Create expense |
/sysapi/expense_update |
POST | Update expense |
/sysapi/expense_delete |
POST | Delete expense |
Categories
| Endpoint | Method | Description |
|---|---|---|
/sysapi/categories |
GET | List categories (nested) |
/sysapi/categories_flat |
GET | List all categories (flat) |
/sysapi/category_create |
POST | Create category |
/sysapi/category_update |
POST | Update category |
/sysapi/category_delete |
POST | Delete category |
Payment Methods
| Endpoint | Method | Description |
|---|---|---|
/sysapi/payment_methods |
GET | List payment methods |
/sysapi/payment_method_create |
POST | Create payment method |
/sysapi/payment_method_update |
POST | Update payment method |
/sysapi/payment_method_delete |
POST | Delete payment method |
Statistics
| Endpoint | Method | Description |
|---|---|---|
/sysapi/dashboard-data |
GET | All dashboard statistics in one call |
/sysapi/stats |
GET | Monthly statistics |
/sysapi/daily_evolution |
GET | Daily evolution data |
/sysapi/category_distribution |
GET | Category distribution |
/sysapi/weekly_comparison |
GET | Weekly comparison |
/sysapi/payment_method_stats |
GET | Payment method statistics |
/sysapi/top_expenses |
GET | Top expenses (?limit=5) |
/sysapi/export_csv |
GET | Export expenses as CSV |
Update
| Endpoint | Method | Description |
|---|---|---|
/sysapi/update/check |
GET | Check for available updates |
/sysapi/update/execute |
POST | Execute update process |
/sysapi/update/status |
GET | Get current update status |
User Management
| Endpoint | Method | Description |
|---|---|---|
/sysapi/users |
GET | List all users |
/sysapi/users/link |
POST | Link two user accounts |
/sysapi/users/unlink |
POST | Unlink two user accounts |
/sysapi/users/linked |
GET | Get linked users for current user |
Example API Calls
# Get expenses for January 2026
curl "http://localhost:3000/sysapi/expenses?month=2026-01&key=YOUR_API_KEY"
# Create an expense
curl -X POST "http://localhost:3000/sysapi/expense_create?key=YOUR_API_KEY" \
-d "amount=50.00&date=2026-01-15&category_id=1&payment_method_id=1&description=Groceries"
# Get all dashboard data in a single call
curl "http://localhost:3000/sysapi/dashboard-data?month=2026-01&key=YOUR_API_KEY"
# Link two user accounts
curl -X POST "http://localhost:3000/sysapi/users/link?key=YOUR_API_KEY" \
-d "user1=john&user2=jane"
Project Structure
WhatISpend/
├── backend/
│ ├── main.py # FastAPI application entry point
│ ├── config.py # Configuration management
│ ├── security.py # Rate limiting, auth middleware
│ ├── storage.py # JSON file storage management
│ ├── models.py # Pydantic data models
│ ├── geolocation.py # GeoIP filtering (optional)
│ ├── excel_generator.py # Excel export functionality
│ ├── update_manager.py # Update process management
│ └── routes/
│ ├── auth.py # Authentication routes
│ ├── expenses.py # Expense CRUD operations
│ ├── categories.py # Category management
│ ├── payment_methods.py # Payment method management
│ ├── stats.py # Statistics and analytics
│ └── update.py # Update API endpoints
├── frontend/
│ ├── index.html # Main application HTML
│ ├── setup.html # Setup wizard page
│ ├── app.js # Frontend application logic
│ ├── setup.js # Setup wizard JavaScript
│ ├── styles.css # Application styles
│ ├── setup.css # Setup wizard styles
│ └── favicon.* # Application icons
├── cli/
│ ├── __init__.py
│ ├── commands/
│ │ ├── user.py # User management commands
│ │ ├── server.py # Server control commands
│ │ ├── backup.py # Backup commands
│ │ ├── logs.py # Log viewing commands
│ │ ├── update.py # Update command
│ │ └── interactive.py # Interactive mode
│ └── utils/
│ └── display.py # CLI display utilities
├── scripts/
│ ├── create_user.py # User creation utility
│ ├── delete_user.py # User deletion utility
│ ├── link_users.py # User linking utility
│ └── watchdog.py # Monitoring utility
├── data/ # JSON data storage
│ ├── users.json # User accounts
│ ├── expenses.json # Expense records
│ ├── categories.json # Category definitions
│ ├── payment_methods.json # Payment method definitions
│ ├── user_links.json # User link relationships
│ └── update_status.json # Current update status
├── backups/ # Automatic backup storage
├── cli.py # Main CLI entry point
├── install.sh # Automated installation script
├── requirements.txt # Python dependencies
├── config.env # Application configuration (auto-generated)
├── .gitignore # Git ignore rules
├── ChangeLog # Version history
├── V2.4.1 # Current version file
└── README.md # This file
Security
API Key Authentication
- 32-character hexadecimal key generated on installation
- Required on all
/sysapi/*endpoints - Stored securely in
config.env
Password Security
- Argon2id hashing (winner of the Password Hashing Competition)
- Automatic salt generation per user
- Parameters: m=65536, t=3, p=4 (recommended secure defaults)
Rate Limiting
- Default: 50 requests per second per IP
- Configurable via
RATE_LIMITinconfig.env - Returns HTTP 429 when exceeded
GeoIP Filtering (Optional)
- Restrict access to French IP addresses only
- Requires MaxMind GeoIP license key
- Enable via
GEOIP_ENABLED=true
Session Management
- 24-hour session duration (configurable)
- Secure cookie-based sessions
- Automatic expiration and cleanup
Production Recommendations
- Use HTTPS: Deploy behind Nginx/Apache with SSL
- Firewall: Restrict access to trusted IPs
- Regular Backups: Use
python cli.py backup createregularly - Strong Passwords: Use complex passwords for admin accounts
- Update Dependencies: Keep
requirements.txtup to date - Enable GeoIP: If you want to restrict access to specific regions
Data Management
Storage Format
Data is stored in JSON files in the data/ directory:
users.json:
{
"admin": {
"username": "admin",
"password_hash": "$argon2id$v=19$m=65536,t=3,p=4$...",
"created_at": "2026-03-21T10:00:00Z"
}
}
expenses.json:
{
"1": {
"id": 1,
"user": "admin",
"amount": 45.50,
"date": "2026-03-21",
"category_id": 1,
"payment_method_id": 1,
"description": "Groceries",
"created_at": "2026-03-21T10:30:00Z"
}
}
Backup
# Create a backup
python cli.py backup create -o my-backup
# List backups
python cli.py backup list
# Restore from backup
python cli.py backup restore --file backup-20260403.tar.gz
User Management
Create a user:
python cli.py user create --username <username> --password <password>
List users:
python cli.py user list
Link users:
python cli.py user link --user1 <username1> --user2 <username2>
Unlink users:
python cli.py user unlink --user1 <username1> --user2 <username2>
Delete a user:
python cli.py user delete --username <username> [--delete-data]
CLI (Command Line Interface)
A beautiful and intuitive CLI for managing your Expense Tracker application.
Quick Start
cd WhatISpend
source venv/bin/activate
python cli.py --help
Usage Modes
Interactive Mode (Recommended):
python cli.py interactive
# or
python cli.py -i
# Then type commands:
expense-tracker> user create
expense-tracker> server start --background
expense-tracker> status
expense-tracker> exit
Direct Command Mode:
python cli.py status
python cli.py user create --username john
python cli.py server start --background
python cli.py backup create -o monthly-backup
python cli.py update
Main Commands
| Command | Description |
|---|---|
status |
Show application status |
user create |
Create a new user |
user list |
List all users |
user link |
Link two user accounts |
user unlink |
Unlink two user accounts |
server start |
Start the server |
server stop |
Stop the server |
server restart |
Restart the server |
backup create |
Create a backup |
backup list |
List available backups |
backup restore |
Restore from backup |
logs show |
View logs |
update |
Update application to latest version |
Interactive Mode Shortcuts
u=usersrv=serverbkp=backuph=helpq=quit
For complete CLI documentation, see CLI_README.md.
Troubleshooting
Server won't start
-
Check if port is in use:
sudo lsof -i :3000 -
Check logs:
python cli.py logs show -
Verify configuration:
cat config.env
Can't login
-
Verify user exists:
python cli.py user list -
Reset password:
python cli.py user delete --username <username> python cli.py user create --username <username> --password <new_password>
API key errors
-
Check API key in config.env:
grep API_KEY config.env -
Regenerate if needed:
python3 -c "import secrets; print(secrets.token_hex(16))" # Update config.env with new key
GeoIP issues
- Disable GeoIP if causing problems:
Then restart the server.# In config.env GEOIP_ENABLED=false
CSS/JavaScript issues
- The application uses non-minified source files for easier debugging
- Browser cache is disabled for assets to ensure fresh content
- If styles appear broken, try a hard refresh (Ctrl+Shift+R / Cmd+Shift+R)
Development
Dependencies
fastapi>=0.104.0 # Web framework
uvicorn[standard]>=0.24.0 # ASGI server
pydantic>=2.0.0 # Data validation
argon2-cffi>=23.1.0 # Password hashing
python-multipart>=0.0.6 # Form data parsing
slowapi>=0.1.9 # Rate limiting
geoip2>=4.7.0 # GeoIP filtering
python-jose[cryptography]>=3.3.0 # JWT/Cryptography
passlib>=1.7.4 # Password utilities
rich>=13.0.0 # CLI formatting
click>=8.0.0 # CLI framework
openpyxl>=3.1.0 # Excel export
psutil>=5.9.0 # Process management
Performance Optimizations
- Dashboard API: Consolidated from 9 calls to 1 (
/dashboard-data) - GZip Compression: Enabled for responses > 1KB (20-30% size reduction)
- Non-minified Assets: Source CSS/JS used directly for easier debugging
| Metric | Before | After | Gain |
|---|---|---|---|
| Dashboard API calls | 9 | 1 | -89% |
| Initial load time | ~2-3s | ~1-1.5s | -50% |
| HTML size (compressed) | 52 KB | 40 KB | -23% |
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests
- Submit a pull request
License
MIT License - See LICENSE file for details.
Support
For issues, questions, or contributions:
- Check existing documentation
- Review the code in
backend/andfrontend/directories - Open an issue on the repository
Version History
See ChangeLog for detailed release notes.
| Version | Date | Highlights |
|---|---|---|
| 2.4.1 | April 2026 | Web update system, Leaflet map fix |
| 2.4 | April 2026 | User linking, CLI update restart, category validation |
| 2.3.4 | April 2026 | Dashboard API optimization, GZip compression, shared categories |
| 2.3 | March 2026 | CLI update command with automatic backup |
| 2.2.1 | March 2026 | Project cleanup and documentation |
| 2.2 | March 2026 | GPS coordinate fixes, setup page CSS |
| 2.1 | March 2026 | Geolocation, dark mode, payment filters |
| 2.0 | Feb. 2026 | FastAPI migration, subcategories, new charts |
| 1.1 | Jan. 2026 | Custom payment methods, CSV export |
| 1.0 | Dec. 2025 | Initial stable release |