A personal finance web application for tracking checking account balances across bill payment periods. Built with Spring Boot 4.0, PostgreSQL, and modern frontend technologies.
- Payment Periods - Track balances across billing cycles with start/end dates
- Payment Items - Record individual expenses with payees, amounts, and notes
- Payee Management - Reusable payees with autocomplete suggestions
- Auto-calculation - Ending balance computed automatically as you add items
- Reports & Analytics - Visual charts and spending statistics
- Keyboard Shortcuts - Productivity shortcuts for power users
- Responsive Design - Works on desktop, tablet, and mobile
- Dark-friendly UI - Modern, clean interface
Choose your preferred setup method:
| Method | Best For | Requirements |
|---|---|---|
| Docker Standalone | Quick demo, no Java needed | Docker only |
| Local Development | Contributing, debugging | Java 25+, Docker |
Run the complete application in Docker containers. No Java installation required.
- Docker Desktop (includes Docker Compose)
git clone https://github.com/dima767/balance-tracker.git
cd balance-tracker
# Build and start (first time)
./compose-up-standalone.sh -bThe first build takes a few minutes to download dependencies and compile.
Open your browser to: https://localhost:8443/balancetracker
SSL Certificate Warning: Your browser will show a security warning because the app uses a self-signed certificate. This is normal for local development.
- Chrome/Edge: Click "Advanced" → "Proceed to localhost (unsafe)"
- Firefox: Click "Advanced" → "Accept the Risk and Continue"
- Safari: Click "Show Details" → "visit this website"
- Click "New Period" to create your first payment period
- Enter the period date and starting balance
- Add payment items (bills, expenses) with payees and amounts
- Watch the ending balance calculate automatically
# Start (after first build)
./compose-up-standalone.sh
# Stop (keeps your data)
./compose-down-standalone.sh
# Stop and delete all data
./compose-down-standalone.sh -v
# Rebuild after code changes
./compose-up-standalone.sh -b
# View logs
docker compose -f docker-compose.standalone.yml logs -f appIf ports 8443/8080 are already in use, create a .env file:
cp .env.example .envEdit .env to change ports:
APP_HTTPS_PORT=9443
APP_HTTP_PORT=9080Then restart:
./compose-down-standalone.sh
./compose-up-standalone.shRun the application locally with hot reload for development and debugging.
| Requirement | Version | Check Command |
|---|---|---|
| Java JDK | 25+ | java -version |
| Docker | Latest | docker --version |
| Docker Compose | Latest | docker compose version |
Install Java 25:
- macOS:
brew install openjdk@25 - Linux: Eclipse Temurin
- Windows: Eclipse Temurin
./compose-up.shThis starts PostgreSQL 17 on localhost:5432.
# Build and run
./build-and-run.sh -b
# Or just run (if already built)
./build-and-run.shOpen: https://localhost:8443/balancetracker
(See SSL certificate warning note above)
| Command | Description |
|---|---|
./compose-up.sh |
Start PostgreSQL database |
./compose-down.sh |
Stop database (keep data) |
./compose-down.sh -v |
Stop database and delete data |
./build-and-run.sh |
Run application (must be built) |
./build-and-run.sh -b |
Build and run |
./build-and-run.sh -br |
Force rebuild and run |
./generate-certs.sh |
Regenerate SSL certificate |
./gradlew test |
Run tests |
./gradlew build |
Build without running |
IntelliJ IDEA:
- Open the project folder
- Import as Gradle project
- Set Project SDK to Java 25
- Run
BalanceTrackerApplication.java
VS Code:
- Install "Extension Pack for Java"
- Open the project folder
- Run via the Run/Debug panel
The application starts with debug port 5005 enabled.
IntelliJ IDEA:
- Run → Edit Configurations → Add New → Remote JVM Debug
- Host:
localhost, Port:5005 - Click Debug
Changes to Thymeleaf templates and static resources reload automatically. For Java changes, restart the application.
Both modes use self-signed SSL certificates for HTTPS.
The certificate is pre-generated at src/main/resources/ssl/keystore.p12.
To regenerate with custom hostnames:
# Default (localhost)
./generate-certs.sh
# Custom hostnames
CERT_HOSTS="localhost,myapp.local" ./generate-certs.shTo use a custom hostname:
-
Add to
/etc/hosts(orC:\Windows\System32\drivers\etc\hostson Windows):127.0.0.1 myapp.local -
Generate certificate:
CERT_HOSTS="localhost,myapp.local" ./generate-certs.sh -
Rebuild:
./build-and-run.sh -b
Certificates are auto-generated on first start and stored in a Docker volume.
To use a custom hostname:
-
Add to
/etc/hosts:127.0.0.1 balancetracker.local -
Create/edit
.env:cp .env.example .env
Set:
CERT_HOSTS=localhost,balancetracker.local -
Rebuild (regenerates certificate):
./compose-down-standalone.sh -v ./compose-up-standalone.sh -b
Create a .env file from the template:
cp .env.example .env| Variable | Default | Description |
|---|---|---|
APP_HTTPS_PORT |
8443 | Host HTTPS port |
APP_HTTP_PORT |
8080 | Host HTTP port |
POSTGRES_DB |
balancetracker | Database name |
POSTGRES_USER |
balancetracker | Database username |
POSTGRES_PASSWORD |
balancetracker | Database password |
CERT_HOSTS |
localhost,balancetracker.local | SSL certificate hostnames |
CERT_IPS |
127.0.0.1,0.0.0.0 | SSL certificate IPs |
JAVA_OPTS |
-Xms256m -Xmx512m | JVM memory settings |
Adjust JAVA_OPTS in .env based on available RAM:
| System RAM | Recommended Setting |
|---|---|
| 512MB | -Xms128m -Xmx384m |
| 1GB | -Xms256m -Xmx512m (default) |
| 2GB | -Xms512m -Xmx1g |
| 4GB+ | -Xms1g -Xmx2g |
Error: Bind for 0.0.0.0:8443 failed: port is already allocated
Solution: Change ports in .env:
APP_HTTPS_PORT=9443
APP_HTTP_PORT=9080Error: Connection to localhost:5432 refused
Solution:
# Check if PostgreSQL is running
docker ps | grep postgres
# Restart database
./compose-down.sh
./compose-up.shError: Browser shows NET::ERR_CERT_INVALID
Solution: This is expected with self-signed certificates. Proceed through the warning (see instructions above).
To regenerate certificates:
# Local development
./generate-certs.sh
./build-and-run.sh -b
# Docker standalone
./compose-down-standalone.sh -v
./compose-up-standalone.sh -bError: gradlew: Permission denied
Solution:
chmod +x gradlew
chmod +x *.shError: Build fails with memory errors
Solution: Increase Docker Desktop memory allocation:
- Docker Desktop → Settings → Resources → Memory → Set to 4GB+
balance-tracker/
├── src/
│ ├── main/
│ │ ├── java/dk/balancetracker/
│ │ │ ├── config/ # Spring configuration
│ │ │ ├── domain/ # JPA entities
│ │ │ ├── repository/ # Data access layer
│ │ │ ├── service/ # Business logic
│ │ │ └── web/ # Controllers
│ │ └── resources/
│ │ ├── static/ # CSS, JavaScript
│ │ ├── templates/ # Thymeleaf views
│ │ └── ssl/ # SSL keystore
│ └── test/ # Test classes
├── docker-compose.yml # Dev database only
├── docker-compose.standalone.yml # Full stack
├── Dockerfile # Application container
├── build.gradle # Gradle build config
└── README.md
| Component | Technology |
|---|---|
| Backend | Spring Boot 4.0, Java 25 |
| Database | PostgreSQL 17 |
| ORM | Spring Data JPA, Hibernate |
| Currency | Java Money API (JSR 354) |
| Templates | Thymeleaf 3.1 |
| Frontend | htmx 2.0, Bootstrap 5.3 |
| Charts | Chart.js |
| Build | Gradle 9.2 |
| Testing | JUnit 6, Testcontainers |
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Run tests:
./gradlew test - Commit:
git commit -m "Add my feature" - Push:
git push origin feature/my-feature - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Questions or issues? Please open an issue on GitHub.