279 lines
9.3 KiB
Markdown
279 lines
9.3 KiB
Markdown
# 💰 Budgeteer
|
|
|
|
[](https://github.com/edgeofsanity76/Budgeteer/actions/workflows/build-and-test.yml)
|
|
[](https://github.com/edgeofsanity76/Budgeteer/actions/workflows/docker-publish.yml)
|
|
|
|
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
|
|
|
|
- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0)
|
|
|
|
### Run Locally
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
dotnet test
|
|
```
|
|
|
|
### Run with Docker
|
|
|
|
```bash
|
|
# 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.db` inside the container.
|
|
> Always mount a volume to `/app/data` so 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
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Default connection string in `appsettings.json`:
|
|
|
|
```json
|
|
{
|
|
"ConnectionStrings": {
|
|
"DefaultConnection": "Data Source=budgetapp.db"
|
|
}
|
|
}
|
|
```
|
|
|
|
Override at runtime via environment variable:
|
|
|
|
```bash
|
|
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.
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
1. **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`
|
|
|
|
2. **Configure Certificate Paths**
|
|
The application will look for certificate files in the following order:
|
|
- Environment variables: `PEM_CERT_FILE` and `PEM_KEY_FILE`
|
|
- Configuration values: `PemCertFile` and `PemKeyFile` in `appsettings.json`
|
|
- Default: `/app/data/certs/cert.pem` and `/app/data/certs/key.pem`
|
|
|
|
You can set environment variables before running the app:
|
|
```bash
|
|
export PEM_CERT_FILE=/path/to/cert.pem
|
|
export PEM_KEY_FILE=/path/to/key.pem
|
|
```
|
|
|
|
Or add to your `appsettings.json`:
|
|
```json
|
|
{
|
|
"PemCertFile": "/path/to/cert.pem",
|
|
"PemKeyFile": "/path/to/key.pem"
|
|
}
|
|
```
|
|
|
|
3. **Fallback Behavior**
|
|
If the certificate files are not found, the app will use the default development certificate.
|
|
|
|
4. **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.
|