English | 한국어
A family budget desktop app built with Go + Wails v2 + React/TS + Supabase (Postgres).
Register transactions manually. Once you label a transaction, a "merchant + amount range" fingerprint rule classifies the same recurring charge automatically from the next month on. For example, three LG U+ auto-payments that differ only in amount can be labeled once as Dad / Kid / Internet — after that, the app tells you whose bill each charge is, every month, automatically.
- Dashboard — monthly income/expense/transfer summary with month-over-month deltas, an alert panel (budget overruns, card-target risk, unclassified backlog), 6-month trend chart, daily spending + cumulative line, per-category budget gauges, category/member donut charts, top merchants, per-card performance widgets
- Transactions — manual entry (cash, dues, gifts); search by merchant/memo plus amount/period/category/member/payment-method filters and sorting; edit via modal; multi-select bulk re-classify/delete with one-click undo; "apply rules to unclassified" to retroactively classify; CSV export of the current view (Excel-friendly, UTF-8 BOM)
- Cards — register cards with issuer, billing day, performance period and spending target; track whether the target is met in the current period; per-card breakdown by merchant and category; custom chip colors
- Statistics (dedicated tab) — daily / cumulative spending by card, member, or category (dimension + mode toggles); this-month vs. previous-month cumulative comparison at the same day; weekday spending averages; 6-month category trend; per-card category composition (stacked bars); per-member analysis (category composition, 6-month trend, and a summary card per member with total, share, top category/merchant and month-over-month change); card performance pace toward target; recurring/fixed-cost tracker (which monthly charges have or haven't posted yet); yearly summary with year-over-year deltas
- Budget — set a recurring monthly budget per category, with optional per-month overrides; the dashboard shows usage gauges and raises alerts on overruns
- Auto-classification — a fingerprint rule (merchant + amount ±8%) is learned whenever you classify a transaction. On manual entry a matching rule takes priority over form defaults and classifies automatically. Add/edit/delete rules manually in Settings
- Dark mode — toggle in the header, remembered across launches
wails dev # development mode (hot reload)
wails build # production build → build/bin/sobi.app (.exe when built on Windows)The app needs a Supabase connection string. On first launch an empty template file is created — open it and fill in the value.
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/sobi/config.json |
| Windows | %AppData%\sobi\config.json (usually C:\Users\<name>\AppData\Roaming\sobi\config.json) |
| Linux | ~/.config/sobi/config.json |
{
"database_url": "postgresql://postgres.xxxxxxxxxxxx:PASSWORD@aws-1-ap-southeast-1.pooler.supabase.com:5432/postgres"
}- Get the URI from the Supabase dashboard → Connect → Session pooler. (Direct connection is IPv6-only; Session pooler is recommended for home networks. Transaction pooler on port 6543 also works — the app switches to a compatible mode automatically.)
- Replace
[YOUR-PASSWORD]with the actual DB password. Special characters such as* : @ / !can be pasted as-is — the app URL-encodes them automatically. - Saving with Windows Notepad is fine (UTF-8 BOM is tolerated).
Put the same database_url into config.json on another PC to share the same ledger.
On connect, if Supabase is empty and a legacy local DB (sobi.db) exists in the same
folder, all data is migrated to Supabase automatically (the local file is kept as a backup).
Supabase stays the operational database, but the app also takes periodic local snapshots to
a self-contained SQLite file — shortly after startup, every 6 hours while running, and on
shutdown. The 7 most recent snapshots are kept (older ones pruned). You can also trigger one
manually from Settings → 로컬 백업. Files live in <config dir>/backups/sobi_YYYYMMDD_HHMMSS.db
(e.g. %AppData%\sobi\backups\ on Windows) and are full, openable DBs you can restore from.
All backend errors (connection failures, insert/update errors) are logged here. Check this file first when something goes wrong — the app creates it automatically.
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/sobi/sobi.log |
| Windows | %AppData%\sobi\sobi.log |
| Linux | ~/.config/sobi/sobi.log |
If the connection fails the app does not quit; an error banner appears at the top and the "reconnect" button recovers without a restart once the config is fixed.
app.go— Wails bindings (API called from the frontend, reconnect/logging, aggregate dashboard endpoint, CSV export, alerts, recurring/budget helpers)internal/store— Supabase (Postgres) schema/queries; analytics & statistics (analytics.go,stats.go); budgets (budget.go); config/log paths; SQLite migrationinternal/classifier— auto-classification rule learning/matching (±8% amount tolerance)frontend/src/pages— Dashboard / Transactions (incl. manual entry) / Cards / Subscriptions / Cashback / Statistics / Settings
DB tests need Postgres (skipped automatically when unavailable):
docker run -d --rm --name sobi-test-pg -e POSTGRES_PASSWORD=test -e POSTGRES_DB=sobi -p 55432:5432 postgres:16-alpine
TEST_DATABASE_URL='postgres://postgres:test@localhost:55432/sobi?sslmode=disable' go test ./...
docker stop sobi-test-pg- Member: who the money was spent for (Dad / Mom / Kid / Shared)
- Category: purpose;
kinddistinguishes income/expense/transfer (salary, telecom, loan repayment, dues, investment transfer, …). Categories form a two-level main/sub hierarchy — e.g.식비 > 배달. A transaction can be filed against either a main or a sub category. Statistics and budgets roll sub-category spending up into the main category by default (the Statistics tab has a 주/부 toggle for sub-level detail), and a budget set on a main category is judged against the sum of itself plus its subs. On first connect, existing names like식비/배달are split into식비 > 배달automatically — but only when the prefix already exists as a category, so names such as회비/경조사are left intact. - Cashback: a card can carry a base rate (e.g. 1% of every charge) plus a bonus rate granted when the card bill for that charge is paid within N days (e.g. +1% within 5 days). Set the rates and window on the card in the Cards tab; the 캐시백 (Cashback) tab lists what is still claimable with a countdown, what was earned, and what was missed. Mark a charge paid there in one click.
- Payment method: which card/cash/bank account it went through; cards carry billing day / performance period / target managed in the Cards tab. A transaction can be flagged 실적 제외 (exclude from card performance) — for charges card issuers don't count toward the spending target, such as taxes and utility bills. Set it with the checkbox on manual entry or in the edit modal, or mark several at once from the Transactions bulk bar. Excluded charges are left out of card performance and pace only; they still count in every normal expense statistic, and the card widgets show the excluded total so the numbers reconcile.
- Card benefit: reference material copied from the issuer's own page. Pick a card in the Cards
tab and you get its annual fee (domestic/overseas) and prior-month spending requirement plus a
table of
area / kind (points, discount, service) / rate / monthly cap / note, editable and reorderable in place. Issuers usually advertise a tier-dependent headline ("up to 4.5%"), so each row can be marked 최대치 (headline maximum) and 확인 필요 (details unverified) — that way you can tell later how much to trust the number. The source URL and any caveats live on the card form. The app does not compute earnings from these rows; that is what the cashback settings do. - Budget: an optional monthly spending limit per category; set a recurring default and override specific months in Settings; the dashboard tracks usage and flags overruns
- Rule: learned automatically whenever you confirm a classification; on a match it takes priority over manual-entry defaults; review/add/edit/delete in the Settings tab. A rule that recurs across months also drives the Statistics tab's fixed-cost tracker