10 KiB
💰 Budgeteer
A personal finance dashboard built with Blazor Server (.NET 10).
Status: beta — see the in-app badge.
Features
- Multi-account support — current accounts, savings, credit cards, each with its own currency and colour
- Transaction tracking — income & expenses with date, category, and account assignment
- Recurring transactions — daily, weekly, monthly, or yearly recurrence with automatic materialisation up to one year ahead
- Dashboard — balance trend chart (Chart.js), recent & upcoming transaction lists, account filter toggles, inline balance editing, and configurable time window
- Reports — doughnut charts for expenses and income by category, monthly income vs expenses bar chart, and a category summary table with filterable date range and account selection
- Categories — emoji-icon categories with sensible defaults and full CRUD
- Transactions table — sortable columns, search, pagination, per-account filtering, time-window presets, bulk selection & delete, and responsive column hiding on mobile
- Authentication — ASP.NET Identity with registration, login, password change, account deletion, and 5-attempt lockout
- SSO providers — optional Google, Microsoft, and GitHub sign-in (configured via
appsettings.json) - Settings — change password, reset all data (with confirmation), delete account
- Toast notifications — inline validation feedback via a toast system
- Help & About pages — in-app guides, tips, and project info
- Responsive UI — Bootstrap 5, mobile-friendly layout with collapsible sidebar, responsive table columns, and scoped CSS
- CI/CD — GitHub Actions for build/test and Docker Hub publishing
- Docker — multi-stage Dockerfile with volume-mounted SQLite, OCI image labels, and automatic security patching
Tech Stack
| Layer | Technology |
|---|---|
| Framework | .NET 10 / Blazor Server (InteractiveServer) |
| Database | SQLite via EF Core |
| Auth | ASP.NET Core Identity + optional Google / Microsoft / GitHub SSO |
| Charts | Chart.js (CDN) with JS interop |
| CSS | Bootstrap 5, scoped CSS |
| Tests | xUnit |
| CI/CD | GitHub Actions |
| Container | Docker (multi-stage build) |
Getting Started
Prerequisites
Run Locally
cd BudgetApp
dotnet run
The app will be available at https://localhost:5001 (or the port shown in the console). A budgetapp.db SQLite file is created automatically on first run.
Run Tests
dotnet test
Run with Docker
# Build
docker build -t budgeteer .
# Run (persists database in a named volume)
docker run -d -p 8080:8080 -v budgeteer-data:/app/data --name budgeteer budgeteer
Note: The SQLite database is stored at
/app/data/budgetapp.dbinside the container. Always mount a volume to/app/dataso your data survives image updates and container replacements.
The app will be available at http://localhost:8080.
Project Structure
BudgetApp/
├── Components/
│ ├── Layout/
│ │ ├── MainLayout.razor
│ │ ├── MainLayout.razor.css
│ │ ├── AuthLayout.razor
│ │ ├── AuthLayout.razor.css
│ │ ├── NavMenu.razor
│ │ ├── NavMenu.razor.cs
│ │ └── NavMenu.razor.css
│ ├── Pages/
│ │ ├── Home.razor
│ │ ├── Home.razor.cs
│ │ ├── Home.razor.css
│ │ ├── Accounts.razor
│ │ ├── Accounts.razor.cs
│ │ ├── Transactions.razor
│ │ ├── Transactions.razor.cs
│ │ ├── Transactions.razor.css
│ │ ├── Categories.razor
│ │ ├── Categories.razor.cs
│ │ ├── Salary.razor
│ │ ├── Salary.razor.cs
│ │ ├── Salary.razor.css
│ │ ├── Reports.razor
│ │ ├── Reports.razor.cs
│ │ ├── About.razor
│ │ ├── About.razor.cs
│ │ ├── Settings.razor
│ │ ├── Settings.razor.cs
│ │ ├── Login.razor
│ │ ├── Login.razor.cs
│ │ ├── Register.razor
│ │ ├── Register.razor.cs
│ │ ├── Logout.razor
│ │ ├── Logout.razor.cs
│ │ ├── Help.razor
│ │ ├── NotFound.razor
│ │ ├── Error.razor
│ ├── ToastContainer.razor
│ ├── ToastContainer.razor.cs
│ ├── ToastContainer.razor.css
│ ├── ToastValidator.razor
│ ├── ToastValidator.razor.cs
│ └── _Imports.razor
├── Services/
│ ├── DashboardService.cs
│ ├── ToastService.cs
│ ├── AppState.cs
│ ├── Models/
│ │ ├── ChartData.cs
│ │ ├── ChartDataset.cs
│ │ └── DashboardData.cs
├── Program.cs
├── wwwroot/
│ ├── app.css
│ └── js/
│ └── chart-interop.js
├── appsettings.json
├── appsettings.Development.json
├── Dockerfile
├── .dockerignore
├── README.md
└── certs/
└── .gitkeep
BudgetApp.Data/
├── Entities/
│ ├── Account.cs
│ ├── ApplicationUser.cs
│ ├── Category.cs
│ ├── RecurrenceType.cs
│ ├── Salary.cs
│ ├── Transaction.cs
│ ├── TransactionType.cs
├── Interfaces/
│ ├── IAccountRepository.cs
│ ├── ICategoryRepository.cs
│ ├── ISalaryRepository.cs
│ ├── ITransactionRepository.cs
├── Repositories/
│ ├── AccountRepository.cs
│ ├── CategoryRepository.cs
│ ├── SalaryRepository.cs
│ └── TransactionRepository.cs
├── ApplicationDbContext.cs
├── Migrations/
│ ├── AddCurrencyCodeAndCategoryIcon.cs
│ ├── AddCurrencyCodeAndCategoryIcon.Designer.cs
│ ├── AddIsDefaultToCategory.cs
│ ├── AddIsDefaultToCategory.Designer.cs
│ ├── AddIsPaidToTransaction.cs
│ ├── AddIsPaidToTransaction.Designer.cs
│ ├── AddRecurringTransactions.cs
│ ├── AddRecurringTransactions.Designer.cs
│ ├── AddSalary.cs
│ ├── AddSalary.Designer.cs
│ ├── InitialCreate.cs
│ ├── InitialCreate.Designer.cs
│ └── ApplicationDbContextModelSnapshot.cs
BudgetApp.Tests/
├── Helpers/
│ └── TestDbContextFactory.cs
├── Models/
│ └── AccountModelTests.cs
├── Services/
│ ├── AccountServiceTests.cs
│ ├── CategoryServiceTests.cs
│ ├── DashboardServiceTests.cs
│ └── TransactionServiceTests.cs
Project Roles
-
BudgetApp: Main Blazor Server application. Contains the UI, interactive pages, layouts, authentication logic, and application services. This is the entry point for running the app and includes configuration, dependency injection, and SSL setup.
-
BudgetApp.Data: Data access layer. Provides EF Core entities, the ApplicationDbContext, repository interfaces and implementations, and database migrations. Handles all database operations and schema management.
-
BudgetApp.Tests: Unit tests for services, models, and data access. Ensures correctness of business logic and data access. Uses xUnit for test execution.
Configuration
Default connection string in appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=budgetapp.db"
}
}
Override at runtime via environment variable:
export ConnectionStrings__DefaultConnection="Data Source=/path/to/budgeteer.db"
SSO Providers (optional)
Add client credentials to appsettings.json (or via environment / user-secrets). Each provider is only registered when both ClientId and ClientSecret are non-empty.
{
"Authentication": {
"Google": {
"ClientId": "",
"ClientSecret": ""
},
"Microsoft": {
"ClientId": "",
"ClientSecret": ""
},
"GitHub": {
"ClientId": "",
"ClientSecret": ""
}
}
}
Licence
This project is provided as-is for personal use.
Using Custom SSL Certificates
To enable HTTPS with custom SSL certificates in your Blazor application, follow these steps:
-
Prepare PEM Files Place your certificate and private key files in PEM format in a directory accessible by your app. Example paths:
/app/data/certs/cert.pem/app/data/certs/key.pem
-
Configure Certificate Paths The application will look for certificate files in the following order:
- Environment variables:
PEM_CERT_FILEandPEM_KEY_FILE - Configuration values:
PemCertFileandPemKeyFileinappsettings.json - Default:
/app/data/certs/cert.pemand/app/data/certs/key.pem
You can set environment variables before running the app:
export PEM_CERT_FILE=/path/to/cert.pem export PEM_KEY_FILE=/path/to/key.pemOr add to your
appsettings.json:{ "PemCertFile": "/path/to/cert.pem", "PemKeyFile": "/path/to/key.pem" } - Environment variables:
-
Fallback Behavior If the certificate files are not found, the app will use the default development certificate.
-
No Code Changes Needed The certificate loading logic is already implemented in
Program.cs. Simply provide the files and configuration as described above.
Note:
- Certificates must be in PEM format (
.pem). - Ensure file permissions allow the app to read the certificate and key files.
- For production, use certificates issued by a trusted Certificate Authority.