diff --git a/Home.md b/Home.md index b329190..b2e9623 100644 --- a/Home.md +++ b/Home.md @@ -1,12 +1,24 @@ # Welcome to the MERN-template wiki! -This is the place where you can learn about the MERN-template and it's microservices. Things like contributing to and using the MERN-template, as well as general documentation of the system as a whole or in part. +This is the place where you can learn about the MERN-template and its various associated services. ## What is the MERN-template? -MERN can stand for a few things, but in this case it means "MariaDB, Express, React and Nodejs". This are a series of technologies commonly used to create websites (also known as a "stack"). +"MERN" stands for "MariaDB, Express, React and Nodejs"; these are a series of web technologies I used to build a simple, reusable template. -I determined that I might want to reuse some parts of the website I was planning to make, so I wrote the template first, to make it easier to reuse. Then, I released it so other people could use it too! +This template is built using a design pattern called "microservices" - where certain parts are separated into their own code repositories, and pulled in only when needed. The currently available services include: + +* News Server: https://github.com/krgamestudios/news-server +* Auth Server: https://github.com/krgamestudios/auth-server +* Chat Server: https://github.com/krgamestudios/chat-server + +These services each manage a different element of the template, but most of their documentation can be found in this wiki. The above listed services cover: + +* The news feed on the front page +* Account creation and logging in +* The ugly chat window in the bottom corner + +As I've developed this template, and the first game based on it, I've also written a lot about it. The goal is to document as much about it as I can, to provide a solid reference point for anyone interested in using this template. # Start Here diff --git a/authentication.md b/authentication.md index ce3aefb..d25eed8 100644 --- a/authentication.md +++ b/authentication.md @@ -1,7 +1,208 @@ -# JSON Web Tokens +# Authentication -I happened to have written an article for blog.pbbg.com that covers JWTs and their usage really well, so allow me to point you there: +*This page has been adapted from an article I wrote for the PBBG blog some time ago, with updated information.* -* [Making Egg Trainer 6](https://blog.pbbg.com/making-egg-trainer-6/) +## Premise -I should note that the "privilege" field is no longer used - it has been replaced with booleans for "admin", "mod" and an enumeration for account type (usually set to "normal"). \ No newline at end of file +A JWT (pronounced "jot") is a method for uniquely identifying an individual using a seemingly arbitrary set of characters. + +To begin, you need a "payload" to be encoded into the JWT. + +``` +{ + "index": "1", + "email": "krgamestudios@gmail.com", + "username": "Ratstail91", + "type": "alpha", + "admin": true, + "mod": true, + "iat": 1703343779, + "exp": 1703344379, + "iss": "auth" +} +``` + +You also need a header containing the algorithm information. + +``` +{ + "alg":"HS256", + "typ":"JWT" +} +``` + +Then, you combine the header and payload, converting both to base64 and separating them with a period. + +``` +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbmRleCI6IjEiLCJlbWFpbCI6ImtyZ2FtZXN0dWRpb3NAZ21haWwuY29tIiwidXNlcm5hbWUiOiJSYXRzdGFpbDkxIiwidHlwZSI6ImFscGhhIiwiYWRtaW4iOnRydWUsIm1vZCI6dHJ1ZSwiaWF0IjoxNzAzMzQzNzc5LCJleHAiOjE3MDMzNDQzNzksImlzcyI6ImF1dGgifQ +``` + +Finally, you hash this string using the algorithm identified by the header, and add that to the end (separated by another period). + +``` +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbmRleCI6IjEiLCJlbWFpbCI6ImtyZ2FtZXN0dWRpb3NAZ21haWwuY29tIiwidXNlcm5hbWUiOiJSYXRzdGFpbDkxIiwidHlwZSI6ImFscGhhIiwiYWRtaW4iOnRydWUsIm1vZCI6dHJ1ZSwiaWF0IjoxNzAzMzQzNzc5LCJleHAiOjE3MDMzNDQzNzksImlzcyI6ImF1dGgifQ.7sIFMccspLmMNyl5FO2MBIHjmlm8rMd_8upnSnLri7I +``` + +The beauty of this is that you can decode it easily for the payload information (such as username, account privilege, and any other information stored within), and you can also ensure that it hasn't been altered by a malicious party, thanks to the hashed information - if the hash doesn't match, then there's a problem. + +Also, there's a concept called public key cryptography that I am not currently using, but it's a bit too advanced to cover in this page though. just know that it's just as valid for JWTs as what I'm currently using. + +## Access and Refresh Token Pairs + +So, now that we have a token that proves our identity, we need to keep it super secure to ensure that nobody can steal it. The problem with this is that no system is ever 100% secure. + +To resolve this, I've added an "exp" field to the payload, defining the number of seconds since Jan 1st 1970 (also called unix time). This lets me simply reject any tokens that are too old. By default, the auth-server gives tokens about 10 minutes of validity. + +Again, you've probably noticed a problem - if tokens are only valid for 10 minutes, then the user will always be logged out automatically when it expires. I wish i had come up with some brilliant solution for this, but I'm just using the same technique everyone else does; I split the token into two tokens: the access token and the refresh token. + +The basics concept is simple - the access token is used for general communication with the website, and when it expires, you ping the auth-server again with the refresh token to get another token pair. This way, the access token which gets shared around can only be stolen for up to 10 minutes at most. + +This does mean that if you steal the refresh token (which doesn't expire at all), you'll be able to refresh token pairs continuously. Thankfully, the auth-server actually checks the database for existing refresh tokens before issuing new pairs. If the player simply sends a valid logout request, then that refresh token is deleted and refreshing the access token is impossible. + +## Implementation + +After much, much tinkering and experimenting, I've found the most straight forward way of handling these token pairs is by providing the access token directly (so the game, etc. can use the info inside), and storing the refresh token in a HttpOnly cookie (which is inaccessible to the webpage). + +This is a little more complex than I wanted for an intermediate difficulty tool - so lets go through it together to understand what's happening. + +``` +//polyfills +import 'regenerator-runtime/runtime'; + +import React from 'react'; +import ReactDOM from 'react-dom/client'; + +import App from './pages/app'; +import TokenProvider from './pages/utilities/token-provider'; + +ReactDOM + .createRoot(document.getElementById('root')) + .render( + + + + ) +; +``` + +React has a concept called a "Context", which is a way to provide global utilities or information throughout an application without requiring that the user pass down props from parent to child. Contexts have "Providers" which are what actually provide the information to the render tree. Just above you can see the TokenProvider wrapping the MERN-template's client application component. + +``` +import React, { useState, useEffect, createContext } from 'react'; +import decode from 'jwt-decode'; + +export const TokenContext = createContext(); + +const TokenProvider = props => { + ... + + return ( + + {props.children} + + ) +}; + +export default TokenProvider; +``` + +Here's the simplest breakdown of the token Provider. You can see the file creates and exports a context, then wraps the TokenProvider's children with the context's provider member. I've omitted stuff from the body and from the argument "value". + +``` +{ + accessToken, + setAccessToken, + tokenFetch, + tokenCallback, + getPayload: () => decode(accessToken) +} +``` + +Here are the arguments to the provider's "value" argument that I omitted above. The first two are actually easy - they're just the result of React's `useState` - this is the actual accessToken used throughout the program. + +The last argument is getPayload, which simply wraps a call to decode the accessToken - literally just a way to get the contents of the token quickly. + +``` +import React, { useContext, useRef } from 'react'; +import { Redirect } from 'react-router-dom'; + +import { TokenContext } from '../utilities/token-provider'; + +const LogIn = props => { + //context + const authTokens = useContext(TokenContext); + + //misplaced? + if (authTokens.accessToken) { + return ; + } + ... +``` + +Here's snippet from login.jsx, showing the usage of the contexts. By using the react hook useContext, and passing in TokenContext you gain access to the "value" argument that was passed to the created context's provider above. + +## tokenFetch + +There's one member of the context value that I skipped over earlier - tokenFetch. This is a wrapper function around the fetch() API. It's purpose is to refresh the token pair when the access token is expired - and do so invisibly to the user. + +It should be noted that tokenFetch is only used for functions where it is appropriate - namely where the user is already logged in. Other times, just using vanilla fetch is enough. + +``` +//wrap the default fetch function +const tokenFetch = async (url, options) => { + //use this? + let bearer = accessToken; + + //if expired (10 minutes, normally) + const expired = new Date(decode(accessToken).exp * 600) < Date.now(); + + if (expired) { + ... + } + + //finally, delegate to fetch + return fetch(url, { + ...options, + headers: { + ...options.headers, + 'Authorization': `Bearer ${bearer}` + } + }); +}; +``` + +Here, lets look at what happens when the token is NOT expired. Basically, the accessToken's value is stored in "bearer", the expiry boolean is checked, and finally fetch is called, with the Authorization header injected (bearer is an argument for Authorization). + +Straight forward; this is what should normally happen. + +``` +//ping the auth server for a new token +const response = await fetch(`${process.env.AUTH_URI}/token`, { + method: 'POST', + credentials: 'include' +}); + +//any errors, throw them +if (!response.ok) { + if (response.status == 403) { + forceLogout(); + } + throw `${response.status}: ${await response.text()}`; +} + +//save the new auth stuff (setting bearer as well) +const newAuth = await response.json(); + +setAccessToken(newAuth.accessToken); +bearer = newAuth.accessToken; +``` + +However, if the token IS expired, this happens first - a POST request to the auth-server carrying the refresh token (specified by the credentials flag). Then, if that response went OK, it retrieves the new accessToken, sets the bearer, and finally, it proceeds with tokenFetch's original task. + +I should also mention that there's a bugfix inside the expired block - if the user is trying to log out, (by pinging ${process.env.AUTH_URI}/logout), then the process intercepts this and sends it's own logout message. This only happens when the user is trying to log out with an expired authToken. + +# Conclusion + +The JWTs are powerful, because they contain all of the authority that the player needs to play the game. They also carry information such as the admin status, so administrators can access the admin panel. + +The auth-server repository has a few tools for sending REST requests - you can invoke them directly from VSCode using [this extension](https://marketplace.visualstudio.com/items?itemName=humao.rest-client). \ No newline at end of file diff --git a/configuration.md b/configuration.md index 51b17ca..02efc44 100644 --- a/configuration.md +++ b/configuration.md @@ -1,6 +1,6 @@ # Configuration -There are a set of tools for configuration included in the core project and it's microservices; these do things like outputting docker scripts. Other configuration scripts, such as CSS generators, are possible for the future. +There are a set of tools for configuration included in the core project and it's services; these do things like outputting docker and SQL scripts. ## configure-script.js @@ -12,7 +12,7 @@ Each [microservice](microservices) has it's own configure-script.js file; but th This file, when generated by the core project, will pull the microservices from docker hub (along with traefik and mariadb) and will put everything together. This file is ignored by git. -When it's generated by a microservice instead, it sets up that microservice independently. +When it's generated by a service instead, it sets up that service independently. ### Dockerfile @@ -20,4 +20,5 @@ This file covers ONLY the repo it exists in. It is committed to the repo, but is ### startup.sql -This file generates a script for mariadb's first run that creates the appropriate databases, and matching users with the specified passwords. This file is ignored by git. \ No newline at end of file +This file generates a script for mariadb's first run that creates the appropriate databases. This file is ignored by git. + diff --git a/learning-the-code.md b/learning-the-code.md index 05ae8e8..3e1487e 100644 --- a/learning-the-code.md +++ b/learning-the-code.md @@ -15,17 +15,7 @@ Next, you can have a quick look at the express server under `server/`. I've trie # Core Client - app.jsx -Under `client/pages/` you'll find `app.jsx`, which is the main switchboard for the template's different webpages. By default, it has enough pages hooked up to serve a simple website that you can interact with. Each route uses `LazyRoute`, which is used in place of `Route` to enable code-splitting (yet another trick to reduce bandwidth). - -The routes have two different ways of loading a page: - -```jsx - import('./accounts/login')} /> - - () => } /> -``` - -The former loads a react-driven page, while the latter loads a Markdown driven page (these pages have HTML embedding enabled). +Under `client/pages/` you'll find `app.jsx`, which is the main switchboard for the template's different pages. By default, it has enough pages hooked up to serve a simple website that you can interact with. Each route uses React's "lazy loading" ability, which is used to enable code-splitting (yet another trick to reduce bandwidth). Finally, at the bottom of the switch there is a ternary expression which optionally renders the `PopupChat` component if the user is logged in (i.e. the browser has an accessToken). diff --git a/legal.md b/legal.md index a968ee4..a69b280 100644 --- a/legal.md +++ b/legal.md @@ -10,13 +10,13 @@ The MERN-template and all of it's microservices are released under the zlib lice ## Privacy Policy And Credits -The website's footer links to the privacy policy and credits pages. These can be found under `client/markdown/` as markdown files; much easier to manage than handling React pages directly. +The website's footer links to the privacy policy and credits pages. These can be found under `client/pages/static/` as react pages. -Please remember to include a privacy policy with your website, and credit everyone involved in your website's creation. Tools for doing this may be coming soon. +Please remember to include a privacy policy with your website, and credit everyone involved in your website's creation. ## Spam And Agreeing to Being Contacted -One of the features built into this project is the contact flag - it's a way for the user to signal to the developer that they are OK with being contacted in the future with promotional material. This flag is saved in the `accounts` table in the `auth` database, and can be freely changed by users via their account pages. Removing this feature means you won't be able to contact *anyone*. +One of the features built into the auth service is the contact flag - it's a way for the user to signal to the developer that they are OK with being contacted in the future with promotional material. This flag is saved in the `accounts` table in the `auth` database, and can be freely changed by users via their account pages. Removing this feature means you won't be able to contact *anyone*. If you're in America, please refer to the [CAN SPAM act of 2003](https://en.wikipedia.org/wiki/CAN-SPAM_Act_of_2003). diff --git a/microservices.md b/microservices.md index 55a9a21..bb87d15 100644 --- a/microservices.md +++ b/microservices.md @@ -2,23 +2,23 @@ This project uses the [microservice architecture](https://en.wikipedia.org/wiki/Microservices). -Currently, there are three officially supported microservices: +Currently, there are three officially supported services: * News Server: https://github.com/krgamestudios/news-server * Auth Server: https://github.com/krgamestudios/auth-server * Chat Server: https://github.com/krgamestudios/chat-server -See [Configuration](configuration) for how to actually pull docker images of these. +See [this page](configuration) for how to actually pull docker images of these. ## News-Server -The news server is the first and most stable element of this system. It provides a stream of news articles, as well as features to publish, edit and delete them. It relies on the auth-server's tokens for authentication. +The news server is the first and most stable element of this system. It provides a stream of news articles, as well as features to publish, edit and delete them. It relies on the auth-server's JWTs for publishing or editing. ## Auth-Server -The auth-server is probably the only required microservice. It provides the signup, login and account systems. It does this via JSON web tokens (JWTs), which are needed for all authorized features of the other microservices. +The auth-server is probably the only required microservice. It provides the signup, login and account systems. It does this via JSON Web Tokens (JWTs), which are needed for all authorized features of the other services. ## Chat-Server -The chat server provides game-wide room-based chat between users. It requires a valid token from the auth-server, otherwise it works pretty simply - it records the chat between all rooms. +The chat server provides game-wide room-based chat between users. It requires a valid JWT from the auth-server, otherwise it works pretty simply - it records the chat between all rooms, and returns them when needed. diff --git a/pbbg.md b/pbbg.md index f20d3bc..c03016f 100644 --- a/pbbg.md +++ b/pbbg.md @@ -1,6 +1,6 @@ # Persistent Browser Based Games -A persistent browser based game (or PBBG) is a type of web-game which occurs entirely through the web browser. The MERN-template is designed to support this type of game specifically, but is not restricted to it. +A persistent browser based game (or PBBG) is a type of web-game which occurs entirely through the web browser. The MERN-template was initially designed to support this type of game specifically, but is not restricted to it. Some examples of PBBGs include: @@ -8,4 +8,5 @@ Some examples of PBBGs include: * [Imperial Conflict](https://imperialconflict.com/) * [Between Worlds](https://betweenworlds.net/) -For a large list of existing PBBGs, please visit [pbbg.com](https://pbbg.com/). \ No newline at end of file +For a large list of existing PBBGs, please visit [pbbg.com](https://pbbg.com/). + diff --git a/structure-folders.md b/structure-folders.md index b8e005b..e4139c0 100644 --- a/structure-folders.md +++ b/structure-folders.md @@ -5,11 +5,11 @@ Each repository in this project has a specific folder structure that I find to b ``` root/ - client/ - - markdown/ - pages/ - - account/ + - accounts/ - administration/ - panels/ + - static/ - utilities/ - app.jsx - dashboard.jsx @@ -26,12 +26,14 @@ root/ - server.js - tools/ - create_database.sql + - test/ - .envdev - .gitignore - - configure-script.js - LICENSE - - package.json - README.md + - configure-script.js + - package.json + - webpack.config.js ``` These are the most common folders and files between the core project and the microservices. Some, like `client/` are only present in the core repo, while others not shown, are only present in their specific `server/` directories (such as `server/auth/` in the auth-server). @@ -40,8 +42,6 @@ These are the most common folders and files between the core project and the mic This folder structure is only in the core repo, and provides the client-facing React code. Most of the components are under `client/pages/`. -`client/markdown/` contains markdown files that are rendered as entire pages on their own, while `client/styles/` contains the CSS files for specific or entire areas of the project. - ## Common The `common/` directory is used for common files shared between client and server directories. @@ -52,7 +52,7 @@ This directory is used by all repos, but the core repo has only a placeholder se ## Test -`test/` contains tools for testing the projects. This will eventually house fully automated testing suites. +`test/` contains tools for testing the services. ## Tools @@ -60,4 +60,4 @@ This directory is used by all repos, but the core repo has only a placeholder se ## Root -There are also a number of files in the root directory listed here, which are fairly common between the projects, and are described by their names. \ No newline at end of file +There are also a number of files in the root directory, which are fairly common between services. These cover things from legalities, to basic documentation. \ No newline at end of file diff --git a/styling.md b/styling.md index ec1e841..f270fb2 100644 --- a/styling.md +++ b/styling.md @@ -32,4 +32,5 @@ const HomePage = props => { }; export default HomePage; -``` \ No newline at end of file +``` + diff --git a/troubleshooting.md b/troubleshooting.md index 628c38f..869006b 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -4,7 +4,7 @@ Sometimes, not everything goes according to plan. I'm writing up as many issues ## Deploying the project didn't work? -Try again. There are timing issues between the different containers that I still need to sort out. If it still doesn't work after 3-ish attempts, keep reading. +Try again. There are occasionally timing issues between the different containers. If it still doesn't work after 3-ish attempts, keep reading. ## Sequelize throws an error that a certain field is missing? @@ -12,7 +12,7 @@ If you just upgraded the template, try checking if any changes to the sequelize ## I accidentally removed all admin privileges, and now I can't login! -When there are 0 accounts with administrator privileges, the auth-server will try to create the default admin account (if details for it have been specified) and when it fails, it crashes. You'll have to mess with the system's database to fix it. +When there are 0 accounts with administrator privileges, the auth-server will try to create the default admin account (if details for it have been specified) and when it fails, it crashes. You'll have to mess with auth's database to fix it. Run the following command on the same machine as the database container: @@ -51,6 +51,6 @@ Google has recently removed the ability to use plaintext passwords with less sec ## None of These Answers My Questions! -That's OK! Please contact me directly at [krgamestudios@gmail.com](mailto:krgamestudios@gmail.com) and I'll try my best to help you out. You can also contact me over [Discord as Ratstail91#6600](https://discord.gg/FQmz8TN). +That's OK! Please contact me directly at [krgamestudios@gmail.com](mailto:krgamestudios@gmail.com) and I'll try my best to help you out. Please don't keep quiet about your issues - letting me know about them will help me improve the whole project! \ No newline at end of file diff --git a/tutorial-setup.md b/tutorial-setup.md index 146569a..6412b65 100644 --- a/tutorial-setup.md +++ b/tutorial-setup.md @@ -4,11 +4,11 @@ Hello! This is the tutorial for setting up a vanilla MERN-template server. If yo https://github.com/krgamestudios/MERN-template -Before we begin, you should know that the MERN-template uses a [microservice architecture](microservices). What this means in practice is that "[Setting Up Deployment](#setting-up-deployment)" will pull a fresh copy of all of the microservices from docker hub, and "[Setting Up Development](#setting-up-development)" will connect to publicly available dev servers that I'm currently providing. You'll need to follow "[Setting Up Locally](#setting-up-locally)" for everything to work locally. +Before we begin, you should know that the MERN-template uses a [microservice architecture](microservices). What this means in practice is that "[Setting Up Deployment](#setting-up-deployment)" will pull a fresh copy of all of the microservices from my docker hub, and "[Setting Up Development](#setting-up-development)" will connect to publicly available shared dev services that I'm currently providing. You'll need to follow "[Setting Up Locally](#setting-up-locally)" for everything to work locally. ## Vanilla? -This just means "unedited" or "unmodified". This project is designed to be highly customizable for the average intermediate developer, so they can create their own [PBBG](pbbg). +This just means "unedited" or "unmodified". This project is designed to be highly customizable for the average intermediate developer, so they can create their own [PBBG](pbbg), or other kind of website. ## Requirements @@ -19,17 +19,19 @@ Familiarity with at least some of these technologies is a great advantage when u * MariaDB (and Sequelize) * Docker (and docker-compose) -You'll also need an email address (if you use google, you'll need to enable "[less secure apps](https://support.google.com/accounts/answer/6010255?hl=en#zippy=%2Cif-less-secure-app-access-is-off-for-your-account%2Cif-less-secure-app-access-is-on-for-your-account)" so external apps can access it). I've only used this site with google so far, but feel free to experiment with other mail hosts. What's important is that you have their SMTP's web address. +You'll also need an email address (if you use Google, which is recommended, you'll need to enable "[less secure apps](https://support.google.com/accounts/answer/6010255?hl=en#zippy=%2Cif-less-secure-app-access-is-off-for-your-account%2Cif-less-secure-app-access-is-on-for-your-account)" so external apps can access it). I've only used this site with Google so far, but feel free to experiment with other mail hosts. What's important is that you have their SMTP's web address. -Update: Google has recently removed the ability to use plaintext passwords with less secure apps enabled - read the link above for more information on how to generate an "app password". +**Update**: Google has recently removed the ability to use plaintext passwords with less secure apps enabled - read the link above for more information on how to generate an "app password". -For deployment you'll also need a server (such as those provided by [linode](https://www.linode.com/)), and a domain name pointing at that server. Add some "A records" to your domain's DNS records such as "news", "auth" and "chat" which point to the same server as the main record. You'll need to add a TXT record to your DNS as well, for the domain "auth": +For deployment you'll also need a server (such as those provided by [Digital Ocean](https://www.digitalocean.com/)), and a domain name pointing at that server (domain names can be obtained from registrars such as [Squarespace](https://domains.squarespace.com/)). Add some "A records" to your domain's DNS records such as "news", "auth" and "chat" which point to the same server as the main record. You'll need to add a TXT record to your DNS as well, for the domain "auth": ``` "v=spf1 a ~all" ``` -This is primarily so the auth-server can send emails to validate user email addresses (if you use linode as I suggested, you'll have to open a support ticket to allow your user account to send emails via the email ports. This is linode's restriction against spammers). +This is primarily so the auth-server can send emails to validate user email addresses. + +**Update**: Due to various changes by my registrar and server hosts, exactly how you obtain a server and a domain name may be different now from how I first did it - some testing is still needed. Depending on your jurisdiction, you'll also need a physical mailing address (blame America's [CAN-SPAM](https://en.wikipedia.org/wiki/CAN-SPAM_Act_of_2003) act). @@ -103,7 +105,7 @@ Default Admin User: Default Admin Pass: ``` -Be aware that "Email Password" is your plaintext email password, which will be stored in docker-compose.yml. It'll be safe, but generally a good idea not to use your main account for this. +Be aware that "Email Password" is your plaintext email password, which will be stored in docker-compose.yml. It'll be safe, but generally a good idea not to use your main account password for this. "Default Admin Pass" will only appear if "Default Admin User" is set, and the generated login email will be printed to the screen (it'll use the web address for the auth-server such as "admin@auth.example.com"). This is the email address you use to log into the deployed app at first; the auth-server tries to generate this account every time it starts with 0 existing administrator accounts. @@ -117,13 +119,11 @@ You might need sudo, and you could add `-d` to detach the process from the conso ## Setting Up Development -Warning: Due to a HTTPS bug, this setup mode does not currently work. See [this issue](https://github.com/krgamestudios/MERN-template/issues/38) for details. - For development, you'll need Nodejs and MariaDB installed and working on your machine. Remember to run `npm install` in the git repo after cloning to get all of the libraries. First, run `tools/create_database.sql` on your mariaDB instance - this will create a database called `template` and a user called `template`@`%` with the password `pikachu`. -Next, copy `.envdev` into a new file called `.env` (`SECRET_ACCESS` should have the value `access`, this is the key for the dev-servers that you're about to connect to). +Next, copy `.envdev` into a new file called `.env` (`SECRET_ACCESS` should have the value `access`, this is the key for the dev-services that you're about to connect to). Finally, it's time to run `npm run dev` in the console. This will begin the server in dev mode - it'll use the `concurrently` library to run both client and server in the same window, so you don't need two monitor terminals. If all goes well, the server should start pretty quickly, though the client will take a moment to compile. @@ -133,13 +133,13 @@ At this stage, your brand new website will call out to the `dev-news` server for ## Setting Up Locally -To set up the microservices locally, you'll first need to download them (probably via git): +To set up the microservices locally, you'll first need to download them (via git): -* Auth Server: https://github.com/krgamestudios/auth-server * News Server: https://github.com/krgamestudios/news-server +* Auth Server: https://github.com/krgamestudios/auth-server * Chat Server: https://github.com/krgamestudios/chat-server -Each one has it's own `configure-script.js` for independent deployment, but in this case copy the `.envdev` file to a new file called `.env` and fill out each field, ensuring that the line `SECRET_ACCESS` matches between every program (including the MERN-template). +Each one has it's own `configure-script.js` for independent deployment, but in this case copy the `.envdev` file to a new file called `.env` and fill out each field, ensuring that the line `SECRET_ACCESS` matches between every service (including in MERN-template). Finally, open a terminal for each project, point it to the project's directory and run `npm run dev` (or `npm run local` for the MERN-template). Once each one reports that they're listening on a specific port (or when the MERN-template says it's finished compiling), then you can visit the local servers at `http://localhost:3001/`.