A minimal, modern web app to track your recurring subscriptions. Works offline with local storage; sign in to sync across devices via Supabase.
Live: https://subscriptions.janat-t.com
- Dashboard — total monthly spend (annual subs normalized to monthly), spend-by-category and spend-by-payment-method donut charts (collapsible), full subscription list
- Sort & filter — sort by price, name, or next payment date; filter by category and payment method; search by name; filters live in a collapsible panel with active-count badge; charts reflect active filters
- Add / Edit / Delete subscriptions with confirmation dialog; mutations are optimistic with rollback — errors surface on the form or list rather than failing silently
- Payment methods — free-text input with suggestions (Credit Card, Apple Pay, Google Pay, PayPal, PayPay, Venmo); blank input stored as "Credit Card"
- Billing cycles — monthly or annually; annually shows a billing month picker; next payment date auto-calculated from billing day
- 10 categories — Entertainment, Productivity, Cloud/Storage, News & Media, Health & Fitness, Finance, Shopping, Gaming, Utilities, Other
- Settings — currency picker (USD, EUR, GBP, JPY, and more) + light/dark/system theme, grouped in a single gear icon
- Auth + cloud sync — optional Supabase sign-in (email/password + Google OAuth); localStorage is the write-through cache, DB is authoritative on load; "Save to cloud" button; pull from DB on tab focus; forgot password + password reset flow; change password in Settings
- Guest mode — app opens directly to dashboard; sign in only when you want cloud sync; data stays in localStorage until then
| Layer | Choice |
|---|---|
| Framework | React 18 + Vite 8 |
| Language | TypeScript (strict) |
| Styling | Tailwind CSS v4 |
| Components | shadcn/ui (base-ui primitives) |
| Charts | Recharts |
| Routing | React Router v7 |
| Storage | localStorage (primary) + Supabase Postgres (cloud) |
| Auth | Supabase email/password + Google OAuth |
| Deployment | Cloudflare Workers |
npm install
npm run dev # http://localhost:5173
npm run build
npm run deploy # Cloudflare Workerssrc/
├── types.ts # Subscription, Category, BillingCycle types
├── lib/
│ ├── supabase.ts # Supabase client
│ ├── storage.ts # localStorage + Supabase CRUD, syncToDatabase
│ └── utils.ts # monthlyEquivalent, nextPaymentDate, formatCurrency
├── hooks/
│ └── useSubscriptions.ts # CRUD state; localStorage-first, background DB sync
├── pages/
│ ├── Dashboard.tsx # / route
│ └── SubscriptionForm.tsx # /add and /edit/:id routes
└── components/
├── AuthGate.tsx # Auth form gate; "Continue without signing in"
├── SettingsDialog.tsx # Theme + currency settings
├── SubscriptionList.tsx
├── CategoryChart.tsx
└── DeleteConfirmDialog.tsx
- Upcoming payments — a "due this week / this month" section so you never get surprised by a charge
- Pause / inactive toggle — hide a subscription from totals without deleting it
- Export / import JSON — backup and restore
- Service emoji / icon — let the user pick an emoji per subscription to make the list scannable at a glance
- Trial end date — flag a subscription as a trial with a countdown to when it converts to paid
- Budget alert — warn when total monthly spend exceeds a user-set threshold
- PWA — installable to home screen; the app already works fully offline
See CONTEXT.md for precise definitions of terms used throughout the codebase.
This project was planned and implemented entirely using AI tooling as a demonstration of the 9ARM AI Passport workflow:
Planning — Requirements were gathered through a structured interview using the grill-with-docs skill in Claude Code, powered by Anthropic Claude Sonnet 4.6. Every product decision (tech stack, data model, UX behavior, routing) was resolved before a single line of code was written and captured in CONTEXT.md.
Implementation — Mechanical scaffolding and boilerplate (component files, type definitions, utility functions) were delegated to the qwen-agent skill, which routes tasks to the 9ARM gateway running Qwen3.6-35B-A3B (claude-9arm). This kept expensive Sonnet reasoning reserved for architecture decisions, debugging TypeScript errors, and verification.
Verification — The final app was verified end-to-end using Playwright headless Chromium, driven by the verify skill, before pushing.
Learn about AI Passport (by 9ARM): youtube.com/watch?v=ZUkVeXmD-Ek
| Tool | Role |
|---|---|
| Claude Sonnet 4.6 (Claude Code) | Planning, architecture, debugging, verification |
9ARM qwen-agent skill |
Scaffolding boilerplate component files |
| Qwen3.6-35B-A3B via 9ARM gateway | Executing the qwen-agent tasks |
grill-with-docs skill |
Structured requirements interview |
verify skill + Playwright |
End-to-end UI verification |
9ARM AI Passport lets you mix models mid-session — use a capable frontier model for reasoning and a fast/cheap model for mechanical work — without leaving your terminal.