Case study
ByteWallet
Personal finance · Gmail auto-record · API design · Multi-platform
A personal finance app for multi-wallet cashflow, friend transfers, split bills, and Gmail auto-recording of bank and e-wallet emails — Expo client, NestJS API, iOS, Android, and web.
System architecture
The system I built
I designed how these layers connect — interface, business rules, data, and delivery — not only the screens on top.
01
User apps
Expo mobile, Expo web, Personal AI, RightNow
02
Core product
Wallets, transactions, friends, Trace, split bills, analysis
03
API
NestJS REST + WebSocket, JWT and API-key guards
04
AI + data
Scoped AI keys, PostgreSQL, Redis, notifications
How the layers connect
Labeled arrows show which parts talk to each other, and how.
User applications
Mobile app
Expo React Native
Web app
React / Expo web
Personal AI chat
Read-only integration
RightNow chat
Read + write integration
Client layer
Authentication
Email/password, Google OAuth, Remember Me
Local storage
AsyncStorage and Secure Store
AI integrations
Personal AI
Read-only finance access
RightNow
Read and write finance access
API key management
Create, list, revoke, hash, expiry
Core features
Multi-wallet
Per-wallet currency and Main wallet
Transactions
Income, expense, transfer, borrow, lend
Friends
Requests and friend transfers
AR/AP Trace
Payable and receivable debts
Split bills
Shared expenses and public share links
Analysis
Cashflow charts, heatmap, PDF export
ByteWallet API
HTTP + WebSocket
App and integration traffic
Auth guards
JWT, API keys, role, owner
Business logic
Wallets, transactions, debts, friends, split bills, AI, notifications
Security
API key hashing
SHA-256 storage
Owner guard
User isolation
Scope enforcement
finance:read and finance:write
Rate limiting
Per API key
Audit logging
Key ID and action
Data layer
PostgreSQL
Supabase
Redis
Cache and notifications
Notifications
In-app, WebSocket, Expo push
Personal AI chat
Read-only Q&A
Balance, spending, debt inquiry
RightNow chat
Finance Q&A
LLM tool calling
Bot commands
/expense, /income, /transfer with confirmation




Problem
Everyday money is split across wallets, friends, and bank notification emails. ByteWallet needed one product for cashflow, P2P debts, and split bills — plus an opt-in path to turn Gmail bank alerts into ledger entries without pasting them by hand.
My contribution
- Designed the product around multi-wallet cashflow, a reserved Main wallet for friend money, and NestJS modules with transactional boundaries
- Built the Expo app (tabs, auth, wallet detail, Trace, split bills, analysis, Gmail sync settings) and the typed API client
- Implemented auth (email/password, Google OAuth, OTP reset, JWT sliding sessions) and wallet rules that block income/expense on Main
- Shipped Gmail auto-recording: readonly OAuth, AES-256-GCM refresh-token storage, Gemini parsing, SHA-256 dedup, pending review, and 15-minute polling with Sync Now
- Modeled friend transfers, AR/AP Trace (repay, mark received, reject/refund), and split bills with time-limited public share links
- Added scoped API keys for Personal AI (read) and RightNow (read/write), plus in-app, WebSocket, and push notifications
- Deployed the web client on Cloudflare Pages and the NestJS API on Render, including cold-start wake
Engineering challenges
- Parsing messy bank and e-wallet emails without double-counting the same alert
- Keeping Gmail credentials encrypted at rest and never sending refresh tokens to the model
- Enforcing Main-wallet rules while friend transfers and repayments still land immediately
- Letting users review auto-detected mail (edit wallet, category, type) before it becomes a transaction
- Shipping one codebase to iOS, Android, and web without treating the API as an afterthought
Why I made this decision
- Why a reserved Main wallet?
- Friend transfers and repayments needed a single, non-deletable destination so P2P money did not mix with everyday income and expense on spending wallets.
- Why pending review for Gmail sync?
- Gemini extraction is useful but not infallible. An opt-in queue lets people edit type, category, note, and wallet — or reject — before the ledger changes.
- Why NestJS modules instead of a thin BFF?
- Wallets, debts, Gmail sync, and API-key scopes needed guards, DTOs, and transactional services. A modular API kept those boundaries explicit.
- Why Expo for the client?
- One React Native app covering iOS, Android, and web matched the product surface (tabs, push, PDF export) without a separate native stack.
Delivery
- Git
- Development
- Local testing
- CI / build
- Cloudflare Pages + Render
- Production
Result
Live web app at bytewallet.pages.dev (iOS, Android, and web from Expo)
Gmail auto-record with encrypted tokens, Gemini parse, and pending review
Wallets, Trace AR/AP, split bills, notifications, and scoped AI API keys in one NestJS API