Skip to content

afallahi/chat-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Node.js AWS

TypeScript npm

Chat App

Requirements

Functional Requirements

  • Conversation: Supports one-on-one conversation between 2 users. Both User A and User B can initiate the call to start chat with the other party.
  • Message Processing: Chat service stores and relays the messages.
  • Acknowledgement: Users get acknowledgemnets on their messages.
  • Media: Messages are in plain text.
  • Storage: Chat service provides persistent storage to save the messages when the recipient is offline.

Out of scope:

  • Media sharing: Users share files and photos
  • Notification: Users get notified if they are offline and get new messages.

Non-Functional Requirements

  • Consistency: Chat service delivers the messages in the same order of receiving from chat parties.
  • Low Latency: User should recieve messages with low latency.
  • Availability: Should be highly available.
  • Scalability: Should be highly scalable and adapt to the workload (i.e. number of users and number of messages in a given time period)
  • Security: Communication must be secure.

System Design

High Level Design

Communication Protocol

  • Http(s): Http is client-initiated protocol and server can not initiate the conversation. Http with keep-alive in header may establish a connection with the server. But this does not help the server to start the communication.
  • Polling: Client requests data from the server priodically. This is inefficient as it leads to high number network calls.
  • Long polling: To reduce the number of requests, server keeps the connection open till there is data to send.
  • Websockets: Common solution for bidirectional real-time communication on a single connection with the lowest latency. We can use this to send async messages from server to the client.

Service Types

  • Stateful services: chat service is the only stateful service and users have persistent network connection.
  • Stateless services: Authentications, profiles, etc (TBD)
  • Third party integrations: e.g. push notifications (TBD)

Architecture

  • Monorepo architecture to accommodate both frontend and backend projects in the same repository.
  • Serverless, Event-driven, Function as a Service (FaaS) in the backend with AWS Lambda functions. This gives us high availability for backend services.
  • Host frontend in AWS S3.

Database

Stateless Services

For services like Authentication and Profile (TBD), Relational databses are a good candidate. We'll revist this once these services implemented.

Chat Service Database

For Chat service, we will have huge amout of data which users may want to access although the request to have the most recent chat history is more frequent. A key-value NoSQL database looks a better candidate to support our needs although some features (e.g. search) out of scope but might be implemented later. For our Serverless Architecture, we use DynamoDB database.

  • DynamoDB is a serverless service meaning that it's billed based on your usage and well integrated with Lambda service that we are using.
  • DynamoDB is horizontally scalable.
  • DynamoDB provides low latency to access data.
  • DynamoDB is a good candidate if later we decide to improve our service and make it Multi-Region service with Global Tables. This will result to even lower latency for a system to serve the users across the globe. You may find more details of a Multi-region serverless architecture with DynamoDB Global Tables here.

Data Models

TBD

API Design

  • connect
  • disconnect
  • send message
  • get messages
  • get users

Security

We benefit from API Gateway features to enforce security of the application. We also need to take more steps to make the connection secure.

  • Communications Encryption: API Gateway provides encrypted websockets over Transport Layer Security (TLS) with scheme wss://.
  • Cross-Site Websocket Hijacking: This is Cross-Site request Forgery (CSRF) for websockets. If Websocket uses cookies for handshakes in the session and does not provide CSRF token, the connection is vulnerable to an attack in which the attacker may obtain sensitive information by establishing a cross-site websocket connection. We are not establishing sessions and are not facing this attack.
  • Denial of Service (DoS): API gateways employ rate limiting and throttling as security measures to mitigate DoS attacks.
  • Input Validation: If server does not valiadate and sanitize the input, the request to the server might be intercepted and trigger SQL injection or Cross-Site Scripting (XSS) attack by replacing the payload of the request.
  • Authentication and Authorization: Authentication has not been implemented in this project yet (TBD).

Diagram

Backend Microservice Design Pattern

We select Serverless Architecture for the backend with the following details.

Event-driven

We detect the events and act based on them on decoupled services.

Benefits

  • Scale and fail independently by decoupling services
  • Agile development with leveraging the event router
  • Reduce costs by spinning the server (or serverless functions) only when trigerred by the event.

Function as a Service (FaaS)

Function as a Service (FaaS) is the comouting part of the Serverless architecture.

Benefits

  • Decoupled
  • Lightweight
  • Highly Scalable
  • Highly Available
  • Very cost efficient (pay per use)

Backend Implementation

We use API Gateway (WebSocket), Lambda functions, and DynamoDB which are well suited for Serverless application and follow the event-driven architecture with FaaS serverless compute.

Note: With Serverless architecture, we no longer need Load balancer or services like Zookeeper for Service Discovery. API Gateway is good enough for this purpose and our Serverless architecture adapts well to the workload with Lambda functions.

Usage

Deployment

Backend

npm run deploy

Frontend

We are going to manually upload our React app to S3 bucket and create a website which will be avilable through Cloudfront.

Deploy Frontend with AWS CLI

Create a bucket policy that allows public read:

touch ./bucket_policy.json
code ./bucket_policy.json

Add the following into the policy json file:

    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<bucket-name>/*"
        }
    
    ]
}

Run the commands below to get the website url:

npm run build
aws s3api create-bucket --bucket <bucket-name> --region=us-east-1

# When creating a new bucket, default policy doesn't grant public access (Amazon S3 Block Public Access is enabled). If your new bucket # # policy grants public access, you need to run this:

aws s3api delete-public-access-block --bucket <bucket-name>
aws s3api put-bucket-policy --bucket chat-frontend --policy file:///tmp/bucket_policy.json
aws s3 sync ./build s3://<bucket-name>/
aws s3 website s3://<bucket-name>/ --index-document index.html --error-document index.html

The website should be available at

http://<bucket-name>.s3-website.us-east-1.amazonaws.com/

Deploy Frontend with AWS Amplify

To host the app with CloudFront and S3 using Amplify, use the chat-amplify folder and follow the steps below to publish the app:

First configure the project

npm install
amplify configure
amplify int

Now is the time to publish

amplify add hosting
amplify publish

Demo

Postman Chat App
postman-to-chat-app chat-app-to-postman

chat-app

CI/CD (TBD)

We use AWS CodePipeline. A Lambda function accommodates the logic to trigger the appropriate pipeline for each project (i.e. backend and frontend).

Enhancements - Multi_Region Architecture (TBD)

Users across the globe connect to the same APIs as well as frontend url available in edge locations.

Frontend

  • Set up a routing rule on Route 53 (e.g. least latency) to route the users to a region.
  • Lambda function maps the S3 buckets to regions and modifies the request to hit the right region.

backend