devsnack
Documentation

Moneymind documentation

Run it, point it at your own accounts, ship it under your own brand. Written against version 1.1.0 of the download you get on CodeCanyon.

$18 on CodeCanyon
  • Version v1.1.0
  • Updated Aug 2026
  • Platform Flutter
  • Stack Flutter · Firebase
On this page
01

Introduction

AI-powered personal finance app — Flutter + Firebase.

Moneymind is an AI-powered personal finance app shipped as production-grade source code: one Flutter mobile app (apps/mobile) plus a Firebase Cloud Functions backend (apps/functions). It is single-user personal finance — one account tracks their own money. It is not multi-user, family-sharing, or a marketplace.

The differentiator is that the AI is actually functional, not a UI mockup. Receipt scanning, a finance coach, forecasting, smart categorization, anomaly detection, a health score, and budget/savings generators all run for real — through a dual OpenAI + Gemini backend, switchable at runtime via Remote Config. Every model call is server-side, so no AI API keys ever ship in the APK/IPA.

Architecture is offline-first: the on-device Drift/SQLCipher database is the source of truth, and Firestore is used for reconciliation/sync — so the core app works with no network, and AI entry points degrade gracefully when offline.

What’s included

  • Full Flutter source (apps/mobile) + Firebase Functions source (apps/functions)
  • Drift (SQLite + SQLCipher) schema & migrations, with the mirrored Firestore schema, security rules, and the one declared composite index
  • Warm Minimalist design system — Material 3 ColorScheme, Sora type scale, shape + spacing tokens; light, dark, and system modes
  • 18 Cloud Functions — 9 AI callables, 2 subscription callables, FX rate, RevenueCat webhook + entitlement refresh, 3 schedulers, 1 auth trigger
  • Next.js admin panel (apps/admin) — an optional operations console: users, AI spend, a validated Remote Config editor, billing, system health, audit log, and access control (see Admin panel)
  • Server-side AI quota + rate limiting with a premium bypass
  • RevenueCat subscription stack + AdMob (banner + interstitial), both Remote-Config-gated
  • App lock (PIN + biometric + auto-lock) and local notifications
  • Google + Apple sign-in (Apple is iOS-only)
  • This documentation + the RevenueCat setup guide (docs/REVENUECAT_SETUP.md)
  • 6 months email support, lifetime updates
02

Features

Money management

  • Multi-wallet (cash / bank / card), each with its own currency
  • Transactions (income / expense / transfer) kept atomic with the wallet balance in a single DB transaction
  • Multi-currency with a per-transaction FX rate — live via the getFxRate callable, with a manual-entry fallback offline
  • Categories with custom icons/colors; budgets with progress + threshold colour buckets; recurring rules auto-posted by a daily scheduler
  • Debts (lent / borrowed, payments, settle) and savings goals (contributions, completion); reports via fl_chart

AI features (server-side, functional)

  • Receipt scannerscanReceipt (GPT-4o Vision) extracts merchant, amount, date, line items from a photo
  • Smart categorizationsuggestCategory
  • Finance coach chataiCoachChat (RAG over the user’s own data)
  • Forecast, anomaly detection, health score forecastSpending, detectAnomalies, computeHealthScore
  • Weekly recap, AI budget generator, savings plangenerateWeeklyRecap, generateBudgetPlan (bulk-creates budgets), generateSavingsPlan
  • Subscription detectordetectSubscriptions + confirmSubscription (90-day pattern match, no LLM)

Monetization

  • RevenueCat subscriptions — paywall, restore, entitlement sync via the webhook (authoritative) + a client fast-path
  • AdMob banner (Home) + interstitial (every Nth transaction add)
  • Free-tier ceilings — wallets & monthly transactions enforced on the client, AI enforced on the server; premium bypasses all of them

Operations (admin panel)

  • Optional Next.js console (apps/admin) — user growth, AI spend, billing, system health, audit log (see Admin panel)
  • Validated Remote Config editor — typed values, drift detection against what the code actually reads, and an ETag-guarded publish so a concurrent console edit cannot be clobbered
  • Gated by a Firebase Auth custom claim; all reads are server-side, so your security rules stay unchanged
  • Demo mode makes it read-only for screenshots or show-and-tell

Security and polish

  • App lock — salted SHA-256 PIN in secure storage, biometric via local_auth, configurable auto-lock
  • Local notifications — budget / recurring / debt / goal thresholds + a weekly recap
  • Settings — profile, JSON backup/export, reset data, about; full light/dark theming; Google + Apple sign-in

Backend (Firebase Functions, asia-southeast1)

  • Every AI callable follows auth → rate-limit → quota → provider → JSON-validate
  • Prompts centralized in src/prompts/; dual provider behind one interface in src/providers/
  • Schedulers: processRecurringRules (daily), resetMonthlyAIQuotas (monthly GC); the RevenueCat webhook is the authoritative entitlement writer
03

Architecture

money-mind/
money-mind/
  apps/
    mobile/      Flutter app (Riverpod 3 + GoRouter + Drift)  ← v1 deliverable
    functions/   Firebase Cloud Functions (Node 22 + TypeScript)
    admin/       Next.js admin ops console (optional — see docs/ADMIN_SETUP.md)
  docs/          REVENUECAT_SETUP.md, codecanyon/
  firebase.json  firestore.rules  firestore.indexes.json  storage.rules
  pnpm-workspace.yaml
App framework
Flutter 3.x / Dart 3.11
State
Riverpod 3 (hand-written providers — no codegen)
Routing
GoRouter
Local DB
Drift (SQLite) + SQLCipher
Models / codegen
freezed, json_serializable, build_runner
Charts / fonts
fl_chart, google_fonts (Sora)
Backend
Firebase Auth / Firestore / Storage / Functions / Remote Config
Functions
Node 22 + TypeScript
AI
OpenAI + Gemini (dual, runtime-switchable)
Monetization
RevenueCat, Google Mobile Ads
Admin panel (optional)
Next.js 16 + React 19, Tailwind CSS v4, Firebase Admin SDK (deploys on Vercel)

Feature-first folders (lib/features/<area>/{presentation,providers}). The Drift schema is mirrored to Firestore across 9 synced tables. JS/TS uses pnpm workspaces (pnpm -F functions …); the Flutter app is driven directly by the Flutter/Dart CLI from apps/mobile.

04

Firebase project setup

This page is the full reference — the sections from here through Production checklist walk through Firebase, secrets, Remote Config, monetization, and release in order. Monetization specifics also live in docs/REVENUECAT_SETUP.md.

Note
Heads up: Moneymind ships without the seller’s Firebase config. You must run flutterfire configure against your own Firebase project before the app will build.

This is the buyer’s biggest task. The repo ships only *.example templates for the Firebase config — the real files are gitignored, so you wire your own project.

  1. 01
    Create a Firebase project. Enable Authentication (Email/Password + Google/Apple — see Social sign-in), Firestore, Storage, Remote Config, and Functions (requires the Blaze plan).
  2. 02

    Register an Android app (com.devsnack.moneymind or your own id) and an iOS app, then from apps/mobile run:

    terminal
    dart pub global activate flutterfire_cli
    flutterfire configure

    This generates lib/firebase_options.dart and drops android/app/google-services.json + ios/Runner/GoogleService-Info.plist for your project.

  3. 03

    Deploy rules + indexes + storage rules:

    terminal
    firebase deploy --only firestore:rules,firestore:indexes,storage
  4. 04
    Set the Function secrets (see Cloud Functions and secrets) and deploy Functions.
Warning
Firebase config is not a secret, but don’t ship the seller’s. Firebase client config (the AIza… key, app id, project id) is safe to embed in client apps — protection comes from your Firestore/Storage rules + App Check, not from hiding the key. But each buyer must use their own project, so these files are gitignored and only *.example templates ship.
05

Social sign-in (Google and Apple)

The Dart side is already built: AuthService.signInWithGoogle / signInWithApple (apps/mobile/lib/data/remote/auth_service.dart), shown by SocialSignInButtons on the sign-in and sign-up screens. The Apple button is iOS-only (!kIsWeb && Platform.isIOS); Google appears on both platforms. You wire your own providers:

  • Firebase console → Authentication → Sign-in method: enable Google and (for iOS) Apple, alongside Email/Password.
  • Google · Android: add your app’s SHA-1 + SHA-256 fingerprints (Firebase → Project Settings → Your apps), then re-run flutterfire configure (or re-download google-services.json). Debug and release keystores have different SHA-1s — register both (cd android && ./gradlew signingReport).
  • Google · iOS: add the REVERSED_CLIENT_ID from GoogleService-Info.plist as a URL scheme (Xcode → Runner → Info → URL Types, or CFBundleURLTypes in Info.plist). google_sign_in 7.x needs it for the auth callback.
  • Apple · iOS: add the Sign in with Apple capability to the Runner target in Xcode, enable it for the App ID in the Apple Developer portal, then enable the Apple provider in Firebase Auth. (A Services ID + key are only needed for the Android/web relay, which this app doesn’t use.)
Note
Removing a provider: edit lib/features/auth/widgets/social_sign_in_buttons.dart. Apple is intentionally hidden on Android — Sign in with Apple there needs a web-redirect relay (out of scope for v1).
06

Cloud Functions and secrets

Set the five secrets, then deploy. Functions are pinned to asia-southeast1; first deploys take a few minutes.

terminal
firebase functions:secrets:set OPENAI_API_KEY
firebase functions:secrets:set GEMINI_API_KEY
firebase functions:secrets:set EXCHANGERATE_API_KEY       # free key: exchangerate-api.com
firebase functions:secrets:set REVENUECAT_WEBHOOK_SECRET  # self-generated
firebase functions:secrets:set REVENUECAT_API_KEY         # RevenueCat REST key

firebase deploy --only functions
FunctionTypeWhat it does
onUserCreate
Auth trigger
Seeds the users/{uid} doc on sign-up
getFxRate
Callable
Live FX rate (12h cache, manual fallback)
suggestCategory
AI callable
Smart category suggestion
scanReceipt
AI callable
Receipt OCR/extraction (GPT-4o Vision)
aiCoachChat
AI callable
Finance coach chat (RAG)
forecastSpending
AI callable
End-of-month spend forecast
detectAnomalies
AI callable
Unusual-spend detection
computeHealthScore
AI callable
Financial health score + factors + tips
generateWeeklyRecap
AI callable
Weekly spending recap
generateBudgetPlan
AI callable
Proposes a monthly budget per category
generateSavingsPlan
AI callable
Savings plan toward a goal
detectSubscriptions
Callable (no LLM)
90-day recurring-charge pattern match
confirmSubscription
Callable (no LLM)
Writes a recurringRules doc
handleRevenueCatWebhook
HTTPS
Authoritative premium-entitlement writer
refreshEntitlement
Callable
Forces a RevenueCat entitlement re-sync
processRecurringRules
Scheduler (daily)
Posts due recurring transactions
resetMonthlyAIQuotas
Scheduler (monthly)
Rolls AI usage into adminStatsMonthly, then garbage-collects old aiUsage docs
aggregatePlatformStats
Scheduler (daily)
Writes the adminStatsDaily snapshot the admin panel reads
07

Remote Config keys

Publish these in the Firebase console. The client registers in-app defaults in remote_config_init.dart, but the console values win.

KeyTypeDefaultControls
ai_provider
string
gemini
Global AI provider (openai|gemini)
free_tier_wallets_max
int
1
Max wallets for free users
free_tier_transactions_monthly
int
100
Monthly transaction cap (free)
free_tier_ai_quota
int
5
Monthly AI-action cap (free)
premium_monthly_price
string
$4.99
Display price (paywall)
premium_yearly_price
string
$29.99
Display price
premium_lifetime_price
string
$79.99
Display price
revenuecat_api_key_ios
string
(empty)
RevenueCat public SDK key (Apple)
revenuecat_api_key_android
string
(empty)
RevenueCat public SDK key (Google)
ads_enabled
bool
false
Global ads kill switch
admob_banner_id_ios / _android
string
(empty)
Banner ad unit ids
admob_interstitial_id_ios / _android
string
(empty)
Interstitial ad unit ids
interstitial_frequency
int
5
Show an interstitial every N transaction adds
Warning
Unset keys have visible effects: empty revenuecat_api_key_* → the paywall shows “not configured”; empty AdMob ids → ads stay hidden. Publish the RevenueCat keys before testing purchases.
08

AI provider setup

Moneymind supports OpenAI and Gemini behind one interface. Set whichever key(s) you have:

terminal
firebase functions:secrets:set OPENAI_API_KEY
firebase functions:secrets:set GEMINI_API_KEY
  • Per-feature default: vision (receipt scan) uses gpt-4o; every other AI feature defaults to gemini-2.5-flash-lite (cheap/fast) with gpt-4o-mini as the OpenAI fallback.
  • Global override: Remote Config ai_provider = "openai" or "gemini".
  • Quota: monthly counters at users/{uid}/aiUsage/{yyyy-MM}, one shared ceiling from free_tier_ai_quota (default 5). Premium users bypass the cap entirely.
Note
Security guarantee: no AI keys live in the Flutter app — every model call goes through a Cloud Function. The keys exist only in Functions secrets.
09

Monetization (RevenueCat and AdMob)

Full RevenueCat walkthrough: docs/REVENUECAT_SETUP.md. In short, RevenueCat needs three credentials:

  • Per-platform public SDK keys → Remote Config revenuecat_api_key_ios / _android.
  • Secret REST key → Functions secret REVENUECAT_API_KEY.
  • Self-generated webhook secret REVENUECAT_WEBHOOK_SECRET, with the webhook URL https://asia-southeast1-<project>.cloudfunctions.net/handleRevenueCatWebhook.

The entitlement identifier must be exactly premium, and your products must be attached to it. Use RevenueCat’s Test Store to validate purchases without store setup.

AdMob: create an AdMob app, put your banner/interstitial unit ids into Remote Config (Google’s test ids are fine for dev), and ads_enabled is the global kill switch. Both surfaces hide for premium users.

10

Admin panel (optional)

apps/admin is a Next.js 16 operations console for your deployment. It is entirely optional — the mobile app works without it — but it is where you see how many users signed up, what your AI features are costing, whether RevenueCat is reaching you, and why a given user is hitting a limit. It also gives you a validated editor for the Remote Config keys (see Remote Config keys), which beats hand-editing strings in the Firebase console.

Dashboard
Users, growth, premium conversion, AI calls and estimated spend
Users
Search, premium filter, per-user detail: entitlement, AI usage, free-tier standing
AI usage & cost
Per-feature call counts, top consumers, quota rejections, estimated cost
Remote Config
Typed editor with validation, drift detection, diff preview, ETag-guarded publish
Billing
RevenueCat webhook events, subscriptions expiring soon, entitlement refresh
System health
Scheduler heartbeats, FX cache freshness, configuration checklist
Audit log
Every change made from the panel — who, what, before → after
Access control
Who can sign in; grant and revoke admin access
Note
Your security rules do not change. The panel reads everything server-side through the Firebase Admin SDK, so firestore.rules stays strictly owner-scoped exactly as it ships. Running the panel does not widen what a mobile client can reach, and the browser never gets a Firestore handle.

How access works

Access is a Firebase Auth custom claim (admin: true) — not a password and not an email list. An ordinary Moneymind user has a valid Firebase account and still cannot get in. Email/password is the only sign-in method, and there is deliberately no sign-up screen, so the first admin is created from a terminal.

Setup

Requires the Blaze plan (already needed for Cloud Functions) and firebase-tools 14.4+.

  1. 01
    Register a Web app in Firebase console → Project settings → Your apps, then copy its config into apps/admin/.env.local (start from .env.example).
  2. 02
    Enable Email/Password under Authentication → Sign-in method. It is the panel’s only sign-in method.
  3. 03

    Create your admin account and grant the claim:

    terminal
    pnpm install
    gcloud auth application-default login
    pnpm -F admin grant-admin you@example.com --create

That creates the Firebase Auth user, sets the claim, and prints a generated password once. Pass --password='…' to choose your own. Then run it locally:

terminal
pnpm -F admin dev     # http://localhost:3000
Warning
Custom claims only apply to new tokens. After granting or revoking access, the account must sign out and back in. A revoke is immediate, because it also revokes refresh tokens.

Deploy

The panel is a standard Next.js app. Vercel is the documented target — it resolves pnpm workspaces natively. Import your repo, then set, under Settings → Build & Deployment:

Root Directory
apps/admin
Include files outside the root directory
On — the workspace and its single lockfile are one level up
Framework Preset
Next.js (auto-detected)

Set the four NEXT_PUBLIC_FIREBASE_* values plus FIREBASE_SERVICE_ACCOUNT_JSON under Settings → Environment Variables. Nothing configuration-related is committed, which is why none of it lives in a file. Pick the function region nearest your Firestore data — asia-southeast1 pairs with Vercel’s Singapore region.

Warning
Vercel needs a service-account key. The Firebase Admin SDK normally authenticates through Application Default Credentials, which only a Google runtime provides. On Vercel you must set FIREBASE_SERVICE_ACCOUNT_JSON to the whole key JSON (Firebase console → Project settings → Service accounts → Generate new private key) and mark it Sensitive. That key has full administrative access and bypasses your security rules — never commit it, never put it in a NEXT_PUBLIC_* variable, and rotate it if it is ever exposed.

Deploy the rules and indexes too, if you have not since adding the panel:

terminal
firebase deploy --only firestore:rules,firestore:indexes
Note
Firebase App Hosting does not work for this app. Its buildpack requires a dependency lock file inside the backend’s root directory, and pnpm keeps exactly one pnpm-lock.yaml at the workspace root — so it fails with fah/missing-lock-file (firebase-tools#7478). Use Vercel, or the container path below.

Any container host also works: output: 'standalone' is enabled everywhere except Vercel, so gcloud run deploy moneymind-admin --source . from the repo root builds and runs it, as does apps/admin/Dockerfile. On a Google runtime the runtime service account supplies credentials — grant it roles/datastore.user, roles/firebaseauth.admin, and roles/firebaseremoteconfig.admin, and never bake a service-account key into an image.

Demo mode

Set NEXT_PUBLIC_DEMO_MODE=true to make the panel read-only: every page still renders, but Remote Config publishing, admin grant/revoke, and entitlement refresh are all refused. It is enforced server-side in each endpoint, not merely hidden in the UI. Useful for screenshots or showing the console to someone without handing them a live deployment. It is inlined at build time, so changing it needs a redeploy.

Note
Full walkthrough: docs/ADMIN_SETUP.md covers IAM, troubleshooting, and the alternative hosting path in detail. apps/admin/README.md is the developer quick reference.
11

Branding and customization

App name + bundle id

Edit apps/mobile/pubspec.yaml, android/app/build.gradle.kts (applicationId), android/app/src/main/AndroidManifest.xml (android:label), and ios/Runner/Info.plist (CFBundleDisplayName) + the Xcode bundle id. Default id: com.devsnack.moneymind.

Theme

All colors, type, shape, and spacing live in apps/mobile/lib/core/theme/. Edit colors.dart once and the whole app reskins — there are no hex literals in widgets (a hard guardrail). Font is Sora via google_fonts; swap the family in typography.dart.

Strings / i18n

User-facing strings are ARB-driven (lib/l10n/app_en.arb). English ships in v1; the structure is i18n-ready.

12

Build and release

terminal
# from apps/mobile
flutter build appbundle --release   # Android → Play Console
flutter build ipa --release         # iOS → App Store Connect

# after any Drift/model change, regenerate code first:
dart run build_runner build --delete-conflicting-outputs

# backend
firebase deploy --only functions
Warning
Replace the AdMob test ids (ca-app-pub-3940256099942544~…) in ios/Runner/Info.plist and the Android manifest with your own before a production release.
13

App signing

Release builds must be signed with your own keys. The Android build is already wired to read your keystore from android/key.properties (gitignored) — you just need to supply the file and the .jks. Release builds also have R8 minification + resource shrinking on by default; keep rules live in android/app/proguard-rules.pro.

Android — keystore

  1. 01

    Generate an upload keystore (keep this file private — never commit it):

    terminal
    keytool -genkey -v -keystore ~/upload-keystore.jks \
      -keyalg RSA -keysize 2048 -validity 10000 -alias upload
  2. 02

    Copy the shipped template and fill it in:

    terminal
    cp android/key.properties.example android/key.properties

    Then edit android/key.properties:

    android/key.properties
    storePassword=********
    keyPassword=********
    keyAlias=upload
    storeFile=/absolute/path/to/upload-keystore.jks

    Both key.properties and any .jks/.keystore under android/ are already in .gitignore.

  3. 03
    That’s it for wiring — android/app/build.gradle.kts already loads key.properties, defines a release signingConfig, enables isMinifyEnabled + isShrinkResources, and points buildTypes.release at both. No edits required.
  4. 04

    Build the release bundle and upload it to Play Console:

    terminal
    flutter build appbundle --release

    Play App Signing is recommended — you keep the upload key and Google manages the app-signing key.

Note
R8 stripped a class my code reflects on? Add a -keep rule to android/app/proguard-rules.pro and rebuild. Common offenders (Firebase, Drift/SQLCipher, RevenueCat, flutter_local_notifications, Play Core) are already covered.
Note
Firebase + Google sign-in: register the keystore’s SHA-1 and SHA-256 fingerprints in Firebase (your debug cert, your upload cert, and — if you enable Play App Signing — the Play-managed app-signing cert). List them with cd android && ./gradlew signingReport, or copy them from the Play Console “App signing” page. Without the right SHA, Google sign-in fails on release builds (see Social sign-in).

iOS — code signing

  1. 01
    Join the Apple Developer Program and create the app record in App Store Connect with your bundle id (com.devsnack.moneymind or your own).
  2. 02
    In Xcode → RunnerSigning & Capabilities: select your Team, set the bundle id, and leave Automatically manage signing enabled (Xcode creates the certificate + provisioning profile). Add the Sign in with Apple capability here (see Social sign-in).
  3. 03

    Build, then upload via Xcode Organizer or Transporter:

    terminal
    flutter build ipa --release
Warning
Never commit signing material. Keep key.properties, *.jks / *.keystore, and .p12 / provisioning profiles out of git — add them to .gitignore if they aren’t already. Losing or leaking the keystore means you can’t ship updates under the same app.
14

Production checklist

  1. 01
    Branding: app name + bundle id across the four native files; launcher icon.
  2. 02
    Theme: edit lib/core/theme/colors.dart — light + dark.
  3. 03
    Firebase: create project, flutterfire configure, enable Auth / Firestore / Storage / Remote Config / Functions (Blaze). Enable Google + Apple sign-in; add Android SHA-1/256, the iOS REVERSED_CLIENT_ID URL scheme, and the Xcode “Sign in with Apple” capability (see Social sign-in).
  4. 04
    terminal
    firebase deploy --only firestore:rules,firestore:indexes,storage
  5. 05
    Set the 5 Function secrets, then firebase deploy --only functions.
  6. 06
    Publish Remote Config keys (RevenueCat keys, AdMob ids, free-tier ceilings, prices).
  7. 07
    RevenueCat: products + premium entitlement + webhook URL/secret (per REVENUECAT_SETUP.md).
  8. 08
    AdMob: real ad unit ids into Remote Config; replace GADApplicationIdentifier in Info.plist + the Android manifest meta-data.
  9. 09
    iOS capabilities: Face ID usage string (present); Sign in with Apple (see Social sign-in). Push not required — notifications are local-only in v1.
  10. 10
    Build releases + upload to Play Console / App Store Connect.
Note
Packaging tip: build the distributable zip from tracked files only so your real Firebase config (which stays on your disk) never leaks: git archive --format=zip -o moneymind-1.0.0.zip HEAD.
15

Changelog

Every version published so far. Updates are free for the life of the item.

v1.1.0 · Aug 2026
Next.js admin console with dashboard, users, AI usage tracking, Remote Config editor, billing, system health and audit log. Android release build improvements and security fixes.
v1.0.0
Initial release.

Version 1.0.0

Initial release. Full personal-finance feature set (wallets, transactions, multi-currency, budgets, recurring, debts, goals, reports), functional AI suite (receipt scan, coach, forecast, anomalies, health score, budget/savings generators, subscription detector), RevenueCat + AdMob monetization, app lock, local notifications, Google + Apple sign-in.

16

Support and licensing

Six months of support are bundled per the CodeCanyon standard, covering setup help and bug fixes.

Note
Your Firebase project, OpenAI/Gemini keys, RevenueCat account, AdMob account, and store developer accounts are your responsibility — we provide the setup walkthroughs, not the accounts or hosting.

What support covers

  • Six months of support from purchase, extendable at checkout
  • Support covers bugs in the template and questions about how it is put together
  • It does not cover custom feature work, third-party API changes or store review outcomes
  • The Regular licence covers one free end product. Charging users for the app itself needs the Extended licence