Full Budget App

Open source · Serverless · Multi-tenant · Event-driven categorisation · AWS CDK

Full Budget App Architecture Client sends GraphQL requests through API Gateway to the GraphQL Lambda (Apollo Server, primary actor). The lambda reads and writes eight DynamoDB tables: Users, Transactions (with stream), Budgets, Recurring Transactions, Categories, Refresh Tokens, Savings Goals, and Sinking Funds. For statement uploads the lambda writes to an S3 bucket; an S3 PUT event triggers an SQS message; SQS triggers the txn-loaders Lambda which parses bank statements (HDFC, SBI, Axis) and writes normalised transactions to DynamoDB. The DynamoDB stream on the Transactions table triggers the tag-loaders Lambda which applies a deterministic NLP rule engine first, then falls back to Amazon Bedrock (Mistral) for low-confidence matches, and writes the result to the Categories table. AWS X-Ray, CloudWatch, and SSM Parameter Store provide observability and configuration. CLIENT / ENTRY COMPUTE STORAGE / ASYNC Client (web / mobile) API Gateway GraphQL Lambda Apollo Server 5 · JWT · X-Ray tracing 7 queries · 18+ mutations · multi-tenant DYNAMODB (8 tables · on-demand · tenantId PK) Users Transactions stream Budgets Recurring Transactions Categories (output of tag-loaders) + RefreshTokens · SavingsGoals · SinkingFunds S3 (statement uploads) SQS Queue batch 10 · 300s visibility txn-loaders Lambda parse (HDFC / SBI / Axis) · normalise · write tag-loaders Lambda NLP rule engine (deterministic first) Amazon Bedrock fallback (Mistral) Amazon Bedrock (Mistral) low-confidence matches only SSM Param Store JWT secret OBSERVABILITY AWS X-Ray (10% sampling) · CloudWatch alarms (errors / duration / throttle) · Winston logs · Prometheus /metrics upload S3 event write DDB stream AI fallback categorise sync async / event primary actor AI / categorisation

Repo: github.com/debrajpaul/full-budget-app

What it is. A multi-tenant serverless budgeting platform built as a pnpm monorepo on AWS. Users upload bank statements (HDFC, SBI, Axis — PDF or CSV) via a GraphQL mutation; the statement lands in S3, an S3 event queues a message in SQS, and the txn-loaders Lambda parses and normalises the transactions into DynamoDB. A DynamoDB stream on the Transactions table immediately triggers the tag-loaders Lambda, which applies a deterministic NLP rule engine for known merchants and categories, falling back to Amazon Bedrock (Mistral) only for low-confidence matches. All 8 DynamoDB tables use tenantId as the partition key, giving hard data-boundary isolation between users.

Why this shape. S3 → SQS decouples ingestion from parsing — spiky upload volumes don’t block the GraphQL API. DynamoDB Streams replace polling entirely: as soon as a transaction is written, the categorisation worker fires. The hybrid NLP+AI strategy keeps Bedrock calls (and their cost) to a minimum; most common merchants are classified by rules in under a millisecond. AWS CDK provisions all resources — tables, queues, buckets, alarms, X-Ray groups — as reproducible stacks with explicit dependency ordering.