Ledgerra is a self-hosted personal finance tracker built with an ASP.NET Core API and a React frontend. It is designed for homelab deployments such as Unraid and TrueNAS SCALE, keeps a clean JSON API, and covers the full personal finance workflow — accounts, transactions, budgets, savings goals, and analytics.
Current version: v0.12.0
- Multiple accounts with types: Checking, Savings, Credit Card, Investment, and more
- Per-account balance chart with range selector
- Institution, masked account number, and icon support
- Transfer between accounts without distorting income/expense reporting
- Full transaction CRUD with inline editing
- Split transactions across multiple categories
- Recurring transaction templates with auto-generation
- Bulk actions: categorize, transfer, delete
- Advanced filters (date range, category, account, amount, type) with shareable URL state
- CSV export of filtered transactions
- Smart CSV import with field mapping
- Monthly category budgets with progress tracking
- CSV export of budget data with category detail
- Savings goals with optional deadlines and target amounts
- Progress tracking linked to actual account transfers
- Customizable widget layout (persisted per user)
- Global month selector
- Quick transaction entry from the dashboard
- Spending insights and net worth summary
- Monthly income vs. expense charts (powered by Recharts)
- AI-assisted monthly report analysis via OpenAI-compatible providers
- Full data export and restore (backup/restore flow)
- CSV transaction import with preview and conflict handling
- JWT authentication with access tokens and refresh tokens
- Personal access tokens for API access
- Profile, security, and appearance settings
- Accent color selection, density, motion, and minimal navigation preferences
- Dark mode
- Internationalization (i18n) with locale switching
- Mobile-responsive PWA with bottom navigation bar
- Onboarding checklist for new users
- Security-hardened API and frontend (audit fixes in v0.1.0)
backend/— .NET solution: API, domain, infrastructure, and testsfrontend/— React + TypeScript SPAdeploy/— deployment templates for Unraid and TrueNAS SCALEsite/— static GitHub Pages project websitedocker-compose.yml— full self-hosted stack
Run the whole development stack from the repository root:
./scripts/dev-stack.shThe script reuses an existing ledgerra-postgres container or starts
PostgreSQL with Docker Compose if needed, then starts the backend and Vite
frontend if they are not already running. Defaults:
- API:
http://127.0.0.1:5027 - Frontend:
http://127.0.0.1:5173 - PostgreSQL:
localhost:5432
docker run --name ledgerra-postgres \
-e POSTGRES_DB=ledgerra \
-e POSTGRES_USER=ledgerra \
-e POSTGRES_PASSWORD=ledgerra \
-p 5432:5432 \
-d postgres:17-alpineUse this connection string for local backend development:
ConnectionStrings__Ledgerra="Host=localhost;Port=5432;Database=ledgerra;Username=ledgerra;Password=ledgerra"Example:
cd backend
ConnectionStrings__Ledgerra="Host=localhost;Port=5432;Database=ledgerra;Username=ledgerra;Password=ledgerra" \
dotnet run --project src/Ledgerra.Api/Ledgerra.Api.csprojIf you already run PostgreSQL natively, create:
- database:
ledgerra - user:
ledgerra - password:
ledgerra
cd backend
dotnet test Ledgerra.sln
dotnet run --project src/Ledgerra.Api/Ledgerra.Api.csprojThe API listens on http://localhost:5027 when started via the default launch profile. A basic health endpoint is available at /health.
cd frontend
npm install
npm test
npm run build
npm run devFor local browser development, set:
VITE_API_BASE_URL=http://localhost:5027If you do not set it, the frontend assumes same-origin /api, which is the production Docker behavior.
The site/ directory contains a static project website for GitHub Pages. It is
separate from the Ledgerra application and only describes the project, features,
stack, and self-hosting workflow. The included GitHub Actions workflow publishes
that static site after changes are merged to main.
In the repository settings, set Pages > Build and deployment > Source to GitHub Actions.
The included compose file is suitable for Docker or Unraid-style deployments:
docker compose up --build -dServices:
postgresstores the application databackendruns the ASP.NET Core API on internal port8080frontendserves the React app on host port8080and proxies/apito the backend
Before production use, change:
Auth__SigningKeyPOSTGRES_PASSWORD- any public-facing reverse proxy or TLS configuration
Tagged releases publish ready-to-run Docker images to GitHub Container Registry and attach deployment assets to the GitHub Release. This is the recommended path for Unraid OS, TrueNAS SCALE, and Linux hosts because the target machine only needs Docker Compose and does not need to build Ledgerra from source.
To publish a release, create and push a semantic version tag:
git tag v0.12.0
git push origin v0.12.0The release workflow runs backend and frontend checks, builds multi-architecture
Linux images for amd64 and arm64, pushes them to GHCR, and creates a GitHub
Release. The published image names are:
ghcr.io/<github-owner>/ledgerra-backend:<tag>
ghcr.io/<github-owner>/ledgerra-frontend:<tag>
The same images are also tagged as latest.
For release deployment, download these assets from the matching GitHub Release:
docker-compose.ymlenv.exampleunraid-ledgerra-stack.ymlandunraid-ledgerra-stack.env.examplefor Unraid Docker Compose Managertruenas-ledgerra-custom-app.yamlandtruenas-app-metadata.yamlfor TrueNAS SCALE custom app installsunraid-README.mdandtruenas-README.mdfor platform-specific steps
Then prepare the host:
mkdir -p ledgerra
cd ledgerra
cp env.example .envEdit .env before first start:
- set
POSTGRES_PASSWORDto a long random password - set
AUTH_SIGNING_KEYto at least 32 random characters - confirm
LEDGERRA_VERSIONmatches the release tag - change
LEDGERRA_HTTP_PORTif the host already uses port8080 - change
LEDGERRA_POSTGRES_DATAto a NAS-friendly appdata path if needed
Start Ledgerra:
docker compose pull
docker compose up -dUpgrade to a newer release by changing LEDGERRA_VERSION in .env, then run:
docker compose pull
docker compose up -dPlatform-specific deployment templates live in:
deploy/unraid/deploy/truenas/
Ledgerra can run on Unraid with the Docker Compose Manager plugin or from the Unraid terminal with Docker Compose.
-
Install the Docker Compose Manager plugin from Unraid Community Applications, or confirm that
docker composeis available in the Unraid terminal. -
Create an application directory:
mkdir -p /mnt/user/appdata/ledgerra/postgres
-
Download the release
docker-compose.ymlandenv.examplefrom the GitHub Release, then place them in/mnt/user/appdata/ledgerra. Renameenv.exampleto.env. -
Edit
/mnt/user/appdata/ledgerra/.envbefore first start:- Change
POSTGRES_PASSWORDin.env. - Replace
AUTH_SIGNING_KEYin.envwith a long random secret. - Change
LEDGERRA_HTTP_PORTif Unraid already uses8080. - Set
LEDGERRA_POSTGRES_DATA=/mnt/user/appdata/ledgerra/postgresfor Unraid-friendly backups.
- Change
-
Start Ledgerra:
cd /mnt/user/appdata/ledgerra docker compose pull docker compose up -d -
Open Ledgerra at
http://<unraid-server-ip>:8080, or the alternate host port you configured.
Useful maintenance commands:
cd /mnt/user/appdata/ledgerra
docker compose pull
docker compose up -d
docker compose logs -f
docker compose downKeep /mnt/user/appdata/ledgerra/postgres in your Unraid backup plan. That
directory contains the PostgreSQL data when using the recommended bind mount.
TrueNAS SCALE 24.10 and newer can install Ledgerra through the custom app YAML flow:
- Create a PostgreSQL data dataset such as
/mnt/tank/apps/ledgerra/postgres. - Open Apps > Discover Apps > more_vert > Install via YAML.
- Use
ledgerraas the app name. - Paste the release
truenas-ledgerra-custom-app.yamlinto the custom config editor. - Replace the example password, signing key, release tag, and dataset path.
- Save the app and open Ledgerra at
http://<truenas-ip>:8080.
Backend checks:
cd backend
dotnet test tests/Ledgerra.Domain.Tests/Ledgerra.Domain.Tests.csproj
dotnet test tests/Ledgerra.Api.Tests/Ledgerra.Api.Tests.csprojFrontend checks:
cd frontend
npm test
npm run build