A full-stack finance tracking app for India with automatic transaction detection, budget management, and smart alerts.
| Layer | Technology |
|---|---|
| Mobile | React Native (Expo SDK 54), Expo Router, Zustand, Axios |
| Backend | NestJS 11, Prisma 7, PostgreSQL |
| AI/LLM | Ollama + Llama 3.2 3B (local, open source) |
| Auth | Google OAuth + Phone OTP via Fast2SMS (JWT + Refresh Tokens) |
| Push Notifications | Expo Notifications |
| Fonts | Syne (headings) + DM Sans (body) |
fintrak/
├── mobile/ React Native Expo app
│ ├── app/ Expo Router screens
│ │ ├── (tabs)/ Tab screens (dashboard, transactions, add, notifications, profile)
│ │ ├── login.tsx Phone OTP + Google OAuth
│ │ ├── otp.tsx OTP verification
│ │ ├── setup.tsx Budget + permissions setup
│ │ ├── privacy.tsx Privacy policy
│ │ └── terms.tsx Terms of service
│ ├── src/
│ │ ├── components/ Reusable UI components
│ │ ├── services/ API client, SMS listener, push notifications, offline manager
│ │ ├── stores/ Zustand state stores
│ │ ├── theme/ Design tokens
│ │ └── types/ TypeScript interfaces
│ ├── eas.json EAS Build configuration
│ └── .env
├── backend/ NestJS API server
│ ├── src/
│ │ ├── auth/ Google OAuth + Phone OTP + Refresh tokens
│ │ ├── users/ User profile CRUD + account deletion
│ │ ├── categories/ Category management
│ │ ├── transactions/ Transaction CRUD + summary + search
│ │ ├── budgets/ Budget CRUD
│ │ ├── notifications/ Notification management + budget alerts
│ │ ├── sms/ LLM-powered SMS parsing (Ollama)
│ │ ├── prisma/ Database service
│ │ └── common/ Exception filters
│ ├── prisma/ Schema + migrations + seed
│ ├── test/ E2E + unit tests
│ ├── Dockerfile Production Docker image
│ └── .env
├── docker-compose.yml Full stack orchestration
└── .github/workflows/ CI/CD pipeline
cd backend
npm install
cp .env.example .env # Edit with your credentials
createdb fintrak
npx prisma generate
npx prisma migrate dev --name init
npx prisma db seed
npm run start:dev # http://localhost:3000/apicd mobile
npm install
cp .env.example .env # Edit API URL
npx expo start # Press i/a for simulators, scan QR for Expo GoFor physical device testing, set EXPO_PUBLIC_API_URL to your machine's LAN IP:
EXPO_PUBLIC_API_URL=http://192.168.x.x:3000/api
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string |
JWT_SECRET |
Yes | Strong secret for JWT signing (use a random 64-char string in production) |
TWOFACTOR_API_KEY |
Yes | 2Factor.in API key for OTP delivery |
GOOGLE_CLIENT_ID |
Yes | Google OAuth2 client ID |
GOOGLE_CLIENT_SECRET |
Yes | Google OAuth2 client secret |
PORT |
No | Server port (default: 3000) |
NODE_ENV |
No | development / production / test |
CORS_ORIGINS |
No | Comma-separated allowed origins (default: *) |
MASTER_OTP |
No | Fixed OTP for dev only (disabled when NODE_ENV=production) |
OLLAMA_BASE_URL |
No | Ollama API URL (default: http://localhost:11434) |
OLLAMA_MODEL |
No | Ollama model name (default: llama3.2:3b) |
| Variable | Required | Description |
|---|---|---|
EXPO_PUBLIC_API_URL |
Yes | Backend API base URL |
EXPO_PUBLIC_GOOGLE_CLIENT_ID |
Yes | Google OAuth2 client ID (web) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/auth/send-otp | No | Send OTP via Fast2SMS |
| POST | /api/auth/verify-otp | No | Verify OTP, get JWT + refresh token |
| POST | /api/auth/google | No | Google OAuth login |
| POST | /api/auth/refresh | No | Refresh access token |
| GET | /api/users/me | Yes | Get current user |
| PUT | /api/users/me | Yes | Update profile |
| DELETE | /api/users/me | Yes | Delete account (cascading) |
| GET | /api/categories | Yes | List categories |
| POST | /api/categories | Yes | Create custom category |
| GET | /api/transactions | Yes | List transactions (paginated, searchable) |
| POST | /api/transactions | Yes | Create transaction |
| PUT | /api/transactions/:id | Yes | Update transaction |
| DELETE | /api/transactions/:id | Yes | Delete transaction |
| GET | /api/transactions/summary | Yes | Monthly summary by category |
| GET | /api/budgets | Yes | List budgets |
| POST | /api/budgets | Yes | Create/upsert budget |
| PUT | /api/budgets/:id | Yes | Update budget |
| GET | /api/notifications | Yes | List notifications |
| PUT | /api/notifications/:id/read | Yes | Mark notification read |
| PUT | /api/notifications/read-all | Yes | Mark all read |
| POST | /api/sms/parse | Yes | Parse SMS via LLM + create transaction |
- Helmet for HTTP security headers
- Rate limiting via
@nestjs/throttler(60 req/min) - CORS restricted to configured origins in production
- OTP hashing with bcrypt (10 rounds)
- JWT access tokens (15 min) + refresh tokens (30 days)
- MASTER_OTP disabled in production (
NODE_ENV=production) - Global exception filter with structured errors (no stack trace leaks)
- Input validation via class-validator with whitelist
# Start the full stack
docker-compose up -d
# Run migrations
docker-compose exec backend npx prisma migrate deploy
docker-compose exec backend npx prisma db seed- Database: Use a managed PostgreSQL (AWS RDS, Supabase, Neon, etc.)
- Backend: Build and deploy the NestJS app
cd backend npm ci npx prisma generate npm run build NODE_ENV=production node dist/src/main.js - Mobile: Build with EAS
cd mobile npx eas build --platform all --profile production npx eas submit --platform all
- Set a strong
JWT_SECRET(64+ random characters) - Set
NODE_ENV=production(disables MASTER_OTP) - Configure
CORS_ORIGINSto your actual mobile app/web domains - Set up a real
TWOFACTOR_API_KEYfor OTP delivery - Configure
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET - Use a managed PostgreSQL with backups enabled
- Set up SSL/TLS (reverse proxy with nginx/Caddy or cloud load balancer)
- Configure EAS build profiles in
mobile/eas.json - Add your Apple/Google developer account details for app store submission
- Publish privacy policy and terms of service URLs
The POST /api/sms/parse endpoint uses Ollama (Llama 3.2 3B) to intelligently parse Indian bank SMS messages. It:
- Determines if the SMS is a financial transaction
- Extracts amount, merchant, bank, transaction type
- Categorizes against the user's categories
- Automatically creates a transaction record
- Triggers budget notifications if thresholds are exceeded
Falls back to regex-based parsing if Ollama is unavailable. Configure via:
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2:3b
GitHub Actions pipeline (.github/workflows/ci.yml):
- Backend: Lint, build, and test with PostgreSQL service
- Mobile: TypeScript type-checking
- Docker: Build verification
# Backend unit tests
cd backend && npm test
# Backend e2e tests (requires PostgreSQL)
cd backend && npm run test:e2e
# Mobile type check
cd mobile && npx tsc --noEmitDark theme inspired by modern fintech apps:
| Token | Value | Usage |
|---|---|---|
| bg | #0A0E1A |
Screen backgrounds |
| surface | #111827 |
Tab bar, overlays |
| card | #161D2E |
Card backgrounds |
| border | #1E2D45 |
Borders, dividers |
| teal | #00D4AA |
Primary accent, positive amounts |
| red | #FF4D6D |
Negative amounts, over-budget |
| amber | #F59E0B |
Warnings |
Typography: Syne (headings, amounts) + DM Sans (body text).