FinTrack is a personal finance management web application built with a MERN-based stack, featuring real-time updates via WebSockets, secure JWT authentication, and a custom state management system.
This guide provides comprehensive documentation of the architecture, real-time capabilities, testing framework, and outstanding tasks to help new developers or AI assistants quickly understand the system.
- Initializes and manages all WebSocket client connections
- Performs JWT authentication immediately upon client connection
- Supports real-time events:
transaction:added,transaction:updated,transaction:deleted - Maintains authenticated client list for secure broadcasting
- Handles reconnection and connection status tracking
// Example WebSocket initialization from server.js
const { initializeWebSocketServer } = require('./wsController');
// Initialize WebSocket server after HTTP server is running
const wss = initializeWebSocketServer(server);
// Store WebSocket server instance for use in routes
app.set('wss', wss);- Every WebSocket message includes a token for verification
- Server-side verification using
jsonwebtokenlibrary - Unauthorized clients are rejected with appropriate error messages
- Authenticated clients receive confirmation and can participate in real-time updates
// Example authentication handling in wsController.js
function handleAuthentication(ws, token) {
try {
// Verify token
const decoded = jwt.verify(token, JWT_SECRET);
// Set authenticated state and user ID
ws.authenticated = true;
ws.userId = decoded.userId || decoded.id;
// Send authenticated message
ws.send(JSON.stringify({
type: 'authenticated',
payload: { userId: ws.userId }
}));
} catch (error) {
// Send unauthorized message
ws.send(JSON.stringify({
type: 'unauthorized',
payload: { message: 'Invalid token' }
}));
}
}- Transaction routes (
/api/transactions) perform CRUD operations on MongoDB - Upon successful database updates, WebSocket broadcast functions are triggered
- Broadcasts ensure all connected clients receive real-time updates
// Example from transaction.js route handler
// After saving a transaction to the database:
const wss = req.app.get('wss');
if (wss) {
broadcastToAuthenticated(wss, {
type: 'transaction:added',
payload: savedTransaction
});
broadcastToUser(wss, req.user._id.toString(), {
type: 'transaction:added',
payload: savedTransaction
});
}- Connects to
ws://localhost:5000and handles reconnection logic - Performs authentication after socket connection is established
- Emits messages in the format:
{ type, token, payload } - Handles server responses and dispatches events to the state manager
- Queues messages during offline periods for later processing
// Example authentication in webSocketService.js
authenticate() {
if (this.isConnected() && this.token) {
// Send authentication message in the format expected by the backend
this.socket.send(JSON.stringify({
type: 'authenticate',
token: this.token,
payload: {}
}));
this.log('Authentication request sent');
}
}All WebSocket messages follow a consistent format:
{
type: "event:name", // The type of message/event
token: "jwt-token", // JWT token for authentication (when sending to server)
payload: { // The actual data being transmitted
// Event-specific data
}
}realTimeTest.jsprovides comprehensive testing tools- Methods include:
testAPI(): Tests adding transactions via APItestWebSocket(): Tests WebSocket event receptiontestStore(): Checks store updatestestUI(): Verifies UI reacts to store changestestFullFlow(): Tests the complete flow from API → UItestMultiTab(): Tests cross-tab WebSocket synchronization
// Example usage of testing tools
// In browser console:
realTimeTest.testAPI(); // Test adding transaction via API
realTimeTest.testWebSocket(); // Confirm real-time event received
realTimeTest.testFullFlow(); // Test full API → WebSocket → Store → UI flow- Runs end-to-end tests for real-time functionality
- Generates detailed pass/fail reports
- Supports UI display and JSON export of test results
- Helps validate the complete transaction flow
- Custom store implementation with publish/subscribe pattern
- UI components subscribe to relevant state changes
- Store gets updated from WebSocket events or API responses
- Provides a consistent interface for state mutations
// Example state subscription in a component
store.subscribe('transactions:updated', (transactions) => {
// Update UI with new transaction data
renderTransactions(transactions);
});- Dynamic connection status indicator shows:
- "Connecting": Initial WebSocket connection attempt
- "Connected": WebSocket connected but not authenticated
- "Authenticated": Fully authenticated and ready for real-time updates
- "Disconnected": Connection lost
- "Error": Connection or authentication error
- TailwindCSS used for styling (currently via CDN)
- Secure Communication: WebSocket connections with token-based authentication
- Real-Time Sync: Transaction updates sync across multiple browser tabs
- Dynamic Updates: UI updates without page refresh when data changes
- Testing Framework: Comprehensive tools for testing real-time functionality
- Status Monitoring: Visual indicators for connection status
- Offline Support: (Partial) Message queuing for offline scenarios
The complete flow for real-time updates follows this pattern:
- User Action: User adds/updates/deletes a transaction in the UI
- API Call: Frontend makes a secure API call to the backend
- Database Update: Backend updates the MongoDB database
- WebSocket Broadcast: Backend broadcasts the change via WebSocket
- Client Reception: All connected clients receive the WebSocket message
- State Update: Each client updates its local state store
- UI Update: UI components subscribed to the state are automatically updated
-
Offline Queue Processing
- Complete implementation of queue flushing logic
- Add conflict resolution for operations performed while offline
-
Extend Real-Time Sync
- Add WebSocket support for budget entities
- Add WebSocket support for savings goals
- Ensure consistent event naming and payload structure
-
Connection Resilience
- Implement exponential backoff in WebSocket reconnection logic
- Add more robust error recovery mechanisms
-
Performance Optimization
- Migrate from Tailwind CDN to PostCSS build for production
- Add performance logging for latency tracking
- Optimize payload size for WebSocket messages
-
Error Handling
- Improve user feedback during connection issues
- Add fallback mechanisms for when WebSockets are unavailable
-
API Testing
realTimeTest.testAPI();
Verifies that transactions can be added via the API.
-
WebSocket Testing
realTimeTest.testWebSocket();
Confirms that WebSocket events are properly received.
-
Full Flow Testing
realTimeTest.testFullFlow();
Tests the complete flow from API to UI updates.
-
Multi-Tab Testing
// In tab 1 realTimeTest.testMultiTab(); // In tab 2 (after opening a second browser tab) realTimeTest.testMultiTab();
Verifies that changes sync across multiple browser tabs.
-
Comprehensive Report
testReport.runAllTests(); testReport.displayReport();
Runs all tests and generates a visual report.
-
Backend
wsController.js: WebSocket server implementationserver.js: Main Express server with WebSocket initializationroutes/transaction.js: API routes with WebSocket broadcasting
-
Frontend
js/services/webSocketService.js: WebSocket client implementationjs/state/stateManager.js: Custom state managementjs/utils/realTimeTest.js: Testing utilitiesjs/utils/testReportGenerator.js: Test reporting tools
- JWT tokens should have appropriate expiration times
- WebSocket messages should be validated on both client and server
- Consider implementing rate limiting for WebSocket messages
- Ensure proper error handling to prevent information leakage
This guide serves as a comprehensive reference for the FinTrack application's real-time architecture. For questions or assistance, please contact the development team or refer to the codebase directly.