A cross-platform personal expense and budget tracking mobile application built with Vue 3, Ionic Framework 8, Capacitor 8, and Supabase.
Designed for mobile devices (Android & iOS) as well as the web, featuring clean hexagonal architecture, native gestures, customizable spending categories, and period-based reporting.
- Features
- Architecture & Design
- Tech Stack
- Project Structure
- Prerequisites
- Getting Started
- Environment Variables
- Mobile Development (Capacitor)
- Available Scripts
- Testing & Quality Assurance
- Database & Supabase Integration
- Documentation & ADRs
- π³ Transaction Tracking: Log daily expenses with amount, title, date, and category. Quick overview of total expenses on the main dashboard.
- π Expense Categories: Group spending by pre-defined categories with intuitive iconography (Food, Housing, Transportation, Health, Shopping, Entertainment, Education, Pets, Utilities, etc.).
- π Period Reports & Analytics: Filter expenses across time horizons (Today, Week, Month, Year, Custom Range) with per-category totals and visual spending distributions.
- π± Native Mobile Gestures:
- Pull-to-refresh on transaction feeds.
- Swipe/slide gestures on list items to edit or delete transactions.
- Native haptics and keyboard handling via Capacitor plugins.
- π Programmatic Toast Feedback: Clean toast notifications for user actions via the reusable
useToastcomposable. - π¨ Design System v2: Modern visual design using semantic CSS variables and design tokens (
--ds-*).
The application follows modular and decoupled design principles:
Pinia setup stores (transactionStore, categoryStore, reportStore) interact with persistent storage solely through an abstract port interface: BudgetStorage (src/core/storage/types.ts).
- Production Adapter (
SupabaseStorage): Uses@supabase/supabase-jsto communicate with Supabase PostgREST endpoints. Encapsulates lazy environment variable validation, camelCase β snake_case mapping, and error normalization. - Testing / Mock Adapter (
InMemoryStorage): Fast, in-memory implementation seeded with test fixtures. Enables 100% deterministic unit testing without network mocks or Supabase credentials.
For details, refer to ADR 0001: Domain Storage Seam.
Code is organized by vertical feature modules under src/modules/<feature>/:
transactions: Dashboard view, transaction lists, add transaction form, update modal, slide list items, and transaction store.categories: Category selection grid and category store.reports: Spending breakdown by category, period filter bar, report headers, and report store.
Shared utilities, components (BaseHeader, BaseRefresher), composables (useToast), and storage ports reside in src/core/.
| Layer | Technologies |
|---|---|
| Frontend Framework | Vue 3 (Composition API, <script setup>) |
| Mobile UI & Components | Ionic Framework 8 (@ionic/vue, @ionic/vue-router, Ionicons 8) |
| Mobile Runtime | Capacitor 8 (Android & iOS runtime, @capacitor/app, @capacitor/haptics, @capacitor/keyboard, @capacitor/status-bar) |
| State Management | Pinia 4 |
| Backend & Database | Supabase (PostgreSQL, PostgREST API) |
| Date & Time | Day.js |
| Build Tool | Vite 8 with tree-shaking & vendor chunk splitting |
| Testing | Vitest 5, @vue/test-utils 2, jsdom |
| Code Quality | TypeScript 5.9, ESLint 9 (Flat Config), Prettier (@ionic/prettier-config), Husky, lint-staged |
| Package Manager | pnpm 11 (Node.js 24) |
βββ android/ # Capacitor Android native project
βββ ios/ # Capacitor iOS native project
βββ docs/ # Project documentation, design specs, and ADRs
β βββ adr/ # Architecture Decision Records
β βββ design/ # Design templates and screen specifications
β βββ design-system.md # Design system v2 token and component guidelines
β βββ features/ # Feature-specific architectural docs
βββ src/
β βββ assets/
β β βββ icons/ # Category PNG icons
β β βββ theme/ # Design tokens (--ds-*) & Ionic variable mappings
β βββ core/ # Shared core domain & infrastructure
β β βββ components/ # BaseHeader, BaseRefresher
β β βββ composables/ # useToast and programmatic controllers
β β βββ storage/ # BudgetStorage port, Supabase & InMemory adapters
β β βββ utils/ # Amount formatting, date intervals, category icons
β βββ modules/ # Feature-based domain modules
β β βββ categories/ # Category components, types & store
β β βββ reports/ # Report views, period filters, types & store
β β βββ transactions/ # Transaction views, forms, modals & store
β βββ views/ # Root tab layout (TabsPage.vue)
β βββ App.vue # Root application component
β βββ main.ts # App entrypoint (Ionic & Pinia bootstrapping)
β βββ router.ts # Route declarations & lazy-loaded tabs
βββ supabase/ # Supabase local config & schema snippets
βββ capacitor.config.ts # Capacitor configuration
βββ vite.config.ts # Vite build & chunking configuration
βββ AGENT.md # Agentic workflow & coding assistant guidelines
βββ GLOSSARY.md # Domain terminology and ubiquitous language
- Node.js:
^24.x(managed via .nvmrc) - pnpm:
^11.x - Android Studio (optional, for Android native testing/building)
- Supabase Account / Project (for backend database storage)
git clone https://github.com/AndreiDetenkov/vue3-ionic-budget-app.git
cd vue3-ionic-budget-apppnpm installCopy the example environment file and provide your Supabase project credentials:
cp .env.dist .envEdit .env:
VITE_SUPABASE_URL=https://your-supabase-project.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=your-supabase-anon-or-publishable-keyNote: In development or test environments without Supabase credentials, unit tests run seamlessly using
InMemoryStorage.
pnpm devOpen http://localhost:5173 in your browser. Use mobile device emulation in browser DevTools for the best experience.
The mobile workflow uses Capacitor to package the Vite web application into the native Android project.
- Build web assets:
pnpm build
- Sync web bundle with the Android project:
pnpm sync
- Open project in Android Studio:
pnpm open
- Run on an Android emulator or connected device with live reload:
pnpm run:android
| Command | Description |
|---|---|
pnpm dev |
Starts the Vite development server with HMR |
pnpm build |
Compiles production web bundle into dist/ |
pnpm preview |
Locally previews production build |
pnpm test:unit |
Starts Vitest in watch mode |
pnpm test:unit run |
Runs Vitest test suite once |
pnpm typecheck |
Type-checks code with vue-tsc -b --noEmit |
pnpm lint |
Runs ESLint with auto-fix on src/ |
pnpm format |
Formats source files using Prettier |
pnpm sync |
Runs ionic capacitor sync android |
pnpm open |
Opens Android Studio for the native Android project |
pnpm run:android |
Runs on Android emulator with live reload |
pnpm release |
Creates a release via changelogen (version bump, changelog, git tag) |
Unit tests are written using Vitest and @vue/test-utils, residing next to the source code (*.spec.ts):
# Run all unit tests once
pnpm test:unit run
# Run a specific test file
pnpm test:unit src/modules/transactions/store/transactionStore.spec.ts
# Filter tests by name
pnpm test:unit -t "calculates total"# Typecheck
pnpm typecheck
# Lint with ESLint
pnpm lint
# Format with Prettier
pnpm formatPre-commit hooks are configured via Husky and lint-staged to automatically lint, format, and typecheck staged files prior to each commit.
The PostgreSQL database contains two primary tables:
categories:id(uuid, primary key)title(text)icon(text, nullable)
transactions:id(uuid, primary key)name(text, transaction description/title)value(numeric, expense amount)category_id(uuid, foreign key referencingcategories.id)created_at(timestamptz)
TypeScript definitions for database tables are generated using the Supabase CLI in src/core/storage/database.types.ts:
npx supabase gen types typescript --project-id <your-project-id> > src/core/storage/database.types.ts- GLOSSARY.md β Ubiquitous domain language and terminology definitions.
- AGENT.md β Development guidelines, conventions, and agent workflow specifications.
- docs/adr/0001-domain-storage-seam.md β Architecture Decision Record on domain-storage seam.
- docs/design-system.md β Design system v2 tokens, layout rules, and component audit.
- docs/features/toast-notifications.md β Programmatic toast notification system architecture.