A privacy-first, offline-capable personal finance PWA built with Eleventy (11ty), Tailwind CSS, and IndexedDB. Supports transactions with accounts and transfers, budgets with monthly usage, and robust offline caching via a service worker.
Prereqs: Node 18+ recommended.
npm install
npm run dev- App runs at http://localhost:8080 by default (Eleventy dev server)
- CSS/JS bundles are emitted to
src/assets/dist/ - PWA service worker is served from
src/assets/workers/sw.jsand caches the app shell for offline
npm run devβ Start Eleventy dev server + watch Tailwind and JS (esbuild)npm run buildβ Production build (minified CSS/JS) + Eleventy output in_site/npm run testβ Run unit tests oncenpm run test:watchβ Run unit tests in watch mode
src/_includes/layouts/β Nunjucks layoutssrc/pages/β App pagessrc/assets/css/main.cssβ Tailwind entrysrc/assets/js/app.jsβ App JS entrysrc/assets/js/core/db.jsβ IndexedDB helpers and stores (transactions, categories, accounts, settings, receipts, budgets)src/assets/workers/sw.jsβ Service workersrc/manifest.jsonβ PWA manifesttests/β Vitest tests (happy-dom + fake-indexeddb)
Key pages:
src/pages/index.njkβ Dashboard (account overview, recent transactions, budget summary)src/pages/transactions/index.njkβ Transactions (add, list, filters; supports transfers)src/pages/budgets/index.njkβ Budgets (create, list, monthly usage)src/pages/categories/index.njkβ Categories (seeded defaults, add)src/pages/accounts/index.njkβ Accounts (add, list)
- Transactions: expenses/income with category, account, date, description
- Transfers: create two linked entries (outflow/inflow) with shared
transferId - Filters: search by description, filter by category and account
- Budgets: create monthly budgets per category; usage computed from current-month transactions
- Dashboard: account overview, recent transactions, budget summary
- PWA: offline-first app shell; stale-while-revalidate for assets; network-first with cache fallback
Uses Vitest with happy-dom and fake-indexeddb.
npm run testTests include:
- DB helpers for transactions, categories, accounts, budgets
- Transactions page (add, filters) and transfer linkage
- Dashboard rendering
- Service worker offline caching behavior
- Data is stored locally in IndexedDB β privacy-first, no external APIs.
- Seeding uses idempotent helpers to avoid duplicate categories in tests.
- Make sure to hard-refresh to update the service worker after changes.