Debbie is a local-first Flutter app for Android and iOS that reframes personal finance as a practice of mindful living. Instead of restrictive budgets, it helps you tag every transaction with the values it serves — growth, family, freedom, generosity — and reflect on whether your money is moving in the direction of the life you want.
No ads. No analytics. No accounts. Your data lives on your device.
- Why Debbie
- Features
- Tech Stack
- Getting Started
- Optional Integrations
- Project Layout
- Data & Privacy
- Contributing
- License
Most finance apps make you feel watched. Debbie is built on a different premise:
- Values over budgets. You don't restrict — you align. Every Rupiah is energy moving toward something you care about.
- Reflection over reporting. Charts are useful, but the real insight comes from journaling about why you spent.
- Privacy by default. Everything runs offline; cloud is opt-in and only used for your own backups.
- A calm interface. The app feels like a journal, not a spreadsheet — warm typography, generous whitespace, gentle motion.
- Values-first onboarding — pick, prioritize, and allocate a monthly Values Plan
- Multi-item transactions with notes, tags, goals, receipt photos, and place labels
- Values Wheel & alignment score to compare planned vs. actual spending
- Impact Goals tied to the values that matter most
- Daily intentions and weekly planning for short-horizon awareness
- Recurring bills & subscriptions with monthly payment tracking and history
- Reflection tools — weekly check-ins, monthly Money Story entries, guided prompts
- Optional AI for reflections, spending insights, value suggestions, and receipt scanning (Gemini)
- Export & backup — CSV, Excel, and Google Drive ZIP backup/restore with daily auto-checks
- Offline-first with bundled fonts and local SQLite storage
| Layer | Technology |
|---|---|
| Framework | Flutter 3.41.x · Dart 3.11.4 |
| State management | flutter_riverpod |
| Navigation | go_router |
| Local persistence | sqflite + SQLite |
| Charts & visuals | fl_chart, CustomPainter, flutter_animate |
| Images | image_picker, flutter_image_compress, photo_view |
| Export | csv, excel, share_plus |
| Backup | Google Sign-In · Google Drive API · ZIP archives |
| AI (optional) | google_generative_ai (Gemini) |
| Location | geolocator, geocoding, OpenStreetMap place search |
- Flutter SDK compatible with Dart
3.11.4 - Xcode and/or Android Studio for simulators, emulators, and platform tooling
- (Optional) a Gemini API key for AI features
- (Optional) Google OAuth credentials for Drive backup and restore
flutter pub get
flutter runTarget a specific device:
flutter devices
flutter run -d <device-id>flutter testflutter build apk --release # Android
flutter build ios --release # iOS (requires signing)- Fonts are bundled under
assets/google_fonts/; runtime font fetching is disabled. - Core flows work without API keys or cloud services.
- Currency is currently optimized for Indonesian Rupiah (
Rp,id_IDlocale).
AI features are opt-in. Enter your API key in Settings → AI Reflection — it is stored on-device only.
Powered features:
- weekly reflections
- journal insights
- transaction value suggestions
- receipt scanning
Drive backup bundles the local database and transaction images into a single ZIP archive. Backup and restore require Google Sign-In to be configured for the build you are running.
If Android sign-in fails with
ApiException: 10, the OAuth client does not match the app package or signing key.
Setup:
-
Enable the Google Drive API in Google Cloud Console or Firebase.
-
Complete the OAuth consent screen.
-
Create an Android OAuth client for package
com.debbie.debbie. -
Register the SHA-1 for the keystore you are using. For the default debug keystore:
keytool -list -v -alias androiddebugkey \ -keystore ~/.android/debug.keystore \ -storepass android -keypass android | rg SHA1
-
Create a Web OAuth client and pass it at runtime:
flutter run \ --dart-define=GOOGLE_SERVER_CLIENT_ID=YOUR_WEB_CLIENT_ID.apps.googleusercontent.com
-
For iOS, also create an iOS OAuth client, add the matching URL scheme to
Info.plist, and pass both client IDs:flutter run \ --dart-define=GOOGLE_SERVER_CLIENT_ID=YOUR_WEB_CLIENT_ID.apps.googleusercontent.com \ --dart-define=GOOGLE_IOS_CLIENT_ID=YOUR_IOS_CLIENT_ID.apps.googleusercontent.com
lib/
├── app/ # Router and theming
├── data/ # Database, tables, models, repositories
├── features/ # Onboarding, dashboard, transactions, reflect, recurring, settings
├── providers/ # Riverpod async/state providers
├── services/ # AI, Drive backup, export, images, location, suggestions
└── shared/ # Constants, utilities, reusable widgets
test/
└── data/ # Focused persistence and backup coverage tests
Architectural conventions:
- Repository pattern — screens never call
sqflitedirectly. - Money is stored as integer IDR (no sub-units, no floats). Formatting happens only in the UI layer.
- Image paths are stored relative in the DB; resolved at read time via
path_provider. - App copy lives in
shared/constants/strings.dart— no inline magic strings.
- All user data is stored locally in SQLite on the device.
- No analytics, no ad SDKs, no third-party tracking.
- Google Drive is used only for user-initiated backup and restore after sign-in.
- Network access is required only for opt-in features: AI, Drive backup, and place search.
This is currently a solo project, but issues and thoughtful PRs are welcome. Please:
- Match the existing code style (
flutter_lints). - Keep money as integer IDR — no floats anywhere in storage logic.
- Avoid "budget" language in user-facing copy. Prefer: Values Plan, energy, alignment, intention, purpose.
- Run
flutter testbefore opening a PR.
This repository does not currently include a LICENSE file. All rights reserved by the author until one is added.