Technical Architecture
Three-platform system: Node.js backend, React web client, and native iOS app connected via REST API and WebSocket.
1 Tech Stack
Server (Backend) Node.js
Fastify 5— HTTP framework@fastify/websocket— real-time chatTypeScript— strict mode, ESMSupabase— PostgreSQL + AuthOpenAI API— GPT-4o / GPT-5Zod 4— runtime validationVitest— testing
Web (Frontend) React
React 19— UI libraryVite 7— build toolTypeScript— strict modeZustand— state managementTanStack Query— server stateTailwind CSS 4— stylingRecharts— charts
iOS (Mobile) Swift
SwiftUI— declarative UIURLSession— HTTP + WebSocketCombine— reactive data flowKeychain— secure storageCertificate pinning— security17 chart views— native chartsLocalization— EN + RU
2 System Architecture
3 Server Directory Structure
4 Chat Message Processing Flow
User Sends Message
Natural language via WebSocket (wss://api.monaime.app/ws/chat). First message must include auth token.
Rate Limit + Command Parsing
Rate limiter checks (30 msg/min). CommandParser calls GPT-4o-mini to extract structured command (action type, parameters) from natural language.
Entity Resolution
EntityResolver resolves text references to real IDs using fuzzy matching: exact → normalized → prefix → contains. Wallets, categories, contacts, etc.
Validation & Safety Check
CommandValidator checks if action is dangerous (delete_wallet, delete_transaction, close_debt). If dangerous — sends confirmation request to user.
Action Execution
ActionExecutor routes to the correct action in ActionRegistry. Action validates params (Zod), performs DB operations, returns result.
AI Response Generation
AIService streams response via GPT-4o. Includes action result, user context, conversation history. Response is streamed chunk-by-chunk via WebSocket.
Cards & Data Updates
Server sends entity cards (card, batch-cards, grouped-cards) and data_updated events for client cache invalidation.
5 WebSocket Message Protocol
| Type | Direction | Description |
|---|---|---|
| { token } | Client → Server | Authentication (first message) |
| authenticated | Server → Client | Auth success confirmation |
| message | Both | Text message (user input / bot response) |
| stream_start | Server → Client | AI response streaming begins |
| stream / stream_chunk | Server → Client | Partial AI response chunk |
| stream_end | Server → Client | AI response streaming complete |
| card | Server → Client | Single entity card (transaction, wallet, etc.) |
| batch-cards | Server → Client | Array of cards |
| grouped-cards | Server → Client | Cards organized in named groups |
| data_updated | Server → Client | Cache invalidation signal with data snapshot |
| typing | Server → Client | Bot is processing |
| error | Server → Client | Error message |
| stop_generation | Client → Server | Stop current AI generation |
6 Key Server Services
AIService
OpenAI API wrapper. Supports GPT-4o and GPT-5. Streaming responses, function calling for command parsing.
CommandParser
Parses natural language into structured commands using GPT-4o-mini. Extracts action type, parameters, entities.
EntityResolver
4-step fuzzy matching: exact, normalized (remove spaces), prefix, contains. Supports entity aliases.
ContextService
Caches user context (wallets, categories, contacts) with 60s TTL to reduce DB queries.
TriggerEngine
7 trigger types: budget limits, goal milestones, salary detection, anomalies, recurring reminders, debt reminders, suggestions.
SchedulerService
Hourly background tasks: process recurring templates, check reminders, debt due dates. Budget spent is computed at query time (no cron needed).
MemoryService
Conversation summarization with OpenAI embeddings (text-embedding-3-small). Stored in pgvector for semantic search (RAG).
ActionHistoryService
Logs all CRUD operations for undo functionality. Stores previous and new state. Auto-cleans (keeps 50 per user).
7 iOS App Architecture (MVVM)
8 Web App Architecture
9 Authentication Flow
Sign In
User signs in via Supabase Auth (email/password or OAuth). Returns access_token, refresh_token, expires_in.
Token Storage
iOS: stored in Keychain. Web: stored in Zustand (persisted to localStorage). Server never stores tokens.
API Requests
REST: Authorization: Bearer <token> header. WebSocket: first message contains { token }. Server validates via supabase.auth.getUser(token).
Token Refresh
Proactive refresh 5 min before expiry. On refresh: WebSocket reconnects with new token. HTTP client uses new token automatically.
10 Environment Variables
| Variable | Required | Description |
|---|---|---|
| PORT | No (3000) | Server port |
| HOST | No (0.0.0.0) | Server host |
| NODE_ENV | No | development / production / test |
| SUPABASE_URL | Yes | Supabase project URL |
| SUPABASE_ANON_KEY | Yes | Supabase anon key (for client auth checks) |
| SUPABASE_SERVICE_KEY | Yes | Supabase service role key (for DB operations) |
| OPENAI_API_KEY | Yes | OpenAI API key |
| JWT_SECRET | Yes | JWT secret (min 32 chars) |
| CORS_ORIGIN | No | Allowed CORS origins (comma-separated) |
| FIXER_API_KEY | No | Fixer.io API key for exchange rates |
| AI_MODEL_FAMILY | No | gpt-4o or gpt-5 (default: gpt-5) |