Webapp
web application boilerplate (React, Redux, React-router, i18n, isomorphic, etc)
Install / Use
/learn @catamphetamine/WebappREADME
WebApp is an example of a generic web application with React and Redux.
Features
- Babel 6
- React
- React-router
- Redux
- Webpack
- Isomorphic (universal) rendering
- Hot reload (aka Hot Module Replacement) for React components, Redux reducers, Redux action creators, translated messages
- Internationalization with React-intl
- User authentication (JSON Web Token) & authorization (roles)
- REST API
- SQL ORM (PostgreSQL + Knex)
- MongoDB
- Microservice architecture
- Responsive web design
- Works both with Javascript enabled and disabled (suitable for DarkNet purposes)
- Koa
- Bunyan logging (log file rotation is built-in)
- Correctly handles Http Cookies on the server-side
- To be done: GraphQL + Relay
- To be done: native Node.js clustering
- // maybe: Protection against Cross Site Request Forgery attacks
Running
Prerequisites:
Prerequisites for production:
Installing:
npm run install-recursive(runsnpm installfor all subdirectories recursively)cd backendnpm run postgresql-knex-initnano database/sql/knexfile.js(editdatabase,usernameandpassword)npm run postgresql-migratecd ..
Running in development mode:
npm run dev- wait for it to finish the build (green stats will appear in the terminal, and it will say "Webpage server is listening at http://localhost:3004")
- go to
http://127.0.0.1:3000
Running in production mode:
npm run production- wait a bit for Webpack to finish the build (green stats will appear in the terminal, plus some
node.jsserver running commands) - go to
http://127.0.0.1:3000
Configuration
One can configure this application through creation of configuration.js file in the root folder (use configuration.defaults.js file as a reference).
All the options set in that file will overwrite the corresponding options set in configuration.defaults.js file.
Running (in development)
npm run dev
After it finishes loading go to http://127.0.0.1:3000
(the web page will refresh automatically when you save your changes)
localhost vs 127.0.0.1
On my Windows machine in Google Chrome I get very slow Ajax requests.
That's a strange bug related to Windows and Google Chrome discussed on StackOverflow
To workaround this bug I'm using 127.0.0.1 instead of localhost in the web browser.
Architecture
The application consists of the following microservices
web-serveris the gateway (serves static files and proxies to all the other microservices)page-serverrenders web pages on the server side (using react-isomorphic-render)authentication-servicehandles user authentication (sign in, sign out, register) and auditing (keeps a list of user sessions and traces latest activity time)password-serviceperforms password hashing and checking (these operations are lengthy and CPU-intensive)user-serviceprovides REST Api for users (getting users, creating users, updating users)image-serverresizes uploaded images using ImageMagick and serves themlog-serviceaggregates logs from all the other servicesemail-servicesends emails
Redis
The application uses Redis for storing user sessions (things like online status).
After installing Redis edit the configuration.js file accordingly
redis:
{
host : 'localhost',
port : 6379,
// password : '...' // is optional
}
To secure Redis from outside intrusion set up your operating system firewall accordingly. Also a password can be set and tunneling through an SSL proxy can be set up between the microservices. Also Redis should be run as an unprivileged redis user.
Consul
Consul is a service discovery software used in conjunction with Nomad and Docker to run high-availability applications in production.
brew install consul
Nomad
Nomad is a Docker container deployment software used in conjunction with Consul and Docker to run high-availability applications in production.
brew install nomad
Docker
Docker is a containerization software used to easily run applications in production.
Download it from the Docker website
Security
The application should be run as an unprivileged user.
When switching to TLS will be made all cookies should be recreated ({ secure: true } option will be set on them automatically upon Https detection when they are recreated).
Redis
This application can run in demo mode without Redis being installed.
If you want this application make use of Redis then you should install it first.
For Windows: https://github.com/MSOpenTech/redis/releases
For OS X:
brew install redis
# To have launchd start redis at login:
ln -sfv /usr/local/opt/redis/*.plist ~/Library/LaunchAgents
# Then to load redis now:
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.redis.plist
and configure it in your configuration.js file
redis:
{
host : 'localhost',
port : 6379,
password : ... // is optional
}
<!-- MongoDB
=======
This application can run in demo mode without MongoDB being installed.
If you want this application make use of MongoDB then you should install it first.
For windows: https://www.mongodb.org/downloads
For OS X:
```
brew install mongodb
# To have launchd start mongodb at login:
ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents
# Then to load mongodb now:
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
```
Then configure it in your `configuration.js` file
```javascript
mongodb:
{
host : 'localhost',
port : 27017,
database : ...,
user : ...,
password : ...
}
```
Setting up a freshly installed MongoDB
```sh
mongo --port 27017
use admin
db.createUser({
user: "administrator",
pwd: "[type-your-administrator-password-here]",
roles: [ { role: "userAdminAnyDatabase", db: "admin" }, { role: "dbAdminAnyDatabase", db: "admin" }, { role: "readWriteAnyDatabase", db: "admin" } ]
})
exit
# set "security.authorization" to "enabled" in your mongod.conf and restart MongoDB.
# (on OS X mongod.conf path is /usr/local/etc/mongod.conf and the restart command is `launchctl unload …`)
```
```sh
mongo --port 27017 -u administrator -p [type-your-administrator-password-here] --authenticationDatabase admin
use type-your-new-database-name-here
db.createUser({
user: "type-your-user-name-here",
pwd: "type-your-user-password-here",
roles:
[
{ role: "readWrite", db: "type-your-new-database-name-here" }
]
})
exit
```
One may also use [Robomongo](https://robomongo.org/download) as a GUI for MongoDB.
To initialize MongoDB database
```sh
npm run mongodb-migrate
```
To rollback the latest MongoDB migration
```sh
npm run mongodb-rollback
```
Migrations are stored in the `database/sql/migrations` folder.
When switching to MongoDB make sure you delete the `authentication` cookie contaning the user id or else an exception will be thrown saying "Argument passed in must be a single String of 12 bytes or a string of 24 hex characters". Similarly, when switching away from MongoDB back to the dummy RAM storage make sure you clear the `authentication` cookie or else "User not found" error will be thrown on page refresh. -->
PostgreSQL
This application can run in demo mode without PostgreSQL being installed.
If you want this application make use of PostgreSQL then you should first install it.
For OS X:
brew install postgresql
# To have launchd start postgresql at login:
ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents
# Then to load postgresql now:
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
# Fixes "psql: FATAL: role "postgres" does not exist"
createuser --superuser postgres
# Then you may also want to install PSequel as a GUI
# http://psequel.com/
(hypothetically MySQL and SQLite3 will also do but I haven't checked that since PostgreSQL is the most advanced open source SQL database nowadays)
To change the default PostgreSQL superuser password
sudo -u postgres psql
# or: psql postgres (for OS X)
postgres=# \password postgres
\q
Then create a new user in PostgreSQL and a new database. For example, in OS X or Linux terminal, using these commands
createuser --username=postgres --interactive USERNAME
n
n
n
createdb --username=postgres --encoding=utf8 --owner=USERNAME DATABASE_NAME --template=template0
Also install PostGIS for geospacial data support
brew install postgis
# install the database extension (requires superuser privileges)
psql --username=postgres --dbname=DATABASE_NAME
CREATE EXTENSION postgis;
\q
Then create your database/sql/knexfile.js file
cd backend
npm run postgresql-knex-init
Then configure your database/sql/knexfile.js file. An example of how it might look
var path = require('path')
module.exports = {
client: 'postgresql',
connection: {
database: 'webapp',
user: 'webapp',
password: 'webapp'
},
pool: {
min: 2,
ma
