Nuvlo - Expense Tracker
End-to-end personal finance system linking real US bank accounts via the Teller.io API — FastAPI + PostgreSQL on GCP Cloud Run, BigQuery analytics, Terraform IaC, and Grafana Cloud observability.
Overview
A full-stack personal expense tracker that links real US bank accounts via the Teller.io API, with a FastAPI + PostgreSQL backend on GCP Cloud Run and a React/TypeScript frontend secured with JWT auth and TOTP/email 2FA. An end-to-end ETL pipeline flows transaction data from Teller.io to PostgreSQL to BigQuery, powering per-user spending analytics by category and weekly trends. Infrastructure is fully automated with Terraform IaC and GitHub Actions CI/CD, with Grafana Cloud for production monitoring.
Problem Statement & Approach
Managing multiple credit cards across different institutions means logging into separate apps to check balances, track spending, and monitor due dates. Most missed payments happen not because of insufficient funds, but because a due date slipped by unnoticed.
Approach: Consolidate every card in one place through the Teller.io API, sync transactions daily, auto-categorize expenses, and send email reminders before due dates — layered on a weekly analytics pipeline that surfaces spending by category, monthly totals, and credit-utilization history that consumer banking apps don't expose directly.
System Architecture
The system is organized into three layers — application, orchestration, and analytics — spanning a transactional API, event-driven processing, and a batch analytics warehouse.
Application Layer
A FastAPI backend handles authentication, card management, transaction CRUD, Teller webhook events, and email notifications, connecting to PostgreSQL on Cloud SQL over a Unix socket. Every transaction write publishes an event to a Kafka topic that a background consumer thread subscribes to for downstream processing.
Orchestration Layer
Apache Airflow runs three DAGs: daily_teller_sync pulls and upserts transactions per linked account, bill_due_checker scans due dates and emails reminders via Gmail SMTP, and weekly_spark_batch triggers a PySpark job that aggregates transactions and writes Parquet files to a GCS data lake.
Analytics Layer
PySpark writes spending_by_category, monthly_totals, and utilization_history tables to the GCS data lake; a loader job moves them into BigQuery, where dbt staging and mart models produce analytics-ready, time-partitioned views.
Key Features
- Real US bank account linking via the Teller.io API
- FastAPI + PostgreSQL backend deployed on GCP Cloud Run
- React/TypeScript frontend secured with JWT auth and TOTP/email 2FA
- End-to-end ETL pipeline: Teller.io → PostgreSQL → BigQuery
- Per-user spending analytics by category and weekly trends
- Terraform IaC and GitHub Actions CI/CD, monitored with Grafana Cloud
Technical Stack
Frontend
Backend
Database
Auth
Bank Data
Data & Orchestration
Infrastructure
Monitoring
Deployment
All GCP infrastructure is defined in Terraform and provisioned with a single terraform apply — Cloud SQL PostgreSQL, Cloud Run with the Cloud SQL connector, Artifact Registry, GCS data-lake buckets, a BigQuery dataset with time-partitioned tables, and least-privilege service accounts. GitHub Actions runs on every push to main: it authenticates to GCP, builds and pushes the backend Docker image to Artifact Registry, deploys to Cloud Run with injected secrets, then builds the React frontend and deploys it to Firebase Hosting.
Challenges & Solutions
Challenge: Transaction writes needed to drive analytics without slowing down the API response.
Solution: Each write publishes to a Kafka topic consumed by a background thread, decoupling downstream processing from the request path.
Challenge: Repeated Teller syncs risked inserting duplicate transactions.
Solution: Upserts keyed on the Teller transaction ID make the daily sync idempotent.
Challenge: Cloud infrastructure had to be reproducible and low-drift across environments.
Solution: Terraform provisions the entire GCP stack from code, so it can be torn down and rebuilt with a single apply.
Improvements
- Real-time transaction streaming to replace the daily batch sync
- Budget goals and anomaly alerts on unusual spending
- Multi-currency and multi-country bank support beyond Teller's US coverage
- A native mobile client for on-the-go reminders
