Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

138 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

CashFlow Manager

CashFlow Manager logo

Offline-first personal finance for Vietnamese, English, and Japanese users.

English Β· TiαΊΏng Việt Β· ζ—₯本θͺž

Flutter Dart Android Docker OpenAPI Version License

Prerequisites: Flutter SDK 3.44+ Β· Dart 3.12+ Β· Docker 24+ (optional, for backend)

Quick Start Β· Docs Β· Architecture Β· Security Posture Β· Repo Health Β· API Β· CI/CD Β· ADRs Β· Security

At a Glance

What Offline-first Flutter personal finance app β€” 3 languages (VI/EN/JA), zero network dependency
Flagship feature Full local finance engine: wallets, budgets, goals, forecasts, export, encrypted backup β€” all offline
Production-shaped Docker Compose (9 services), Ed25519 JWT/JWKS, CI/CD configured (hosted runs quota-deferred), security gates (Gitleaks+Trivy+CodeQL+SBOM)
Not claimed No bank integration, no real-time collaboration, no web frontend, no production cloud sync (foundations ready)

Demo

CashFlow Manager dashboard

CashFlow Manager demo flow

Dashboard Transactions Budgets
Dashboard screenshot Transactions screenshot Budgets screenshot
Wallets Reports Privacy settings
Wallets screenshot Reports screenshot Privacy settings screenshot

About

CashFlow Manager demonstrates a release-ready mobile finance architecture: local SQLite persistence, integer VND money logic, Riverpod state management, privacy-first PIN and opt-in biometric protection, PDF/CSV/backup flows, a separate Fastify/Prisma API, PostgreSQL-backed validation through Docker Compose, OpenAPI documentation, and an optional n8n HMAC automation workflow.

The July 2026 mobile UI uses a light-first private banking ledger style with ivory surfaces, emerald finance actions, compact transaction rows, and seeded professional README media.

The Flutter app is useful without accounts, network access, PostgreSQL, or n8n. The backend and automation stack are production-style foundations for authenticated sync and AI-assisted analysis, not a requirement for local-first usage.

Feature Highlights

Personal finance

  • Dashboard with current balance, monthly income, monthly expense, net cashflow, chart, recent transactions, and budget alerts.
  • Five bottom tabs cover Dashboard, Transactions, Wallets, Budgets, and Reports; app-bar actions handle Add transaction and Settings without a floating action button overlay.
  • Income/expense transaction management with wallet, category, date, note, recurring flag, validation, search, and filters.
  • Wallet overview for cash, bank, e-wallet, and credit-card-ready models.
  • Wallet transfer flow with same-wallet validation.
  • Monthly budget create/edit/delete flow with warning threshold logic.
  • Saving goals with create/edit/delete flow and monthly saving suggestions.
  • Reports with selected-month navigation, income/expense chart, category pie, top spending, forecast cards, CSV preview, and PDF sharing.

Privacy and safety

  • Hardened PIN hashing with salted PBKDF2-HMAC-SHA256.
  • Failed PIN attempt cooldown and reset after successful unlock.
  • Lifecycle relock when the app leaves foreground.
  • Opt-in biometric unlock through local_auth, with PIN always available as fallback.
  • Re-authentication before destructive flows such as reset data and backup restore.
  • Encrypted backup schema v2 with passphrase-derived AES-GCM, while legacy plaintext JSON imports remain supported.
  • Backup restore preview with file-size and data-shape validation before replacement.
  • CSV export formula escaping to reduce spreadsheet injection risk.

Production-style platform work

  • Separate api service using Fastify, Prisma, PostgreSQL, JWT/JWKS, and OpenAPI.
  • Docker Compose stack for PostgreSQL, API, frontend artifact server, migrations, seed job, and optional n8n automation.
  • n8n workflow import/activation path with HMAC request verification before AI provider calls.
  • GitHub Actions CI for Flutter, Android emulator smoke, iOS simulator/no-codesign validation, API, PostgreSQL migration/seed, Docker image builds, Android release artifacts, and Docker Hub and GHCR publishing.

Architecture

CashFlow Manager project architecture

Flutter mobile app (offline-first)
  β”œβ”€ Riverpod controllers
  β”œβ”€ SQLite local finance store
  β”œβ”€ Finance calculator and export services
  β”œβ”€ Privacy lock service
  └─ Optional remote sync client
        ↓ HTTPS / OpenAPI
Fastify API service
  β”œβ”€ Auth + JWKS
  β”œβ”€ Finance validation routes
  β”œβ”€ Sync bootstrap foundation
  β”œβ”€ Optional n8n AI analysis proxy
  └─ PostgreSQL persistence
        ↓ HMAC webhook
n8n automation
  └─ OpenAI-compatible chat completions workflow

API contract: docs/openapi.yaml

Architecture decisions: docs/adr/

Tech Stack

  • Flutter 3.44 / Dart 3.12
  • Riverpod for state management
  • SQLite via sqlite3 + sqlite3_flutter_libs
  • fl_chart for charts
  • local_auth + flutter_secure_storage for local lock
  • csv, pdf, printing, share_plus, file_picker for export and backup flows
  • Node.js 26 + Fastify + Prisma API for authenticated PostgreSQL-backed sync foundation and AI analysis proxy
  • Docker Compose with PostgreSQL 16, migration/seed jobs, API, frontend artifact server, and optional n8n automation
  • GitHub Actions CI for Flutter analyze/tests/builds, Android emulator smoke, iOS simulator/no-codesign validation, API Prisma/typecheck/tests/build, PostgreSQL migration/seed validation, Docker image builds, Android release artifacts, and Docker Hub and GHCR publishing

Project Structure

.
β”œβ”€β”€ lib/                          # Flutter app source
β”‚   β”œβ”€β”€ app/                      # App shell, router, theme
β”‚   β”œβ”€β”€ core/                     # Shared services (export, privacy, sync)
β”‚   β”œβ”€β”€ data/                     # SQLite store, sync, backup/restore
β”‚   └── features/                 # Feature modules (dashboard, transactions, etc.)
β”œβ”€β”€ api/                          # Fastify + Prisma backend
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ modules/             # auth, finance, sync, households, payments, ai
β”‚   β”‚   └── lib/                  # Shared utilities (errors, env, tokens)
β”‚   └── prisma/                   # Schema + migrations + seed
β”œβ”€β”€ test/                         # Flutter unit + widget tests
β”œβ”€β”€ integration_test/             # Flutter integration (smoke) tests
β”œβ”€β”€ docs/                         # Documentation (ADRs, OpenAPI, architecture)
β”œβ”€β”€ infra/n8n/workflows/          # n8n automation workflow definitions
β”œβ”€β”€ scripts/                      # Demo media capture, smoke tests
β”œβ”€β”€ .github/workflows/            # CI/CD pipelines
β”œβ”€β”€ docker-compose.yml            # Production stack
β”œβ”€β”€ docker-compose.local.yml      # Local dev override (port remapping)
β”œβ”€β”€ Dockerfile.frontend           # Flutter APK build + nginx artifact server
└── api/Dockerfile                # Multi-stage Fastify API image

Quick Start

flutter pub get
flutter analyze
flutter test
flutter run

Backend API

npm --prefix api install
npm --prefix api run prisma:generate
npm --prefix api run typecheck
npm --prefix api test

With Docker Desktop running, apply migrations, seed demo data, then start separate backend and frontend containers plus PostgreSQL:

docker compose up --build -d postgres
docker compose --profile tools run --rm --build migrate
docker compose --profile tools run --rm --build seed
docker compose up --build -d api frontend
  • api builds from api/Dockerfile and serves the Fastify backend on container port 3000.
  • frontend builds from Dockerfile.frontend and serves the Android APK artifact on container port 8080.
  • postgres runs PostgreSQL 16 for backend validation.
  • migrate and seed use the Dockerfile tools target so Prisma CLI stays available without bloating the API runtime image.

If host port 3000 is already in use, keep the API container on 3000 and remap only the host port:

$env:API_HOST_PORT = '3001'
docker compose up --build

If host port 8080 is already in use, remap the frontend artifact server:

$env:FRONTEND_HOST_PORT = '8081'
docker compose up --build

The API exposes /healthz, /readyz, /.well-known/jwks.json, auth/account routes, finance CRUD routes, sync bootstrap/changes/push routes, household/shared-budget foundations, entitlement/payment foundations, and an optional n8n-backed /v1/ai/analysis endpoint. /readyz checks the migrated application schema, so run migrate before treating the API as ready. The mobile app release version (1.0.0+1) and backend/API package version (0.1.0) are versioned independently.

Optional n8n ChatbotAI Workflow (click to expand)
$env:N8N_CHATBOT_WEBHOOK_URL = 'http://n8n:5678/webhook/cashflow-ai-analysis'
$env:N8N_CHATBOT_WEBHOOK_SECRET = 'replace-with-local-webhook-hmac-secret'
$env:N8N_ENCRYPTION_KEY = 'replace-with-local-n8n-encryption-key'
$env:N8N_AI_CHAT_COMPLETIONS_URL = 'https://api.openai.com/v1/chat/completions'
$env:N8N_AI_API_KEY = '<local-ai-api-key>'
$env:N8N_AI_MODEL = 'gpt-4o-mini'
docker compose --profile automation up --build -d n8n-postgres n8n
docker compose --profile automation run --rm n8n-import
docker compose --profile automation run --rm n8n-activate
docker compose --profile automation restart n8n

The imported workflow at infra/n8n/workflows/cashflow-ai-analysis.json verifies x-cashflow-signature-sha256 before calling an OpenAI-compatible chat completions endpoint. ChatbotAI is a conservative finance coach, not a bank/account data agent: it must not claim access to bank accounts, transactions, wallets, files, external services, or hidden app data. After HMAC verification, the provider prompt receives only { question, locale }, and the workflow/API response contract is strict JSON { answer, suggestions } with 3-5 non-empty suggestions. Keep real AI provider tokens only in local .env files or deployment secrets.

For a token-free local smoke test, run a mock provider in one terminal and point n8n at it before importing the workflow:

node scripts/mock-openai-compatible-provider.mjs
$env:N8N_AI_CHAT_COMPLETIONS_URL = 'http://host.docker.internal:4567/v1/chat/completions'
$env:N8N_AI_API_KEY = 'local-mock-token'
$env:N8N_AI_MODEL = 'local-mock-model'
$env:N8N_CHATBOT_WEBHOOK_SECRET = 'replace-with-local-webhook-hmac-secret'
docker compose --profile automation up --build -d n8n-postgres n8n
docker compose --profile automation run --rm n8n-import
docker compose --profile automation run --rm n8n-activate
.\scripts\smoke-test-n8n-ai.ps1

Run the mock-provider smoke before any real AI-provider token test. The smoke script first proves an invalid signature is rejected with zero provider calls, then sends a valid HMAC-signed request and expects exactly one provider call plus { answer, suggestions } with 3-5 non-empty suggestions.

Troubleshooting:

Symptom Likely cause Fix
ai_analysis_unconfigured API is missing N8N_CHATBOT_WEBHOOK_URL or N8N_CHATBOT_WEBHOOK_SECRET Set local env or deployment secrets and restart the API
Invalid HMAC smoke fails Secret mismatch between the smoke script/API and n8n Use the same local placeholder secret on both sides
Provider returns 401 N8N_AI_API_KEY is invalid or missing Replace it only in a local .env file or deployment secret store
n8n import fails Docker daemon, n8n database, or workflow import job is not ready Re-run after Docker responds and inspect docker compose logs n8n n8n-postgres

CI/CD Status

Lane Status
Flutter (analyze, test, build) Flutter local verified
API (generate, typecheck, test) API local verified
Security (Gitleaks, Trivy, audit) Security locally checked
CodeQL SAST CodeQL deferred
Docker Publish (GHCR + Docker Hub) Packages verified

Status note: GitHub Actions quota/token is exhausted, so remote workflow badges are intentionally replaced with static green local-evidence badges. Restore live workflow badges after Actions capacity is available again.

Quick Links

Need Link
Full documentation index docs/README.md
C4 architecture diagrams docs/system-architecture.md
Sequence & flow diagrams docs/system-diagrams.md
Interactive architecture dashboard docs/architecture-dashboard.html
OpenAPI 3.1 contract docs/openapi.yaml
ADRs (4 records) docs/adr/
Database schema docs/database-schema.md
Deployment guide docs/deployment-guide.md
Code standards docs/code-standards.md
Design guidelines docs/design-guidelines.md

Release and Package Story

Android

flutter build apk --debug
flutter build appbundle --debug
flutter build apk --release
flutter build appbundle --release

Release signing requires standard Android keystore setup outside this repo. Do not commit keystores or passwords.

Published GitHub Release v1.0.0:

  • Release page: CashFlow Manager 1.0.0+1
  • APK: cashflow-manager-v1.0.0-android.apk
  • App Bundle: cashflow-manager-v1.0.0-android.aab
  • The updated release workflow is configured to generate SBOM and SHA256 checksum artifacts on the next tagged release run.

iOS

The iOS structure exists under ios/. Build/archive requires macOS with Xcode and Swift installed:

flutter pub get
flutter test --no-pub integration_test/cashflow_smoke_test.dart -d <ios-simulator-id> -r expanded
flutter build ios --release --no-codesign --no-pub

Then create the signed archive/IPA through Xcode Organizer, Fastlane, or the manual signed CI lane with Apple signing secrets.

Docker images

The intended public container image names are:

The Docker publish workflow has published public GHCR manifests for 1.0.0; it also tags release builds as v1.0.0, git SHA, and latest. Docker Hub latest manifests are available for both API and frontend images. GitHub's repository sidebar package list is controlled by GitHub Packages visibility and OCI source-link metadata. The local token can now verify both container packages through the package API; the direct package links above remain the stable public entry points while GitHub refreshes sidebar presentation.

Test

flutter analyze
flutter test --no-pub -r expanded
flutter test --no-pub integration_test/cashflow_smoke_test.dart -d <device-id> -r expanded
flutter test --no-pub scripts/capture_demo_media_test.dart -r expanded

Current coverage focus:

  • Money parsing and VND formatting edge cases.
  • Wallet balance logic across income, expense, and transfer.
  • Budget warning logic.
  • Saving goal monthly suggestion.
  • Empty export behavior and PDF payload generation.
  • Privacy lock setup/unlock/relock, biometric opt-in, PIN cooldown, destructive-flow re-auth, dashboard, transaction, wallet transfer, budget, goal, report, export, and backup widget flows.
  • Device/simulator smoke coverage for PIN setup, navigation, transaction entry, wallet transfer, budget warning, saving goal, report export preview, backup entry, and reset confirmation.
  • Demo screenshot generation from deterministic fake financial data.

Repository Presentation Checklist

Use this when preparing the GitHub repository page:

  • About: Professional offline-first Flutter personal finance app with PIN/biometrics, SQLite, Riverpod 3, Node 26 Fastify/PostgreSQL API, OpenAPI, Docker Hub/GHCR packages, and n8n HMAC automation.
  • Website/homepage: leave empty until a real public release/download page exists.
  • Topics: android, android-app, dart, docker, fastify, finance-app, flutter, flutter-app, mobile-app, n8n, offline-finance, offline-first, openapi, personal-finance, postgresql, prisma, riverpod, security, sqlite, vietnamese.
  • Pin screenshots/GIF from docs/media/ in the README.
  • GitHub Release v1.0.0 is published with APK/AAB artifacts; the updated release workflow is configured to attach SBOM and SHA256 checksum artifacts on the next tagged release run.
  • GHCR packages are public for 1.0.0; Docker Hub latest images are verified for API and frontend.
  • Security posture and branch/package audit live in docs/security-posture.md and docs/repository-health.md.
  • Do not publish secrets, signing assets, local databases, private automation files, or internal planning notes.

Privacy Notes

Financial data is local-first. PINs use salted PBKDF2-HMAC-SHA256 before storing in secure storage, biometric unlock is opt-in, repeated failed PIN attempts trigger a cooldown, and the privacy gate relocks when the app leaves foreground. Destructive flows such as data reset and backup restore require re-authentication before replacing local financial data. Backup/restore and report export flows warn about sensitive financial data. Secret files, signing assets, local databases, private automation files, and internal planning notes stay out of git.

Known Limitations

  • No production cloud sync yet; the app remains offline-first, and server sync/account pieces are release foundations until a separate sync rollout.
  • Supabase/Firebase sync is intentionally out of MVP scope.
  • Receipt image/OCR remains local-first work for the next product phase.
  • iOS release archive cannot be verified on Windows; use macOS/Xcode.
  • file_picker and share_plus still emit Flutter's future Kotlin Gradle Plugin migration warning during Android release builds.

About

Offline-first Flutter personal finance learning app with PIN/biometrics, SQLite, Riverpod 3, Fastify/PostgreSQL API, OpenAPI, containers, and n8n automation.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages