Parent: Chat Service
REST API Request Flow
sequenceDiagram participant Client as Client App participant LB as Load Balancer participant MW as Express Middleware participant Ctrl as Controller participant Svc as Service participant DB as Database Client->>LB: HTTP Request LB->>MW: Forward Request MW->>MW: Auth (JWT verification) MW->>MW: Rate Limiting MW->>MW: Request Validation MW->>Ctrl: Validated Request Ctrl->>Svc: Business Logic Svc->>DB: Database Query DB-->>Svc: Result Svc-->>Ctrl: Processed Data Ctrl-->>Client: HTTP Response
WebSocket Message Flow
sequenceDiagram participant Client as Client Socket participant SocketIO as Socket.IO Server participant Auth as Auth Middleware participant Handler as Event Handler participant Svc as Service Layer participant DB as PostgreSQL participant Redis as Redis Adapter Client->>SocketIO: Connect + JWT SocketIO->>Auth: Validate Token Auth-->>SocketIO: Authenticated SocketIO->>SocketIO: Join Room (session:123) SocketIO-->>Client: connected event Client->>Handler: message:send Handler->>Svc: Process Message Svc->>DB: Save Message DB-->>Svc: Message ID Svc->>SocketIO: Broadcast to Room SocketIO->>Redis: Publish to Channel Redis-->>SocketIO: Sync Across Instances SocketIO-->>Client: message:new
Room-Based Architecture
Each chat session maps to a Socket.IO room named session:{id}. When users connect, they automatically join rooms for all their active chat sessions.
flowchart TB subgraph server1 [Server Instance 1] Room123_S1[Room: session:123] Customer1[Customer Socket] Customer1 --> Room123_S1 end subgraph server2 [Server Instance 2] Room123_S2[Room: session:123] Dentist1[Dentist Socket] Dentist1 --> Room123_S2 end subgraph redis [Redis Adapter] PubSub[Pub/Sub Channel] end Room123_S1 <-->|sync| PubSub Room123_S2 <-->|sync| PubSub
Key Points:
- Users can be connected to different server instances
- Redis adapter syncs room membership and events across instances
- Messages sent to a room are delivered to all participants regardless of which server they’re connected to
Send Message Flow
flowchart TD A[Client sends message] --> B{Via REST or Socket?} B -->|REST API| C[Authenticate JWT] B -->|Socket.IO| D[Already authenticated] C --> E[Verify session access] D --> E E --> F{Has images?} F -->|Yes| G[Upload to S3] F -->|No| H[Continue] G --> H H --> I[Save message to PostgreSQL] I --> J[Broadcast to Socket.IO room] J --> K[Redis adapter syncs to other instances] K --> L{Recipient online?} L -->|Yes| M[Deliver via WebSocket] L -->|No| N[Send push notification] M --> O[Done] N --> O
Push Notification Logic
Push notifications are sent when the message recipient is offline (not connected to any Socket.IO server instance).
flowchart TD A[Message saved to DB] --> B[Check recipient online status] B --> C{Is recipient in any room?} C -->|Yes| D[Skip notification] C -->|No| E[Lookup OneSignal player ID] E --> F{Player ID exists?} F -->|No| G[Skip notification] F -->|Yes| H[Send push via OneSignal] H --> I[Fire and forget]
OneSignal Integration:
- Player IDs are stored in
customer_notification_mapping - Notifications include sender name and message preview
- Deep links open the specific chat in the mobile app
Message Read Flow
sequenceDiagram participant Recipient as Recipient Client participant Server as Socket.IO Server participant DB as PostgreSQL participant Sender as Sender Client Recipient->>Server: message:read (messageId) Server->>DB: Update is_read, read_at DB-->>Server: Updated Server->>Sender: message:read_receipt Note over Sender: UI updates read status
Typing Indicator Flow
sequenceDiagram participant UserA as User A (Typing) participant Server as Socket.IO Server participant UserB as User B (Viewing) UserA->>Server: typing:start Server->>UserB: typing:indicator (isTyping: true) Note over UserB: Show typing indicator Note over UserA: User stops typing (3s timeout) UserA->>Server: typing:stop Server->>UserB: typing:indicator (isTyping: false) Note over UserB: Hide typing indicator
Horizontal Scaling
The Chat Service is designed for horizontal scaling without sticky sessions.
flowchart TB subgraph clients [Clients] C1[Client 1] C2[Client 2] C3[Client 3] end subgraph lb [Load Balancer] ALB[ALB / NGINX] end subgraph servers [Server Pool] S1[Instance 1] S2[Instance 2] S3[Instance 3] end subgraph redis [Redis] Adapter[Socket.IO Adapter] Cache[JWKS Cache] end C1 --> ALB C2 --> ALB C3 --> ALB ALB --> S1 ALB --> S2 ALB --> S3 S1 <--> Adapter S2 <--> Adapter S3 <--> Adapter S1 --> Cache S2 --> Cache S3 --> Cache
Scaling Mechanisms:
| Component | Strategy |
|---|---|
| WebSocket connections | Redis adapter for cross-instance messaging |
| JWT validation | JWKS cached in Redis |
| Database connections | Connection pooling per instance |
| Session state | Stateless design - no server-side sessions |
| Room membership | Synchronized via Redis adapter |
Image Upload Flow
flowchart LR A[Client uploads image] --> B[Multer middleware] B --> C[Validate file type/size] C --> D[Generate S3 key] D --> E[Upload to S3] E --> F[Store S3 key in message] F --> G[Generate presigned URL] G --> H[Return URL to clients]
S3 Key Format:
chat-service/sessions/{sessionId}/messages/{messageId}/{uuid}.{ext}
Presigned URLs:
- Generated on-demand when fetching messages
- Expire after 60 minutes for security
- Support for multiple images per message (max 5)
Security Measures
| Measure | Implementation |
|---|---|
| Authentication | JWT verification (Cognito + Django) |
| Authorization | User must be participant in chat session |
| Rate Limiting | Per-user and per-IP limits |
| Input Validation | Request body validation via middleware |
| XSS Protection | Helmet middleware |
| CORS | Configured allowed origins |
| Presigned URLs | Time-limited S3 access |