You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A full-stack personal finance web application for tracking income and expenses, setting budgets, and visualising spending patterns. Built with a microservices backend and a React frontend, with a focus on clean API design, secure authentication, observability, and real-world usability.
Features
Authentication & Security
JWT-based authentication with httpOnly cookie storage (access + refresh tokens)
Secure password hashing with bcrypt
Email verification on registration via Resend
Forgot password / reset password flow with time-limited tokens
Proactive token refresh every 12 minutes; 30-minute inactivity autologout
Global 401 interceptor with automatic token retry before logout
Transactions
Add, edit, and delete income and expense transactions with amount, category, date, note, and comment
Keyword-based auto-detection of category from free-text input with manual override
Filter transactions by type (all / income / expense) and by category
Real-time summary: total income, expenses, and balance
Budget Management
Set monthly category budgets
Visual progress bars showing spent vs budgeted amount
Each service owns its own PostgreSQL database. JWT verification is performed independently per service using a shared secret — no cross-service HTTP calls for auth. The budget service reads transaction data directly via a read-only SQLAlchemy connection to the transaction database to compute monthly spend per category.
User Service — http://localhost:8000
Auth
Method
Endpoint
Description
POST
/auth/register
Register and send verification email
POST
/auth/login
Login, sets access + refresh token cookies
POST
/auth/logout
Clear auth cookies, blacklist token in Redis
POST
/auth/refresh
Refresh access token using refresh cookie
GET
/auth/verify-email?token=
Verify email address
GET
/auth/status
Check if current session is authenticated
POST
/auth/forgot-password
Send password reset link to email
POST
/auth/reset-password
Reset password with token
Users
Method
Endpoint
Description
GET
/users/me
Get current user profile
DELETE
/users/me
Delete account and clear session
Transaction Service — http://localhost:8001
Method
Endpoint
Description
POST
/transactions/
Create a transaction (multipart/form-data)
GET
/transactions/
List transactions (filterable by type, date range)
PUT
/transactions/{id}
Update a transaction
DELETE
/transactions/{id}
Delete a transaction
GET
/transactions/summary
Get total income, expense, and balance
All transaction endpoints require a valid access_token cookie. Transactions are scoped to the authenticated user via the JWT sub claim.
Budget Service — http://localhost:8002
Method
Endpoint
Description
GET
/budgets/
List all budgets with real-time spent amount
POST
/budgets/
Create a budget for a category
PUT
/budgets/{id}
Update a budget amount
DELETE
/budgets/{id}
Delete a budget
Spent amount is calculated via direct SQL query to transaction_db — no inter-service HTTP call.
Observability
Prometheus
Scrapes /metrics on all three services every 15 seconds. Available at http://localhost:9090.
Useful queries:
# Request rate per service
rate(http_requests_total[1m])
# Error rate (4xx + 5xx)
rate(http_requests_total{status_code=~"4..|5.."}[1m])
# P95 latency for user_service
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{job="user_service"}[1m]))
# CPU usage per service
rate(process_cpu_seconds_total[1m])
Grafana
Pre-provisioned dashboard at http://localhost:3000 (admin / admin). Shows:
Request rate (req/s) per endpoint
Error rate (4xx + 5xx req/s)
P50 and P95 latency
Total request counters
Running Locally
Prerequisites
Docker Desktop
Start everything
docker-compose up --build
This starts all databases, backend services, frontend, Prometheus, and Grafana in the correct dependency order.