Make sure you have MongoDB installed and running on your local.
Initialize and edit config file:
cp src/config.example.js src/config.js
Install dependencies:
yarn
Seed database:
yarn run seed
Start client and server in separate terminals:
yarn run client
yarn run server
Always make your changes in a feature branch and create a PR against develop
branch. Our release branch is master
, which should only accept PR from develop
branch and hotfix branch.
To deploy new code:
ssh [email protected]
cd news
git checkout master
git pull
# Install latest dependencies
yarn
# Reload server
pm2 reload news-server
# Make client production build. Since we simply serves the static files,
# we don't need to restart the client server
yarn run build
To start client/server app on a fresh server:
pm2 start src/serveClient.js --name news-client
pm2 start src/server/index.js --name news-server
To restart client/server in case they're stopped:
pm2 restart news-client
pm2 restart news-server
The production environment is setup according to this tutorial.
pm2 is used to serve client and server app in the background. If we run pm2 list
, we should be able to see news-client
and news-server
running.
There are two endpoints configured for the production app:
https://bloc42.com
: serve client app.https://api.bloc42.com
: serve server app.
To edit Nginx server blocks:
sudo vim /etc/nginx/sites-available/bloc42.com
Client:
- React. Bootstrapped with create-react-app.
- GraphQL
- Apollo Client
Server:
Read here for more details.
Under src
folder:
index.js
: Entry point.components
: Dumb components. Cares about how things look.containers
: Smart components. Cares about how things work.pages
: Page components. Each corresponds to an url route.theme.js
: Theme provider for styled-components. Define global CSS variables here.serveClient.js
: To serve client build in production.
Under src/server
folder:
index.js
: Entry point.entities
: A collection of data entities. Everything releated to an entity, e.g., model and API, is defined within the entity folder.passport.js
: Configurations and strategy definitions for passport.schema.js
: Exports merged schema for GraphQL API.
Use camelCase
for:
- Variables.
- MongoDB document fields.
- GraphQL schema.
Use PascalCase
for:
- React component name and filename.
Use UPPER_CASE
for:
- Constants.
There is a useful tool to interact with GraphQL API:
http://localhost:3001/graphiql
You can explore available query and mutation in Documentation Explorer on the right panel.
Get post feed:
query {
postFeed {
posts {
id
title
author
}
}
}
Get post and its comments:
query {
postById(id: "5b5b9422347605b1342553f4") {
id
title
url
content
author
comments {
id
author
content
createdAt
}
}
}
Get current login user:
query {
currentUser {
id,
username
}
}
Sign up a user:
mutation {
signup(username: "foo", email: "[email protected]", password: "89hf9&*H") {
id,
username
}
}
A user is authenticated via koa-passport middleware after signup/login. The server will send back a session id and the browser saves the session id in cookie. The subsequent requests initiated by the browser will include this session id which allows the server to identify a specific user.
We use bcrypt to hash the password before we save a new user to the database. The implementation is in server/entities/user/model.js
.
After a user logged in or signed up, we update the currentUser
in Apollo cache. Once the user logs out, we reset the Apollo cache to make sure currentUser
is cleared.
After yarn run seed
, fake users will be created with password 123456
.
An admin account will also be created with username admin
.