One dashboard for every card and account you own.
Track credit limits, live balances, available credit, and spend power across all your financial accounts — secured per-user with Supabase Auth and Postgres Row-Level Security.
Simple Finance Tracker is a personal finance tracker that consolidates credit cards and bank accounts into a single, clean dashboard. After signing in, users see a live summary of total credit limits, current balances, and remaining available credit — updated instantly as accounts are added, edited, or removed.
Health indicators (color-coded green / yellow / red) surface accounts approaching their limit at a glance, and an optional spend power field lets users override the raw available-credit calculation when a card issuer reports a different figure.
- Unified dashboard — aggregate totals for limit, balance, and available credit shown as stat cards
- Credit cards & bank accounts — distinct account types with type-appropriate field handling (bank accounts have no credit limit)
- Spend power override — enter a card-issuer-reported spend power figure that takes precedence over the calculated available credit
- Color-coded health indicators — green (>50% available), yellow (20–50%), red (<20% or over limit)
- Over-limit detection — explicit warning when a balance exceeds the credit limit
- Per-account notes — freeform text field for storing card-specific context
- Secure per-user data — Supabase Auth with Postgres Row-Level Security; users can only access their own records
- Responsive layout — mobile-first design with drawer/sidebar patterns for small screens
- Dark mode — system-preference-aware theme via
next-themes - Full CRUD — add, edit, and delete accounts with optimistic UI updates and toast feedback
| Layer | Technology |
|---|---|
| Framework | React 18 + TypeScript 5.8 |
| Build tool | Vite 5.4 (SWC compiler) |
| Styling | Tailwind CSS 3.4 + shadcn/ui (Radix UI primitives) |
| Forms | react-hook-form 7 + Zod validation |
| State | React Context + useReducer |
| Backend / DB | Supabase (Postgres + Auth) |
| Routing | React Router v6 |
| Icons | Lucide React |
| Notifications | Sonner |
| Testing | Vitest 3 + Testing Library + jsdom |
| Package manager | npm (Bun lock files also present) |
my-money-compass/
├── src/
│ ├── components/
│ │ ├── finance/ # Domain components
│ │ │ ├── AccountCard.tsx # Individual account tile
│ │ │ ├── AccountList.tsx # Account list with empty state
│ │ │ ├── AddAccountForm.tsx # Validated add/edit form
│ │ │ ├── Header.tsx # Top bar + logout
│ │ │ └── SummaryDashboard.tsx # Aggregate stat cards
│ │ └── ui/ # 50+ shadcn/ui primitives
│ ├── context/
│ │ └── AppProvider.tsx # Global state (accounts CRUD + Supabase sync)
│ ├── integrations/
│ │ └── supabase/
│ │ ├── client.ts # Supabase client init
│ │ └── types.ts # Auto-generated DB types
│ ├── pages/
│ │ ├── Auth.tsx # Sign in / sign up
│ │ ├── Index.tsx # Main dashboard
│ │ └── NotFound.tsx # 404
│ ├── test/
│ │ ├── calculateTotals.test.ts
│ │ ├── reducer.test.ts
│ │ └── setup.ts
│ ├── types/
│ │ └── account.ts # Account, AppState, AppAction types
│ └── utils/
│ └── calculateTotals.ts # Financial aggregation + formatCurrency
├── supabase/
│ ├── config.toml
│ └── migrations/ # SQL migrations
├── vite.config.ts
├── vitest.config.ts
├── tailwind.config.ts
└── components.json # shadcn/ui config
Browser
└─ React Router
├─ /auth → Auth page (Supabase email/password)
└─ / → Index (protected)
└─ AppProvider (Context + useReducer)
├─ Supabase client (reads/writes accounts table)
├─ SummaryDashboard ← calculateTotals()
├─ AccountList
│ └─ AccountCard (edit / delete)
└─ AddAccountForm (react-hook-form + Zod)
Supabase (cloud)
├─ Auth — JWT session management
└─ Postgres
└─ accounts table
├─ Row-Level Security: users see only their own rows
└─ updated_at trigger (auto-timestamps)
State flows in one direction: Supabase mutations dispatch AppAction events into the reducer, which updates the context consumed by all components. No external state library is required.
- Node.js ≥ 18 (recommend installing via nvm)
- A Supabase project (free tier works) with the schema applied (see Database Schema)
# 1. Clone the repository
git clone https://github.com/andrewr303/my-money-compass.git
cd my-money-compass
# 2. Install dependencies
npm install
# 3. Configure environment variables
cp .env.example .env # then fill in your Supabase credentialsCreate a .env file in the project root with the following variables:
VITE_SUPABASE_URL=https://<your-project-id>.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=<your-supabase-anon-key>Both values are available in your Supabase project under Settings → API.
These are Vite public variables (prefixed
VITE_). They use Supabase's anon key, which is safe to include in frontend builds — Row-Level Security enforces data isolation server-side.
npm run dev
# → http://localhost:8080Apply the migrations in supabase/migrations/ to your Supabase project, or run the SQL below directly in the Supabase SQL editor.
create table accounts (
id uuid primary key default gen_random_uuid(),
user_id uuid references auth.users(id) on delete cascade not null,
type text check (type in ('credit_card', 'bank_account')) not null,
name text not null,
credit_limit numeric default 0,
current_balance numeric default 0,
spend_power numeric, -- optional override
notes text,
created_at timestamptz default now(),
updated_at timestamptz default now()
);
-- Row-Level Security
alter table accounts enable row level security;
create policy "Users manage own accounts"
on accounts for all
using (auth.uid() = user_id)
with check (auth.uid() = user_id);An updated_at trigger is included in the migration files.
| Command | Description |
|---|---|
npm run dev |
Start dev server at http://localhost:8080 with HMR |
npm run build |
Production build (output: dist/) |
npm run build:dev |
Development-mode build |
npm run preview |
Serve the production build locally |
npm run lint |
Run ESLint across the codebase |
npm run test |
Run all tests once |
npm run test:watch |
Run tests in interactive watch mode |
Tests live in src/test/ and run with Vitest in a jsdom environment.
npm run test # single pass
npm run test:watch # watch mode (re-runs on file save)Current coverage includes:
calculateTotals.test.ts— financial aggregation logic: empty state, single credit card, mixed account types, over-limit scenariosreducer.test.ts— AppState reducer actions (SET, ADD, UPDATE, DELETE)
If the project was set up via Lovable, open your Lovable project and click Share → Publish. Custom domains can be connected under Project → Settings → Domains.
npm run build
# Deploy the contents of dist/ to any static hosting provider
# (Vercel, Netlify, Cloudflare Pages, S3 + CloudFront, etc.)The app is a fully static SPA — no server runtime required. Just point your host at dist/ and configure it to serve index.html for all routes.
- Path alias:
@resolves tosrc/— use@/components/...instead of relative paths - Component library: shadcn/ui components live in
src/components/ui/. Add new ones withnpx shadcn@latest add <component> - Supabase types: Re-generate after schema changes with
npx supabase gen types typescript --project-id <id> > src/integrations/supabase/types.ts - TypeScript strictness is currently permissive (
strict: false). Tightening this is a good first contribution
- Fork the repository and create a feature branch (
git checkout -b feat/your-feature) - Make your changes, add tests where appropriate
- Run
npm run lint && npm run testand ensure both pass - Open a pull request with a clear description of the change
Bug reports and feature requests are welcome via GitHub Issues.