A modern personal finance management application built with Ruby on Rails 8, following 37signals patterns and conventions.
π Live Site: Personal Finance Tracker
- Create, edit, and delete income and expense transactions
- Categorize with custom categories and color-coded tags
- Multi-filter: type, category, tag, date range, and text search
- Paginated list (20 per page) with mobile card layout
- CSV import with preview and per-row validation
- CSV export of filtered results
- Balance summary with current-month income, expenses, and net balance
- Income vs Expenses bar chart
- Expenses by Category pie chart
- Monthly Evolution line chart (last 6 months, income vs expenses)
- Month-over-month comparison with absolute and percentage changes
- Category budget alerts β warning at 80%, exceeded at 100%
- Filters applied to charts and transaction list simultaneously
- Four goal types: Savings, Expense Reduction, Income Increase, Debt Payoff
- Five statuses: Active, Completed, Paused, Cancelled, Rolled Over
- Progress tracking with percentage and visual indicators
- Due-soon and overdue detection
- Recurring monthly goals β automatically roll over to a new cycle each month
- Cycle history view for rolled-over goals
- Filtering by type, status, and search
- Custom categories with hex color coding and optional monthly budget limits
- Tags (many-to-many with transactions) with their own colors
- Prevent deletion of categories or tags that have associated transactions
- Goal due-soon email notifications (7-day window)
- Monthly financial summary emails
- Automatic rollover of recurring goals (via
rake goals:process_rolloversor cron) - Job monitoring dashboard at
/jobs/monitoring
- Dark mode toggle
- Fully responsive β mobile-first with dedicated card layouts
- Real-time UI updates via Turbo Frames and Turbo Streams (no full-page reloads)
- i18n support: English and Brazilian Portuguese (pt-BR)
| Layer | Technology |
|---|---|
| Backend | Ruby 3.3.6 Β· Rails 8.1.1 |
| Database | PostgreSQL 16 |
| Frontend | Hotwire (Turbo + Stimulus) Β· TailwindCSS Β· Importmap |
| Charts | Chartkick |
| Authentication | Devise 5 |
| Pagination | Kaminari |
| Job Queue | Solid Queue |
| Caching | Solid Cache |
| WebSockets | Solid Cable |
| Deployment | Kamal Β· Docker Β· Thruster |
| Security | Brakeman |
| Code Quality | RuboCop (omakase) |
| Testing | RSpec Β· FactoryBot Β· Faker Β· Capybara Β· SimpleCov |
- Docker & Docker Compose (recommended)
- Or: Ruby 3.3.6, PostgreSQL 16, Node.js 22
# Start all services
docker compose up
# First time only β set up the database and seed demo data
docker compose exec web rails db:create db:migrate db:seedApp runs at http://localhost:3000 β PostgreSQL is exposed on localhost:5434.
Demo credentials seeded by default:
- Email:
demo@example.com - Password:
password123
# Install dependencies and set up the database
./bin/setup
# Start the development server
./bin/devApp runs at http://localhost:3000.
# Docker
docker compose up # Start services
docker compose exec web rails console # Rails console
docker compose exec web rails db:migrate # Run migrations
docker compose exec web rails db:seed # Seed demo data
# Local
./bin/dev # Start with live reload
rails console
rails db:migrate
rails db:seed# Docker
docker compose run --rm web bundle exec rspec
# Local
bundle exec rspec # Full suite
bundle exec rspec spec/models # Models only
bundle exec rspec spec/requests # Request/integration specs
bundle exec rspec spec/jobs # Job specsbundle exec rubocop # Linting
bundle exec brakeman # Security audit# Process recurring goal rollovers (run monthly via cron)
rails goals:process_rolloverskamal setup # Initial setup
kamal deploy # Deploy to productionapp/
βββ controllers/
β βββ dashboard_controller.rb # Charts, budget alerts, goals stats
β βββ transactions_controller.rb # CRUD + filtering + CSV export
β βββ goals_controller.rb # CRUD + progress update + history
β βββ categories_controller.rb
β βββ tags_controller.rb
β βββ transaction_imports_controller.rb # CSV import preview workflow
β βββ jobs_controller.rb # Job monitoring
βββ models/
β βββ user.rb # Auth + balance helpers
β βββ transaction.rb # income/expense with tags
β βββ category.rb # Colors + budget limits
β βββ tag.rb # Many-to-many with transactions
β βββ goal.rb # Progress + rollover logic
β βββ transaction_tagging.rb
β βββ concerns/
β βββ progressable.rb # Shared progress tracking
βββ services/
β βββ dashboard/
β β βββ charts_data.rb
β β βββ monthly_evolution_data.rb
β β βββ month_comparison_data.rb
β β βββ category_budget_alerts.rb
β β βββ transactions_filter.rb
β βββ import/
β β βββ transactions_csv_parser.rb
β β βββ transactions_preview.rb
β β βββ transactions_importer.rb
β βββ export/
β β βββ transactions_csv.rb
β βββ reports/
β βββ monthly_summary.rb
βββ jobs/
β βββ process_goal_rollovers_job.rb
β βββ enqueue_goal_due_soon_notifications_job.rb
β βββ goal_due_soon_notification_job.rb
β βββ enqueue_monthly_financial_reports_job.rb
β βββ monthly_financial_report_job.rb
βββ mailers/
β βββ goal_notifications_mailer.rb
β βββ reports_mailer.rb
βββ javascript/controllers/ # Stimulus controllers
db/
βββ seeds.rb # Orchestrates all seed files
βββ seeds/
βββ tags.rb # Sample tags
βββ transactions.rb # 6 months of historical transactions with tags
βββ goals.rb # One-time + recurring + rolled-over goals
lib/tasks/
βββ goals.rake # goals:process_rollovers
spec/
βββ factories/
βββ models/
βββ requests/
βββ services/
βββ jobs/
βββ features/ # Capybara system tests
| Table | Key columns |
|---|---|
users |
email, encrypted_password (Devise) |
categories |
name, color, monthly_budget_limit |
tags |
name, color |
transactions |
amount, date, description, transaction_type (income/expense), category_id |
transaction_taggings |
transaction_id, tag_id |
goals |
title, target_amount, current_amount, target_date, goal_type, status, recurring, period_start, period_end, parent_goal_id |
- Follow the conventions in
CLAUDE.md - Write tests for every new feature
- Run
rspecandrubocopbefore opening a PR - Use descriptive commit messages scoped to the change
Available as open source under the MIT License.