A modern, minimal personal finance tracking application built with a focus on clarity, scalability, and AI-assisted development.
Spendrift helps users track:
- Daily expenses (Needs vs Wants)
- Monthly budgets and savings targets
- Financial reports (weekly / monthly / yearly)
- Multi-year spending comparisons
- Category breakdowns and analytics
The app is designed as a tracker-based system, where each tracker represents an independent financial workspace with its own currency (e.g., Bangladesh Tracker in BDT, Europe Tracker in EUR).
All features are backed by the real Spendrift API (FastAPI) β see Getting Started.
- TanStack Start β full-stack React framework (SSR + file-based routing)
- React + TypeScript
- TailwindCSS + ShadCN UI (Radix primitives)
- TanStack Query β server-state, caching, and invalidation
- Zod + React Hook Form β schema validation
- Recharts (via ShadCN charts), Sonner (toasts)
- Biome β formatter + linter
- Vitest β unit tests
- Sentry β error monitoring
- Node.js 20+ and pnpm
- A running Spendrift API (FastAPI). The frontend expects it at
http://localhost:8000with the base path/api/v1. Interactive API docs live athttp://localhost:8000/docs.
# 1. Install dependencies
pnpm install
# 2. Create your local env file
cp .env.example .env.local
# then set VITE_API_BASE_URL (default: http://localhost:8000/api/v1)
# 3. Start the dev server (http://localhost:3000)
pnpm dev| Variable | Required | Description |
|---|---|---|
VITE_API_BASE_URL |
β | Base URL of the Spendrift API, including the /api/v1 prefix. |
VITE_APP_TITLE |
optional | App title override. |
VITE_SENTRY_* / SENTRY_* |
optional | Sentry monitoring (see .env.example). |
pnpm dev # start the dev server on :3000
pnpm test # run the Vitest unit suite
pnpm check # Biome lint + format check
pnpm build # production build
pnpm start # serve the production buildSpendrift follows a Domain-Driven, Feature-Based Architecture. Each feature is self-contained and split into three layers:
src/features/<feature>/
βββ domain/ # types + pure business logic (services.ts)
βββ data/ # repository.ts (API calls), dto.ts (wire mapping), queryKeys.ts
βββ presentation/ # pages + React Query hooks (use*.ts)
Pages and hooks never call fetch directly. Every feature talks to the API through its data/repository.ts, which is the single swap seam:
Page β presentation/use*.ts (TanStack Query) β data/repository.ts β shared/api/client.ts
Two impedance mismatches are handled at the data/dto.ts boundary so the domain stays clean:
- Money is a Decimal string on the wire (e.g.
"1267.42") βnumberin the domain. - Casing: API is
snake_caseβ domain iscamelCase.
JWT access + refresh tokens (stored in localStorage) with a single-flight refresh-on-401 retry in shared/api/client.ts. Because tokens aren't readable during SSR, a client-side WorkspaceGate (in routes/__root.tsx) is the auth source of truth.
- Feature-based structure, cohesive domains
- Separation of UI from business logic
- Repositories as the single API seam
- Composition over abstraction; avoid premature optimization
Each tracker is an independent financial context with its own currency:
- π§π© Bangladesh Tracker (BDT)
- πͺπΊ Europe Tracker (EUR)
Each tracker owns its expenses, categories, budgets, dashboard, and reports. The active tracker is carried in the URL as ?tracker=<id>.
- Add / edit / delete expenses
- Needs vs Wants tagging
- Search, date-range, type, and category filtering
- Per-category management (with safe "reassign to Uncategorized" on delete)
- One budget per tracker per current month
- Monthly limit + savings target
- Remaining balance and a savings-health indicator (green / yellow / red)
- Previous months become read-only history
- Current-month spend, expense count, and budget remaining
- Needs-vs-Wants split and top categories
- Cashflow trend + recent expenses
- Weekly / monthly / yearly spending
- Category breakdown and Needs-vs-Wants
- Year-over-year comparison
- Total / min / max / average analytics
- Custom calendar date ranges
Spendrift is designed to feel minimal, calm, modern, and data-focused β inspired by Linear, Notion, and modern fintech dashboards.
- Dark theme first
- High readability and clear hierarchy
- Meaningful colors (not decorative)
- Reduced visual noise
An emerald-forward palette defined as oklch design tokens in src/styles.css (light and dark variants). The default is dark; a stored preference wins. Charts use ShadCN's chart components.
Unit tests cover the pure domain/services functions (budgets, expenses, reports) with Vitest:
pnpm testTests run in an isolated vitest.config.ts (node environment, @/ alias) so they skip the full app plugin chain.
src/
βββ features/ # dashboard, expenses, budgets, reports, trackers
β βββ <feature>/ # domain/ Β· data/ Β· presentation/
βββ shared/
β βββ api/ # apiFetch client + token storage
β βββ ui/ # shared UI (AppSidebar, StatCard, ThemeToggleβ¦)
β βββ hooks/
β βββ utils/
βββ components/ui/ # ShadCN-generated primitives
βββ routes/ # TanStack Start file-based routes
βββ styles.css
- Plan the feature structure first
- Break it into small steps
- Implement incrementally behind the repository seam
- Verify (tests + run the app)
- Commit using conventional commits
feat(expenses): add expense list UI
fix(budget): correct remaining balance calculation
refactor(api): back reports with the real API
This project leans on AI for architecture planning, code explanation, UI exploration, and refactoring β used as a mentor and assistant, not an autopilot. The goal is learning by building, not blind generation.
- Investment tracking
- Loan management
- AI-powered financial insights
- Multi-user SaaS support
- Mobile optimization
- SSR auth via httpOnly cookies (currently a client-side gate)
Copyright (c) 2026 Dipto Karmakar
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See the LICENSE file for full terms.
In plain English:
- You may study and use this code for personal/educational purposes
- If you modify and distribute it, you must open-source your version under AGPL-3.0
- You may not use this in a commercial product or SaaS without written permission from the author
- You must credit the original author (Dipto Karmakar) in any derivative work
For commercial licensing inquiries: diptokmk47@gmail.com
Dipto Karmakar β Frontend engineer focused on React / TypeScript, domain-driven design, high-performance UI, and AI-assisted workflows. Spendrift is a personal initiative to explore modern fintech UX and scalable SaaS architecture.





