v1.9.13 · Released · April 26, 2026
Global Ledger + Link Previews + Admin Bulk Moderation
New Ledger surface shows every transaction across every account in chronological order with running totals for Assets, Liabilities, and Net Worth. Pasting the app's URL into Slack, iMessage, Twitter, or Facebook now produces a proper preview card. Admin Feature Requests gains bulk status updates and deletion. Also: a defensive guard against direct writes to Account.balance, plus a permanent fix for the root-owned-files Docker problem on local dev.
Global Ledger
- New **Ledger** page (sidebar, between Accounts and Transactions) shows every Income, Expense, Transfer, and opening-balance row across every account in chronological order — the unified ledger view that complements the per-account ledgers under each Account detail page.
- Three KPI cards at the top: Total Assets, Total Liabilities, Net Worth. Each shows the delta over the visible filter window so you can see how the period moved your finances.
- Per-row running totals for Assets ↑, Liabilities ↑, and Net Worth ↑ are computed from a single chronological walk of the full transaction trail. They reflect your actual state at each moment regardless of any filters applied — not just a sum of the filtered rows.
- Filters: date range picker (defaults to All time), Type chips (Income / Expense / Transfer / Payment), and per-account chip multi-select. Reset button clears all filters at once.
- Page-size selector (25 / 50 / 100). Fixed chronological sort — running totals are only meaningful in date order.
- Discrepancy tripwire: if the walked running totals ever disagree with the sum of account balances by ≥ ₱0.01, a banner surfaces at the top so you know the data is out of sync before you trust it.
Link Previews
- Pasting `budgetplanner.app` (or any link to the landing page) into Slack, Twitter, Facebook, iMessage, Discord, etc. now shows a 1200×630 preview card with the Budget Planner wordmark, the headline, a tagline, and a peek of the dashboard.
- Image is generated at request time via Next.js `ImageResponse` — no static asset to maintain, and the same renderer powers the Twitter card so both unfurl identically.
- `metadataBase` is now set on the root layout, so all relative metadata URLs resolve to absolute (required by every major crawler).
Admin — Feature Requests Bulk Actions
- Checkbox column on the Feature Requests table with header tristate (none / some / all-on-page) and per-row selection.
- Bulk action bar appears with the count and two actions: **Set status** (any of NEW / REVIEWING / PLANNED / COMPLETED / DECLINED, applied to all selected rows) and **Delete** (with a destructive confirm).
- Up to 100 requests per batch. Selection clears automatically when you change a filter or paginate, preventing stale-ID mistakes.
- Admin role + active sudo session are required server-side for both bulk endpoints.
Correctness Guards
- Edit Account form can no longer accept `balance` or `openingBalance` in its payload (Zod schema + service-layer strip). Manual balance changes already route through the **Adjust Balance** flow, which records a real Income or Expense row — this guard prevents a future caller from bypassing that trail and desyncing the ledger tripwire.
Local Dev
- Docker `app` container now runs as the host user (`HOST_UID:HOST_GID`, defaulting to 1000:1000). Files Prisma / Next.js / TypeScript write onto the bind-mounted project dir are owned by your user, not `root` — no more `sudo chown` after every `git pull`.
- Override via `HOST_UID` / `HOST_GID` env vars if your host UID differs. See `CLAUDE.md` for the recovery command for pre-existing root-owned files.