AI-powered receipt scanner and spending tracker.
This project is the primary testbed for the Agentic Development Workflow — a structured, multi-phase AI-assisted development process. NovaScan exists to exercise every phase of that workflow (research → spec → plan → execute → review → verify) on a non-trivial, full-stack application and feed improvements back into the workflow itself.
If you're here to understand the agentic workflow in practice, the workflow/ directory contains the complete trail: research notes, specs, task plans, review files, and retrospectives generated across milestones.
NovaScan is a mobile-optimized web application that lets users photograph or bulk-upload receipt images. The system extracts merchant, date, line items, and totals using a dual OCR pipeline (Amazon Textract + Bedrock Nova for OCR-AI, and Bedrock Nova multimodal for AI-multimodal) and presents spending data through a receipt management interface.
- Passwordless email OTP authentication (Cognito)
- Receipt image upload via camera capture or file picker (up to 10 files, JPEG/PNG, max 10 MB)
- Automatic OCR processing via dual pipelines with ranking and fallback
- Receipt list with status badges (processing/confirmed/failed), date filtering, pagination
- Receipt detail view with image alongside extracted data (responsive layout)
- Inline line item editing: add, remove, edit name/quantity/price/subcategory
- Category management: 13 predefined categories with subcategories, custom category creation/deletion
- Staff-only pipeline comparison toggle (side-by-side OCR-AI vs AI-multimodal results)
- Receipt deletion with confirmation dialog
- Dashboard: weekly/monthly spending totals with % change, top categories, recent activity
- Transactions ledger: sortable table (date/amount/merchant), date range/category/status filters, merchant search
- Analytics page: "Coming Soon" placeholder
- Security hardened: input validation, error sanitization, scoped IAM, rate limiting
- Python 3.13+
- Node.js 22 LTS
- Docker (for DynamoDB Local in tests)
- AWS CLI v2 (configured with your AWS account)
- uv (Python package manager)
- AWS CDK CLI:
npm install -g aws-cdk
git clone https://github.com/wilsonkichoi/novascan.git
cd novascan
# Backend
cd backend && uv venv --python 3.13 && uv sync && cd ..
# Frontend
cd frontend && npm install && cd ..
# Infrastructure
cd infra && uv venv --python 3.13 && uv sync && cd ..
# Git hooks (auto-regenerates CDK snapshot on commit)
git config core.hooksPath .githooks# Backend (555 tests)
cd backend && uv run pytest
# Frontend (354 tests)
cd frontend && npm run test -- --run
# Infrastructure (101 tests)
cd infra && uv run pytest
# Lint
cd backend && uv run ruff check src/# Start DynamoDB Local
docker run -d -p 8000:8000 amazon/dynamodb-local
# Copy frontend/.env.example to frontend/.env and fill in values from CDK stack outputs
cp frontend/.env.example frontend/.env
# Frontend dev server
cd frontend && npm run dev- Fork and clone this repo
- Install prerequisites (see above)
- Configure AWS credentials (
aws configureor setAWS_PROFILE) - Bootstrap CDK in your account:
cd infra && uv run cdk bootstrap
- Deploy the dev stack (builds frontend, deploys infra + frontend to S3/CloudFront):
The deploy script reads CDK stack outputs and injects them into the frontend build automatically — no manual
python scripts/deploy.py all dev
.envconfiguration needed for deployed environments. - Create a user:
uv run scripts/add_user.py --stage dev --email you@example.com
- Open the CloudFront URL printed in the deploy output
No custom domain is required. The dev stage uses CloudFront's default URL.
uv run scripts/dangerous_full_teardown.py devThis destroys the CloudFormation stack and cleans up any retained resources (prod DynamoDB table, S3 buckets, Cognito User Pool). All data is permanently deleted.
Add "domainName": "your-domain.example.com" to the config.prod section of
infra/cdk.json, then deploy with python scripts/deploy.py all prod.
See workflow/guides/cloudflare-custom-domain.md for DNS setup.
Browser (React SPA)
├── CloudFront → S3 (static frontend)
├── API Gateway → Lambda (Powertools REST API)
└── S3 (presigned URL upload)
↓
SQS → EventBridge Pipes → Step Functions
├── LoadCustomCategories
├── Parallel:
│ ├── Textract AnalyzeExpense → Bedrock Nova (OCR-AI)
│ └── Bedrock Nova multimodal (AI-multimodal)
└── Finalize (ranking + DynamoDB update)
↓
DynamoDB (single-table)
- Frontend: Vite + React + Tailwind CSS v4 + shadcn/ui
- Backend: AWS Lambda Powertools (Python) + Pydantic
- Auth: Cognito email OTP (passwordless), JWT authorizer
- Storage: DynamoDB (on-demand, single-table design) + S3 (receipt images)
- Pipeline: SQS + EventBridge Pipes + Step Functions (dual OCR with ranking)
- IaC: AWS CDK (Python), single stack per stage (dev/prod)
See workflow/spec/SPEC.md for the full technical specification.
MIT
