Sumptus — Data Sovereignty. Self-hosted household expense tracking: who paid what, who owes whom, and where the money goes — by category, by month, by label. Built for a family or a shared flat; everything stays on your own machine.
A public instance with fictional data (a two-person household with ~2 years of expenses) is hosted for review:
- No account needed: browse, add and edit freely.
- The demo is reset every night — nothing you type there is kept, and no real data is ever connected to it.
- Expenses — date, label, description, amount, category, paid by, paid-from account
- Label combobox — browse or type-to-filter your own label history (accent-insensitive), and label → category links that preselect the category as you type
- Splitting — equal split, custom percentage default, or a custom amount per member (validated)
- Balance — paid vs owed per member, with a simplified "who owes whom" settlement
- Details — per-category, per-month and per-label breakdowns (label totals by year)
- Charts — yearly totals, category donut, monthly trend, category × year stacked bars (Chart.js, bundled)
- List tools — sort on every column, per-column filters (category, payer, amount range, date range)
- Discreet mode — hides every amount (keeps the charts readable)
- Settings — members, accounts (joint / personal), categories; inline editing
- SQLite — zero external dependencies
- Demo dataset —
SEED_DEMO=1inserts the fictional household on first boot (empty database only) - Backup — full JSON export / restore from the Settings page (all-or-nothing import; the desktop build saves through a native dialog), plus a CSV export of the expense list
- Desktop builds (Windows / macOS) — standalone packages (
Sumptus-Windows.zip,Sumptus-macOS.zip, attached to each release): no Python, no Docker, data next to the app
- Backend: Python FastAPI + SQLite (stdlib, no ORM)
- Frontend: vanilla JS + Chart.js (single page, bundled)
- Deploy: Docker — private LAN compose + Traefik demo compose
cd backend
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8020Private LAN (no reverse proxy, never exposed to the internet):
cp .env.example .env # adjust PORT / SEED_DEMO if needed
docker compose -f docker-compose.lan.yml up -d --build
# open http://localhost:8020Public demo (Traefik + Let's Encrypt; create the DNS record first):
echo "DOMAIN=your-domain.example.com" >> .env
docker compose up -d --buildEach release ships standalone desktop packages:
Sumptus-Windows.zip: unzip anywhere (avoidProgram Files), double-clickSumptus.exe— the app opens in its own window.Sumptus-macOS.zip: unzip anywhere, double-clickSumptus.app(first launch: right-click → Open, unsigned build).
In both cases data lives in the data/ folder next to the app (on macOS
it falls back to ~/Library/Application Support/Sumptus if that folder is
read-only, e.g. launched from a mounted image); backup = copy that folder.
Each zip includes user guides in French, English, German and
Luxembourgish.
| Variable | Default | Description |
|---|---|---|
PORT |
8020 |
HTTP port |
DB_PATH |
/data/sumptus.db |
SQLite database file (container: /data) |
SEED_DEMO |
0 |
1 = insert the fictional demo dataset on first boot (empty database only) |
| Method | Path | Description |
|---|---|---|
| GET | /api/health |
Liveness + app name + version |
| GET | /api/version |
Current version |
| GET/POST | /api/members |
List / create members |
| PUT/DELETE | /api/members/{id} |
Edit / delete member (delete blocked if expenses exist) |
| GET/POST | /api/accounts |
List / create accounts (joint or personal) |
| PUT/DELETE | /api/accounts/{id} |
Edit / delete account |
| GET/POST | /api/categories |
List / create categories |
| PUT/DELETE | /api/categories/{id} |
Edit / delete category |
| GET | /api/expenses?month=YYYY-MM&category_id=N |
List expenses (filtered) |
| POST | /api/expenses |
Create expense (equal or custom split) |
| PUT/DELETE | /api/expenses/{id} |
Edit / delete expense |
| GET | /api/balance |
Balances + net debts |
| GET | /api/stats?month=YYYY-MM |
Totals, per category, per month |
| GET | /api/stats/analytics |
Chart datasets (year / category / month) |
| GET | /api/stats/labels |
Per-label totals and per-year breakdown |
| GET/PUT | /api/settings |
Default split + dashboard panels |
| GET/PUT | /api/label-categories |
Label → category links |
| GET | /api/export |
Full JSON backup (members, accounts, categories, expenses + shares, settings) |
| POST | /api/import |
Restore a JSON backup (replaces all data, all-or-nothing) |
| GET | /api/export/csv |
Expense list as CSV (Excel-friendly) |
backend/
├── app/
│ ├── main.py # FastAPI app (health/version endpoints, startup seed)
│ ├── db.py # SQLite schema + connection
│ ├── seed.py # fictional demo household (SEED_DEMO=1)
│ ├── routes/api.py # API routes
│ └── static/ # frontend (single page) + brand assets
└── tests/ # pytest suite
desktop/ # Desktop packages (PyInstaller: Windows + macOS)
MIT — see LICENSE.
