npx create-react-app chime-in-ui --template typescript
npm i @mui/material @emotion/react @emotion/styled @fontsource/roboto @mui/icons-material
createTheme
API andThemeProvider
for dark themeCssBaseline
for base styling
npm i react-router-dom localforage match-sorter sort-by
- packages:
react-router-dom
,localforage
,match-sorter
,sort-by
- react-router-dom is used for routing
- localforage is used for storing data in local storage
- match-sorter is used for sorting and filtering data
- sort-by is used for sorting data
- install nestjs globally:
npm i -g @nestjs/cli
- create a new nestjs project:
nest new chime-in-be
pnpm run start:dev
to start the server
pnpm i @nestjs/config @nestjs/mongoose mongoose
- @nestjs/config: Configuration module for Nest
- @nestjs/mongoose: Mongoose module for Nest
- mongoose: MongoDB object modeling tool
pnpm i joi
for validation- will validate env variables as well
- mongodb installation: https://www.mongodb.com/docs/manual/installation/
- install mongo for mac: https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/
- create a folder data/db in ~ and from ~ run:
mongod --dbpath=data/db
- run be:
pnpm run start:dev
and check if the connection is successful- mongod should log "msg":"Connection accepted"
- be should log "MongooseCoreModule dependencies initialized"
- if already running please kill the process.
ps aux | grep mongod
kill <processid>
pnpm i @nestjs/graphql @nestjs/apollo @apollo/server graphql
- graphql playground: http://localhost:3000/graphql
nest g resource users
- abstract schema for common fields
- abstract repository for common methods
pnpm i bcrypt
andpnpm i -D @types/bcrypt
- sample graphql queries and mutations:
- createUser:
mutation {
createUser(createUserInput:{
email:"[email protected]",
password: "password123"
}) {
_id
email
}
}
- https://github.com/pinojs/pino
- Docs: https://www.npmjs.com/package/nestjs-pino
pnpm i nestjs-pino pino-http pino-pretty
- we will use https://www.npmjs.com/package/migrate-mongo
pnpm i migrate-mongo
- type:
pnpm i -D @types/migrate-mongo
pnpm i mongodb
: to get access to the types- create migration for user email index and make it unique
- we can use this for validation to make sure we don't have duplicate emails
- in mongo client we should be able to see
email_1
index - and in changelog we should see the migration file details
- apollo client is a graphql client that helps us to interact with the graphql server from the client side i.e. our react app
- it will help us manage data both local and remote
- it will help us fetch, cache and modify data
- we need to write query and mutation on UI using graphql with apollo client
pnpm i @apollo/client graphql
from ui folder
- install apollo client devtools extension (ext id: apollographql.vscode-apollo)
- to fix CORS issue:
- use proxy in package.json:
"proxy": "http://localhost:3001"
. this will proxy all requests to 3000
- use proxy in package.json:
pnpm install --save @nestjs/passport passport passport-local
pnpm install --save-dev @types/passport-local
- https://docs.nestjs.com/recipes/passport
- https://www.passportjs.org/packages/
- we are using passport-local strategy for now
- it will accept a username and password and authenticate the user and return a jwt token
- generate auth module:
nest g module auth
- generate auth service:
nest g service auth
- Expose local strategy as a guard
- https://docs.nestjs.com/guards#authorization-guard
nest g controller auth
- read more about custom decorators: https://docs.nestjs.com/graphql/other-features#custom-decorators
- https://docs.nestjs.com/recipes/passport#jwt-functionality
pnpm install --save @nestjs/jwt passport-jwt
pnpm install --save-dev @types/passport-jwt
- generate secret key:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
- you can decode jwt token at https://jwt.io/
- send jwt token back in reponse
- use jwt strategy to authenticate jwt and apply to graphql, REST endpoints
pnpm i cookie-parser
: to parse cookies from request and attach to responsepnpm i -D @types/cookie-parser
- https://www.npmjs.com/package/cookie-parser
- use cookie parser to parse cookies from request and attach to response
- use jwt strategy to authenticate jwt and apply to graphql, REST endpoints
- create useLogin.ts hook
- if user is not signed in, redirect to sign in page
- let's do this by checking the status code, if it is 401, redirect to sign in page
- also if jwt token is expired, backend will return 401
- TODO 🚨: Currently unauthenticated errors from apollo are uncaught and we need to fix this. This happens during logout
- after successful login, redirect to home page
- TODO: 🚨 Navigation not working on clicking the links
- create chat resource
nest g resource chats
- for validation: https://docs.nestjs.com/techniques/validation#using-the-built-in-validationpipe
pnpm i --save class-validator class-transformer
- install on ui code base
- https://the-guild.dev/graphql/codegen/docs/getting-started/installation
npm i -D @graphql-codegen/cli @parcel/watcher
- graphql codegen will generate types for us
- parcel watcher will watch for changes and regenerate types
npx graphql-code-generator init
- run watch script parallely using https://www.npmjs.com/package/concurrently
npm i -D concurrently
- we created a findAll method in chat service
- on FE we created useFindChats to call the graphql query
- we also created a chat.fragment.ts to define the fields we need from the chat object
- after chat creation, update the cache with the new chat (useCreateChat hook)
- also make sure to export the chat fragment from chat.fragment.ts
- add error handling
- each chat will have multiple messages
- one to many relationship
nest g resource chats/messages
- this will generate all the stub files
- https://docs.nestjs.com/fundamentals/circular-dependency
- to update the cache for particular chatId, use readQuery and writeQuery
- TODO: 🚨 Check why content IsNotEmpty validaiton not working for createMessage
- To receive real-time updates from the server, we will use GraphQL Subscriptions.
- why websockets?
- we can use polling but it is not efficient
- websockets are more efficient
- why websockets?
- on BE:
pnpm i graphql-ws graphql-subscriptions
- https://github.com/enisdenjo/graphql-ws
- this will help us to create a websocket server using graphql
- https://www.npmjs.com/package/graphql-subscriptions
- this will help us establish pub sub functionality
- Implement pub sub functionality
- implement locally at first and make it persistent later
- install on FE:
pnpm i graphql-ws
- REACT_APP_WS_URL=localhost:3001 because we won't get CORS issues for WS.
- use split in apollo client to separate http and ws
- add jwt token to websocket connection in app.module.ts
- so that it is real-time visible on UI
44 Improve Messages aggregation on chat entity, user aggregation on message entity, add support for username, UI changes
- create chat.document.ts file to store the chat mongoose schema
- use chat.entity.ts file for graphql schema
- TODO: Fix the sidebar cache issue
nest g controller chats
- create chats.controller to add
chats/counts
GET endpoint to count the number of chats
- infinite scroll libraries
- https://www.npmjs.com/package/react-infinite-scroll-hook (1KB)
- https://www.npmjs.com/package/react-infinite-scroller (2KB) - we are using this to explore a new library
- npm i -D @types/react-infinite-scroller
- useCountChats hook and update useFindChats hook to accept skip and limit
- customize apollo-client cache to merge the new data with the old data
nest g controller chats/messages
- https://aws.amazon.com/
- aws s3 free tier: https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=*all&awsf.Free%20Tier%20Categories=*all
- Steps:
- setup aws account
- create an s3 bucket (in search bar type s3)
- create a user with s3 access (in search bar type iam) - click users - create user
- assign s3 full access policy to the user
- create security credentials for the user
- https://docs.nestjs.com/techniques/file-upload
pnpm i -D @types/multer
,nest g module common/s3
nest g service common/s3
pnpm i @aws-sdk/client-s3
- to fix the s3 url access issue, add a new policy to the bucket
- go to bucket -> permissions -> bucket policy -> edit policy
-
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Principal": "*", "Effect": "Allow", "Action": "s3:GetObject", "Resource": [ "arn:aws:s3:::chime-in-users/*", "arn:aws:s3:::chime-in-users" ] } ] }
- create an IAM role with policies
- AWSElasticBeanstalkMulticontainerDocker
- AWSElasticBeanstalkWebTier
- AWSElasticBeanstalkWorkerTier
- choose t2.micro instance for free tier: Instance types
-
This will help us to automate the deployment process
-
ProcFile is used to specify the commands to run on the server
-
make sure symlinks=false is set in .npmrc because symlinks for pnpm are not supported on elastic beanstalk