EasyStarter

Expense Tracker API

DatabasesAPI DesignAuth

Problem Statement

SpendWise is building a personal finance app where users track their daily expenses. Features:

- Add expenses - log amount, category (food, transport, entertainment, etc.), date, and notes. Support multiple currencies.Categories & budgets - set monthly budgets per category. Show progress bars (e.g., "Food: $320 / $500 spent").Recurring expenses - mark expenses as recurring (daily, weekly, monthly). Auto-create entries.Reports - monthly/yearly summaries with breakdown by category (pie chart data), spending trends over time (line chart data).Export - export expenses as CSV or PDF for tax purposes.Multi-device sync - expenses sync across phone, tablet, and web.

Targeting 25,000 users with 15,000 DAU.

What You'll Learn

Design a personal expense tracking app with categories, budgets, recurring expenses, and monthly reports. Build this architecture under realistic production constraints, then validate tradeoffs in the design lab simulation.

DatabasesAPI DesignAuth

Constraints

Registered users~25,000
Daily active users~15,000
Expenses per user/month~100
API response time< 200 ms
Report generation< 1 second
Availability target99.5%
ApproachClick to expand

Interview-Ready Approach

1) Clarify Scope and SLOs

  • Problem statement: Design a personal expense tracking app with categories, budgets, recurring expenses, and monthly reports.
  • Design for a peak load target around 100 RPS (including burst headroom).
  • Registered users: ~25,000
  • Daily active users: ~15,000
  • Expenses per user/month: ~100
  • API response time: < 200 ms
  • Report generation: < 1 second

2) Capacity Planning Method

  • Convert traffic and growth constraints into request rate, storage growth, and concurrency budgets.
  • Keep at least 2-3x safety margin per tier (ingress, compute, storage, async workers).
  • Reserve explicit latency budgets per hop so p95 can be defended in review.

3) Architecture Decisions

  • Databases: Define a clear system-of-record and design read/write paths separately before adding optimizations.
  • API Design: Standardize API boundaries, idempotency keys, pagination, and error contracts first.
  • Auth: Centralize identity verification and keep authorization checks close to domain resources.

4) Reliability and Failure Strategy

  • Use strong write constraints (transactions or conditional writes) and explicit backup/restore strategy.
  • Apply strict input validation and backward-compatible versioning.
  • Use short-lived tokens and secure key rotation workflows.

5) Validation Plan

  • Run one peak-load test, one dependency-degradation test, and one failover test.
  • Verify idempotency for all retried writes and async consumers.
  • Track user-facing SLOs first: p95 latency, error rate, and successful throughput.

6) Trade-offs to Call Out in Interviews

  • Databases: SQL gives stronger transactional guarantees; NoSQL often gives better write scaling and flexibility.
  • API Design: Rich APIs improve developer speed but can create long-term compatibility burden.
  • Auth: Central auth simplifies policy, but makes auth service availability/security critical.

Practical Notes

  • A relational database with proper indexes on (user_id, date, category) handles all queries efficiently.
  • Pre-compute monthly aggregates whenever a new expense is added - store in a summary table for instant report loading.
  • Recurring expenses: a scheduled job creates new expense entries at the start of each period.

Learn the Concept

Practice Next

Reference SolutionClick to reveal

Why This Solution Works

Request path: The solution keeps ingress, service logic, and stateful dependencies separated so each layer can scale independently.

Reference flow: Web Clients -> API Gateway -> API Service -> Auth Service -> Primary SQL DB

Design strengths

  • Security controls are enforced at ingress to protect downstream capacity.

Interview defense

  • This design makes bottlenecks explicit (ingress, core compute, persistence, async workers).
  • It supports progressive scaling without re-architecting the core request path.
  • It keeps correctness-sensitive state changes in durable systems while offloading background work asynchronously.