A goal-driven personal finance platform that helps users track expenses, set financial goals, link investments to goals, manage budgets, and gain actionable insights β all from a mobile-first experience backed by a zero-trust ledger architecture.
| Feature | Description |
|---|---|
| Home Dashboard | At-a-glance balance, portfolio summary, goal progress cards, and recent transactions |
| Transactions | Full transaction history with search, date-range filters, source & category filters |
| Analytics | Income vs. expense breakdowns by category with period selection, drill-down to transactions |
| Goals | Create, edit, and track financial goals (education, retirement, travel, etc.) with inflation-adjusted projections and SIP/lumpsum recommendations |
| GoalβInvestment Linking | Map portfolio holdings to specific goals and track per-goal investment progress |
| Portfolio | Net worth overview, individual holding details, returns tracking, and risk profile display |
| Risk Assessment | Interactive questionnaire to determine user risk profile (Conservative β Very Aggressive) |
| Budgets | Set monthly spending limits per category |
| Budget Breach Notifications | Real-time alerts when spending exceeds budget limits |
| Notifications | Centralized feed for SIP deductions, goal milestones, dividends, and budget alerts |
| Settings | Budget limit configuration per spending category |
ββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββ
β Mobile App ββββββββΆβ API Gateway ββββββββΆβ Ledger ββββββββΆ PostgreSQL
β (Expo/RN) β β :3000 β β :3001 β
ββββββββββββββββ β JWT Auth β β Append-only β
β Ownership check β β Single writer β
β Reverse proxy β β Idempotent β
ββββββββββββββββββββ ββββββββββββββββββ
Zero-Trust Ledger Gateway β the client never writes directly. Every mutation flows through the API Gateway (auth + ownership) to the Ledger service (the single writer to financial data). The Ledger enforces append-only writes with compensating entries for corrections.
| Service | Directory | Port | Responsibilities |
|---|---|---|---|
| API Gateway | server/api-gateway/ |
3000 | Supabase JWT auth, ownership enforcement, reverse proxy to Ledger. No DB access. |
| Ledger | server/ledger/ |
3001 | Single writer to financial data. Append-only, idempotent. Internal-only (X-Internal-Secret). |
| Mobile App | client/mobile-app/ |
β | Expo SDK 54, React Native 0.81, NativeWind/Tailwind. Currently uses mock data. |
| Prototype | proto/ |
3000 | Interactive React/TypeScript UI prototype with all 13 screens. Used for design validation and user-story generation. |
Both server services follow strict domain/ β application/ β adapters/ β framework/ layering, enforced by AST-based fitness functions in CI.
src/
βββ domain/ # Pure business types & rules β no external imports
βββ application/ # Use cases β imports domain only
βββ adapters/ # External integrations β imports domain + application
βββ framework/ # Express, config, middleware β wires everything together
- Runtime: Node.js (ESM)
- Framework: Express 5
- Language: TypeScript 5.9 (strict mode,
nodenextmodules) - Auth: Supabase JWT
- API Spec: OpenAPI 3.0.3 (37+ endpoints defined)
- Deployment: Render.com
- Framework: React Native 0.81 + Expo SDK 54
- Styling: NativeWind 4 / Tailwind CSS 3
- Icons: lucide-react-native
- Animations: react-native-reanimated 4
- Language: TypeScript
- Framework: React 18 + react-scripts 5
- Styling: Tailwind CSS (CDN)
- Icons: lucide-react
- Language: TypeScript
- Source: Single-file app at
proto/src/App.tsx(13 screens)
Full OpenAPI spec at server/api-gateway/openapi.yaml. Currently live routes serve gateway infra (docs, health, tester). All domain endpoints are spec'd and planned:
| Domain | Endpoints | Description |
|---|---|---|
| Auth | /auth/login, /auth/refresh |
JWT login & token refresh |
| User | /me |
Profile get & update |
| Transactions | /transactions, /transactions/{id}, /transactions/summary |
CRUD + monthly summary |
| Analytics | /analytics/category-breakdown, /analytics/cashflow, /analytics/trends |
Spending & income insights |
| Goals | /goals, /goals/{id}, /goals/{id}/progress, /goals/{id}/linked-investments |
Goal lifecycle + investment linking |
| Portfolio | /portfolio/summary, /portfolio/holdings, /portfolio/holdings/{id}/performance |
Holdings & performance |
| Risk | /risk-profile, /risk-assessment/submit |
Risk profile management |
| Funds | /funds, /funds/{id}, /recommendations |
Fund catalog & recommendations |
| Budgets | /budgets |
Budget limits per category |
| Alerts | /alerts/budget-breaches |
Budget exceeded alerts |
| Notifications | /notifications, /notifications/{id}/read, /notifications/read-all |
Notification feed |
The mobile app includes these screens with full navigation:
| Screen | Description |
|---|---|
| Home | Balance card, portfolio value, goal carousel, recent transactions |
| Analytics | Donut visualization of income/expense by category, period filter |
| Transactions | Searchable, filterable transaction list grouped by date |
| Goals | Goal list with progress bars and "Add New" |
| Goal Details | Target, SIP amount, time left, linked investments |
| New/Edit Goal | Category picker, inflation calculator, SIP/lumpsum recommendation engine |
| Portfolio | Risk profile card, net worth, holdings list |
| Holding Details | Current value, returns, mapped goals |
| Risk Assessment | Multi-step questionnaire β profile result |
| Settings | Monthly budget limits per category |
| Notifications | Budget breach alerts + activity feed |
- Node.js β₯ 18
- npm β₯ 9
- Expo CLI (
npx expo) - iOS Simulator / Android Emulator (or physical device with Expo Go)
cd server
npm ci # Install all workspaces
npm run dev --workspaces # Start both services in dev mode (tsx watch)API Gateway runs at http://localhost:3000, Ledger at http://localhost:3001.
cd client/mobile-app
npm install
npx expo start # Start Expo dev server
# Then press 'i' for iOS or 'a' for Androidcd proto
npm install
npm start # Opens at http://localhost:3000The prototype contains all 13 screens: login, home, transactions, goals, portfolio, new-goal, analytics, goal-details, holding-details, risk-assessment, settings, notifications, connect-email.
# Server
cd server
npm run build --workspaces
# Mobile
cd client/mobile-app
npx expo run:ios # or npx expo run:androidcd server
npm test # Jest across all projects (90% coverage threshold)
npm run fitness:all # Full fitness gate| Check | What It Enforces |
|---|---|
verify-clean-architecture-imports |
Import direction: domain β application β adapters β framework |
verify-money-math |
No number type for money fields β string / bigint / Decimal only |
verify-ledger-invariants |
Append-only: no UPDATE / DELETE on ledger_entries |
verify-idempotency |
All writes require UNIQUE(owner_user_id, idempotency_key) |
verify-sql-safety |
No string concatenation/interpolation in SQL queries |
verify-authorization-completeness |
Auth middleware coverage across routes |
verify-api-contract |
OpenAPI spec valid via swagger-parser + spectral-cli |
verify-pii-secrets |
No leaked secrets or PII in source |
verify-config-hardening |
Secure configuration defaults |
verify-dependency-policy |
Allowed dependency list enforcement |
verify-migration-safety |
Safe DB migration patterns |
verify-outbox-consistency |
Transactional outbox pattern compliance |
verify-webhook-replay-safety |
Idempotent webhook handling |
verify-performance-budget |
Performance constraint checks |
verify-observability-baseline |
Logging & monitoring baseline |
verify-clean-architecture-project |
Project structure validation |
- No float money β Never use
numberfor amounts. Usestring,bigint, or Decimal. - Append-only ledger β
ledger_entriessupports onlySELECTandINSERT. Corrections use compensating entries. - Idempotency β All externally-triggered writes require
UNIQUE(owner_user_id, idempotency_key). - Ownership β Every financial row has
owner_user_id NOT NULL, enforced by middleware. - No raw SQL β Parameterized queries only.
- No
anyβ@typescript-eslint/no-explicit-any: error. - No floating promises β Every async call must be
awaited. - ESM only β
.jsextensions in imports,"type": "module".
| Context | Style | Example |
|---|---|---|
| TypeScript code | camelCase |
getBalance(), ownerUserId |
| Types / Interfaces | PascalCase |
LedgerEntry, Money |
| DB columns / API DTOs | snake_case |
owner_user_id, idempotency_key |
| Booleans | isX / hasX / shouldX |
isActive, hasPermission |
| Files | PascalCase.ts |
AuthMiddleware.ts, SupabaseAdapter.ts |
project-blue/
βββ README.md
βββ render.yaml # Render.com deployment config
βββ adr/ # Architecture Decision Records
β βββ ADR-0001 Zero-Trust Boundary
β βββ ADR-0004 Ledger & DB Hardening
β βββ ADR-0007 Backend Architecture & Tech Stack
β βββ ADR-0009 Clean Architecture Folder Rules
β βββ ADR-0011 Code Style & Linting Standards
βββ system/ # System docs (SLOs, invariants, fitness rules)
βββ proto/
β βββ package.json # React + react-scripts prototype
β βββ public/ # Static HTML entry point
β βββ src/
β βββ App.tsx # All 13 prototype screens (single-file)
βββ server/
β βββ package.json # Workspace root (api-gateway + ledger)
β βββ jest.config.cjs # Jest config (3 projects, 90% threshold)
β βββ api-gateway/
β β βββ openapi.yaml # Full API specification
β β βββ src/
β β βββ domain/
β β βββ application/
β β βββ adapters/auth/ # SupabaseAdapter
β β βββ framework/ # Express, routes, middleware, config
β βββ ledger/
β β βββ src/
β β βββ domain/ # Money type
β β βββ framework/ # Express server
β βββ scripts/ # 16 fitness function scripts + tests
βββ client/
βββ mobile-app/
βββ App.tsx # Root component
βββ src/
βββ components/ # BottomNav
βββ constants/ # Mock data
βββ screens/ # 11 screen components
βββ types.ts
βββ utils/
Deployed to Render.com via render.yaml:
- API Gateway β Node.js web service, auto-discovers Ledger URL
- Ledger β Node.js web service, internal secret for auth
- Supabase credentials configured as environment variables
| ADR | Topic |
|---|---|
| ADR-0001 | Zero-Trust Boundary pattern |
| ADR-0004 | Append-only enforcement, compensating entries |
| ADR-0007 | Two-service split, Supabase as infra |
| ADR-0009 | Clean Architecture folder rules & DDD |
| ADR-0011 | Linting, no-float-money, import boundaries |
Private β not open source.