Offline-first personal finance, allocated like a cat plans its naps.
Budgets, debts, goals, and net worth — all in one minimalist PWA that works without a network and syncs when it has one.
- About
- Features
- Tech Stack
- Architecture
- Getting Started
- Supabase Setup
- Environment Variables
- Available Scripts
- Project Structure
- Roadmap
- Contributing
- Code of Conduct
- License
- Maintainer
- Acknowledgements
AlloCat is a minimalist, offline-first personal-finance PWA. Track budgets, debts, savings goals, assets, and net worth in one place. The app reads from a local IndexedDB cache first and reconciles with Supabase in the background, so it stays fast and usable even on flaky networks or fully offline.
Hosted at grow.allocat.xyz. Works on mobile, desktop, and installs as a PWA.
- Budget — monthly budgets with categories, items, and templates
- Debt — track loans, EMIs, payoff progress
- Goals — savings goals merged with assets for unified net-worth view
- Net Worth — assets, liabilities, history snapshots
- Activity Log — audit trail of every change with INR-formatted summaries
- AI Chat — ask questions about your finances; OpenRouter-powered, topic-guarded
- Offline-first — IndexedDB cache + mutation queue; full functionality without network
- PWA — installable on iOS, Android, desktop; service worker pre-cached
- Onboarding tour — Driver.js-guided walkthrough on first visit
| Layer | Tech |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| UI | React 19, Tailwind CSS v4 |
| State / cache | TanStack Query 5 |
| Local DB | Dexie (IndexedDB) |
| Backend | Supabase (Postgres + Auth + RLS) |
| Auth | @supabase/ssr (cookie sessions) |
| AI | OpenRouter streaming chat |
| PWA | @ducanh2912/next-pwa |
| Tour | Driver.js |
| Icons | Lucide + Material Symbols Outlined |
| Fonts | Inter Tight, Bricolage Grotesque, JetBrains Mono |
AlloCat is offline-first. Three layers cooperate:
- IDB cache (
lib/db/AllocatDB.ts) — Dexie schema mirrors Supabase tables plus three sync tables (sync_queue,id_map,sync_meta). Every page reads here first. - Hydration + prefetch (
lib/providers/SyncProvider.tsx) — on mount, bulk-pulls all tables for the active user into IDB, then warms React Query cache so first navigation has zero skeletons. Wipes IDB on user switch. - Mutation queue (
lib/sync/SyncEngine.ts) — mutations write to IDB optimistically withtemp_<uuid>ids, enqueue aSyncQueueItem, then SyncEngine drains it via server actions. Failed items retry with backoff (max 3); permanent failures roll back and invalidate query keys.
Server actions in lib/actions/<domain>.ts are the only path that talks to Supabase from the client. Read hooks (lib/hooks/use<Domain>.ts) follow the pattern: try IDB → fall back to server action.
See CLAUDE.md for a deeper dive intended for AI assistants and contributors.
- Node.js 20+ (LTS recommended)
- pnpm 9+ — this project pins pnpm via
pnpm-lock.yaml. Install withnpm i -g pnpmif you don't have it. - Supabase project (free tier works) — see Supabase Setup
- OpenRouter API key (optional, only for AI chat) — openrouter.ai
# 1. Clone
git clone https://github.com/devoctane/allocat.git
cd allocat
# 2. Install
pnpm install
# 3. Configure env
cp .env.example .env.local
# fill in NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY, OPENROUTER_API_KEY
# 4. Run migrations on your Supabase project (see Supabase Setup below)
# 5. Start dev server
pnpm devOpen http://localhost:3000.
AlloCat needs Postgres tables, Row Level Security policies, and auth wired up.
Go to supabase.com, create a new project, and grab:
- Project URL →
NEXT_PUBLIC_SUPABASE_URL - Publishable (anon) key →
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY
SQL migrations live in supabase/migrations/. Apply them in order using either:
Option A — Supabase CLI (recommended)
# install CLI: https://supabase.com/docs/guides/cli
supabase link --project-ref <your-project-ref>
supabase db pushOption B — SQL Editor (manual)
Open the Supabase dashboard → SQL Editor → paste each file from supabase/migrations/ in chronological order and run.
After migrations, your Postgres should have: profiles, budgets, categories, budget_items, goals, assets, asset_categories, asset_value_history, debts, reports, net_worth_snapshots, activity_logs.
Note: if
activity_logsis missing, the activity feed will silently no-op. Confirm migrations ran.
In Supabase dashboard → Authentication → Providers, enable:
- Email (default)
- Google OAuth (optional, used by
/auth/oauth-callback)
Set the redirect URL to http://localhost:3000/auth/oauth-callback for dev and your production domain for prod.
Row Level Security policies are included in the migration files. Verify they are enabled on every table after applying — without RLS, every user sees every row.
Copy .env.example to .env.local and fill in:
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Yes | Supabase project URL |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY |
Yes | Supabase publishable (anon) key |
OPENROUTER_API_KEY |
No | OpenRouter API key for AI chat. Omit to disable /api/ai/chat. |
Never commit .env.local. It is gitignored.
pnpm dev # Next dev server (Turbopack)
pnpm build # Production build (PWA enabled)
pnpm start # Start production server
pnpm lint # ESLint (flat config)No test runner is configured yet — see Roadmap. For type checking:
pnpm exec tsc --noEmitallocat/
├── app/
│ ├── (app)/ # Protected app shell — dashboard, budget, debt, goals, net-worth, profile, activity
│ ├── auth/ # Login, signup, OAuth callback
│ ├── onboarding/ # Post-signup flow
│ ├── api/ai/chat/ # Streaming AI chat endpoint
│ └── manifest.ts # PWA manifest
├── components/ # UI components organized by domain
├── lib/
│ ├── actions/ # Server actions (only Supabase entrypoint from client)
│ ├── db/ # Dexie schema, hydration, prefetch
│ ├── hooks/ # Read hooks (IDB → server action fallback)
│ ├── providers/ # SyncProvider, query client, theme
│ ├── server/ # activity-logger and other server-only utils
│ ├── sync/ # SyncEngine, mutation queue
│ ├── supabase/ # client/server/middleware Supabase factories
│ └── tour/ # Driver.js tour steps + context
├── public/ # Static assets, PWA icons
├── supabase/migrations/ # SQL migrations
├── proxy.ts # Next.js middleware (named proxy.ts in Next 16)
└── CLAUDE.md # Architecture deep-dive
Path alias: @/* → repo root.
- Test suite (Vitest + Playwright)
- Multi-currency support (currently hardcoded
en-IN/ INR) - Recurring transactions
- CSV import / export
- Bank statement parsing
- Self-host guide (Docker compose with Supabase local)
- i18n
- Public API + webhook integrations
- Shared / household budgets
Have an idea? Open an issue.
Contributions are welcome and appreciated. Whether it is a bug report, feature request, doc fix, or pull request — every bit helps.
- Fork the repo and clone your fork
- Branch from
main:git checkout -b feat/your-featureorfix/your-bug - Install deps:
pnpm install - Hack away. Keep changes focused — one PR, one concern.
- Lint before pushing:
pnpm lint - Type-check:
pnpm exec tsc --noEmit - Commit using Conventional Commits:
feat:,fix:,docs:,refactor:,perf:,chore: - Push and open a PR against
main
- Lint passes
- Type check passes
- Existing offline-first patterns preserved (IDB → enqueue → invalidate)
- New tables / operations registered in
SyncEnginedispatch table - No secrets committed
- Screenshots / video for UI changes
- CLAUDE.md updated if architecture changed
- Tests (currently none)
- Multi-currency formatting
- Accessibility audit
- Documentation and tutorials
- Migration tooling for self-hosters
Open an issue with:
- What you expected
- What happened
- Steps to reproduce
- Browser / OS / app version
- Screenshots if relevant
Found a security issue? Do not open a public issue. Email ashwinkv.octane@gmail.com directly.
Be kind. Be respectful. Assume good faith. Harassment, discrimination, or hostile behavior is not tolerated and will result in removal from the project.
This project follows the spirit of the Contributor Covenant. Report violations to ashwinkv.octane@gmail.com.
MIT © Octane
Ashwin KV — @devoctane · ashwinkv.octane@gmail.com
Built on the shoulders of:
Made with care by Octane.