https://forwardemail.net (made with Lad)
Project Spotlight: Forward Email @https://lad.sh
Live Framework Demo:Table of Contents
- Features
- Get Started
- Architecture
- Principles
- Related
- Contributing
- Contributors
- Trademark Notice
- License
Features
Lad boasts dozens of features and is extremely configurable.
Microservices
These microservices are preconfigured for security, performance, and graceful reloading.
Front-end
- Browser linting using eslint-plugin-compat and browserslist (see .browserslistrc for the default config)
- Pug template engine (you can easily use Moon, Vue, React, or Angular, though typically you aren't going to need it)
- Gulp (latest version 4.x)
- Sass
- PostCSS (with font-magician, import-url, font-grabber, base64, and cssnext pre-configured)
- Bootstrap
- Font Awesome
- SpinKit
- SweetAlert2
- Dense
- Waypoints
- LiveReload
- β¦
Back-end
- Redis, sessions, and flash toast and modal SweetAlert2 messages (uses ioredis which has support for Cluster, Sentinel, and more)
- Koa-based webapp and API servers (uses HTTP/2 for production!)
- Pagination built-in (using ctx-paginate)
- RESTful API with BasicAuth and versioning
- Automated job scheduler with cron and human-readable syntax (backed by Mongoose and Bree)
- Passport-based authentication and group-based (Unix-like) permissioning
- Stripe-inspired error handling
- Mongoose and MongoDB with common database plugins
- Email template engine with Nodemailer and local rendering
- Proxy eliminates need for Nginx reverse-proxy or Apache virtual hosts
- Multilingual through built-in i18n translation support (see configuration)
- Automatic phrase translation with Google Translate
- Sitemap generator for simple SEO
- β¦
Translation
Finally a framework that solves i18n everywhere; complete with automatic translation.
- Translation constants built-in so you don't repeat yourself
- Webapp error messages and templates are translated
- Emails are translated
- API responses are translated
- Database errors are translated
- Authentication errors are translated
- β¦
Email Engine
Our beautiful email engine uses email-templates (which is also made by the creator of Lad)!
- Test your emails locally with automatic browser-rendering on the fly
- Automatically inlines CSS for cross-browser and cross-platform email client support
- Use Bootstrap in your email template designs
- Reuse your existing CSS and webapp styling
- Use any template engine (defaults to Pug)
- Render custom fonts in emails with code
- Add icons with Font Awesome with code
- Automatically avoid email client caching
- Include any image you want and it will be properly rendered
- Rids the need for awkward embedded image CID attachments
- β¦
Error Handling
We've spent a lot of time designing a beautiful error handler.
- Supports
text/html
,application/json
, andtext
response types - User-friendly responses
- HTML error lists
- β¦
See koa-better-error-handler for a complete reference.
Performance
- Compression and zero-bloat approach
- Stream-based file uploading
- Graceful reloading, shutdown, and reconnection handling
- Manifest asset revisioning
- Amazon S3 and CloudFront ready
- β¦
Security
- Database security plugins and helpers
- Automated tests and code coverage
- CORS, SameSite set to "lax" (an alternative to CSRF), CSRF (since not all browsers support SameSite yet) XSS, and rate limited protection
- Dotenv support for environment-based configurations
- App, user, and request-based logging
- SSL-ready (see instructions below)
- β¦
Get Started
We strictly support Mac and Ubuntu-based operating systems (we do not support Windows).
Requirements
Please ensure your operating system has the following software installed:
-
Git - see GitHub's tutorial for installation
-
MongoDB (v3.x+):
-
Mac (via brew):
brew tap mongodb/brew && brew install mongodb-community && brew services start mongodb-community
. -
Ubuntu:
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6 echo "deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list sudo apt-get update sudo apt-get -y install mongodb-org
-
-
Redis (v4.x+):
-
Mac (via brew):
brew install redis && brew services start redis
-
Ubuntu:
sudo add-apt-repository -y ppa:chris-lea/redis-server sudo apt-get update sudo apt-get -y install redis-server
-
Install
npm:
npm install -g lad
yarn:
yarn global add lad
Usage
Create a project
lad new-project
cd new-project
Development
To begin, try typing npm start
(or yarn start
) on command line. This will display to you all the scripts you can run.
The start
script (among many others) uses nps and nps-utils under the hood. This helps to keep scripts very developer-friendly, and rids the need to write in JSON syntax.
This script accepts a <task>
argument, whereas a task of all
will spawn, watch, and re-compile all of the microservices mentioned above.
Just open http://localhost:3000 for testing!
npm:
npm start all
yarn:
yarn start all
Debugging
-
DEBUG
- debug using debug output (widely adopted package in the community for debugging across all Node packages):DEBUG=* ...
-
NODE_DEBUG
- debug node internal modules:NODE_DEBUG=* ...
-
MONGOOSE_DEBUG
- debug Mongoose raw database operation output:MONGOOSE_DEBUG=true ...
-
TRANSPORT_DEBUG
- debug Nodemailer transport:TRANSPORT_DEBUG=true ...
-
REDIS_MONITOR
- debug Redis usingMONITOR
(uses @ladjs/redis and passestrue
for themonitor
argument):REDIS_MONITOR=true ...
-
REDIS_FRIENDLY_ERROR_STACK
- debug Redis with friendly error stack messages (see showFriendlyErrorStack option of ioredis)REDIS_FRIENDLY_ERROR_STACK=true ...
Production
We strongly recommend using SemaphoreCI, PM2, and Digital Ocean for production deployment.
-
We've provided you with a preconfigured ecosystem.json deployment file. You will need to modify this file with your server's IP, hostname, and other metadata if needed.
-
Make sure that your project's assets are built with
NODE_ENV=production
flag, e.g.NODE_ENV=production npm run build
(or with yarn asyarn build
);this creates abuild/rev-manifest.json
file per koa-manifest-rev. -
You can test this locally by installing PM2 globally with npm or yarn, and then running the following command:
NODE_ENV=production pm2 start
-
See the Continuous Integration and Code Coverage and Tutorials sections below for instructions on how to setup continuous integration, code coverage, and deployment.
-
If you specify an environment variable value for
AWS_CF_DOMAIN
andNODE_ENV=production
is set then your assets will need to be published to Amazon S3/Cloudfront. To do so runnpm start publish-assets
(or with yarn asyarn start publish-assets
). This command automatically setsNODE_ENV=production
for you as well viacross-env
.
Provisioning
See the ansible folder for our Ansible configuration and playbooks, which we use to provision servers with.
We recommend you to install yamllint and configure it in your editor while working with Ansible playbooks.
Also note that ansible-lint is a helpful linting tool you can use if you plan on making changes to playbooks. Note that our current playbooks have several existing lint errors.
First you must provision Ubuntu 18.04 LTS 64-bit server(s) using Digital Ocean, Linode, Vultr, or your host of choice. These newly provisioned server(s) should have your SSH key automatically added.
Follow the Deployment guide below for automatic provisioning and deployment instructions.
Deployment
-
Set up host configuration by copying the
hosts.yml
file template:cp ansible/playbooks/templates/hosts.yml hosts.yml
-
Edit this configuration and update the file with your newly created server aliases and IP addresses. You can add more than one host to each group if you are setting up load balancing. Refer to the Naming Convention documentation for our recommended approach to server alias naming. Note that this file is automatically ignored by git. If you have a private repository and would like to commit this, then remove
hosts.yml
from the root.gitignore
file.vim hosts.yml
-
Set up environment configuration by copying the
env
file template:cp ansible/playbooks/templates/env .env.production
-
Edit this configuration and reference the official Lad documentation for a list of all available environment variables (or see .env.defaults). You will need to open this file in your preferred editor and set the values for any fields containing
TODO
, whereby you replaceTODO
with the appropriate value. Preserve double quotes where they are already defined.vim .env.production
-
Generate pm2 ecosystem files using our automatic template generator. We created an ansible-playbook.js which loads the
.env.production
environment variables rendered with @ladjs/env intoprocess.env
, which then gets used in the playbooks. This is a superior, simple, and the only known dotenv approach we know of in Ansible. Newly createdecosystem-api.json
,ecosystem-bree.json
,ecosystem-web.json
files will now be created for you in the root of the repository. If you ever more add or change IP addresses, you can simply re-run this command.node ansible-playbook ansible/playbooks/ecosystem.yml -l 'localhost'
-
Set up the web and API server(s) (see patterns and ansible-playbook flags docs if you need help). If you completely (or partially) run this playbook (or any others below), then the second time you try to run it may not succeed. This is because we prevent root user access through security hardening. To workaround this, run the same command but without
-e 'ansible_user=root'
appended as it will default to thedevops
user created.node ansible-playbook ansible/playbooks/http.yml -e 'ansible_user=root' -l 'http'
-
Set up the Bree server(s):
node ansible-playbook ansible/playbooks/bree.yml -e 'ansible_user=root' -l 'bree'
-
Set up the Redis server:
node ansible-playbook ansible/playbooks/redis.yml -e 'ansible_user=root' -l 'redis'
-
Set up the Mongo server:
node ansible-playbook ansible/playbooks/mongo.yml -e 'ansible_user=root' -l 'mongo'
-
Set up GitHub deployment keys for all the servers. Note that the
deployment-keys
directory is ignored from git, so if you have a private repository and wish to commit it, then removedeployment-keys
from the.gitignore
file.node ansible-playbook ansible/playbooks/deployment-keys.yml -l 'http:bree'
-
Go to your repository "Settings" page on GitHub, click on "Deploy keys", and then add a deployment key for each servers' deployment key copied to the
deployment-keys
directory. If you're on macOS, you can use thepbcopy
command to copy each file's contents to your clipboard. Use tab completion for speed, and replace the server names and paths with yours:cat deployment-keys/api-1-li-dal.forwardemail.net.pub | pbcopy # # NOTE: repeat the above command for all servers # and after running the command, it will copy # the key to your clipboard for you to paste as # a new deploy key (make sure to use read-only access) #
-
Set up PM2 deployment directories on all the servers:
pm2 deploy ecosystem-web.json production setup
pm2 deploy ecosystem-api.json production setup
pm2 deploy ecosystem-bree.json production setup
-
Create a SSL certificate at Namecheap (we recommend a 5 year wildcard certificate), set up the certificate, and download and extract the ZIP file with the certificate (emailed to you) to your computer. We do not recommend using tools like LetsEncrypt and
certbot
due to complexity when you have (or scale to) a cluster of servers set up behind load balancers. In other words, we've tried approaches likelsyncd
in combination withcrontab
forcertbot
renewals and automatic checking. Furthermore, using this exposes the server(s) to downtime as ports80
and443
may need to be shut down so thatcertbot
can use them for certificate generation. This is not a reliable approach, and simply renewing certificates once a year is vastly simpler and also makes using load balancers trivial. Instead you can use a provider like Namecheap to get a cheap SSL certificate, then run a few commands as we've documented below. This command will prompt you for an absolute file path to the certificates you downloaded. Renewed your certificate after 1 year? Simply follow this step again. Do not set a password on the certificate files. When using theopenssl
command (see Namecheap instructions), you need to use*.example.com
with an asterisk followed by a period if you are registering a wildcard certificate.ansible-playbook ansible/playbooks/certificates.yml
Important: If you renew or change certificates in the future, then after running the previous command, you will subsequently need to reload the processes as such:
# # NOTE: See the "Important" note above BEFORE running this command. # This command ONLY APPLIES for certificate renewals/changes. # pm2 deploy ecosystem-web.json production exec "pm2 reload web" pm2 deploy ecosystem-api.json production exec "pm2 reload api"
-
(Optional) Create a Google application credentials profile file and store it locally. You only need this if you want to support automatic translation. The following command will prompt you for the absolute file path (e.g.
/path/to/client-profile.json
). See the mandarin docs for more information.ansible-playbook ansible/playbooks/gapp-creds.yml -l 'http:bree'
-
Copy the
.env.production
file and create an AWS config file on the servers:node ansible-playbook ansible/playbooks/env.yml -l 'http:bree'
-
Run an initial deploy to all the servers:
pm2 deploy ecosystem-web.json production
pm2 deploy ecosystem-api.json production
pm2 deploy ecosystem-bree.json production
-
Save the process list on the servers so when if the server were to reboot, it will automatically boot back up the processes:
pm2 deploy ecosystem-web.json production exec "pm2 save"
pm2 deploy ecosystem-api.json production exec "pm2 save"
pm2 deploy ecosystem-bree.json production exec "pm2 save"
-
Test by visiting your web and API server in your browser (click "proceed to unsafe" site and bypass certificate warning).
-
Configure your DNS records for the web and API server hostnames and respective IP addresses.
-
Test by visiting your web and API server in your browser (in an incognito window). There should not be any certificate warnings (similar to the one that occurred in step 15).
-
(Optional) Remove the local
.env.production
file for security purposes. If you do this, then make sure you have a backup, or securely back up off the server in the future before destroying the server.rm .env.production
-
(Optional) Remove the local certificate files you downloaded locally and specified in step 11. If you do this, then make sure you have a backup, or securely back up off the server in the future before destroying the server.
-
Finished. If you need to deploy again, then push your changes to GitHub
master
branch and then follow step 14 again. We recommend you to read the Ansible getting started guide, as it provides you with insight into commands likeansible all -a "echo hello"
which can be run across all or specific servers.
Tests
We use ava and nyc for testing and code coverage.
npm:
npm test
yarn:
yarn test
Configuration
Environment Variables
We have made configuration of your Lad project easy through a dotenv configuration package called @ladjs/env, per Twelve-Factor.
We use the following three packages to manage configuration:
- dotenv-extended - allows us to craft a
.env
definition (otherwise known as a "schema") in a file named.env.schema
- mustache - allows us to use the Mustache templating language in our
.env
and.env.defaults
configuration files - dotenv-parse-variables - automatically parses variable types from
process.env
(e.g.FOO=4
will setprocess.env.FOO = 4
with aNumber
variable type instead of aString
)
Configuration is managed by the following, in order of priority:
- Contents of the file at
config/index.js
(reads inprocess.env
environment variables) - Contents of the files in directories under
config/environments/
(sets defaults per environment, e.g. you can passNODE_ENV=staging
and it will load the file atconfig/environments/staging.js
) - Environment variables used to override defaults or set required ones (e.g.
NODE_ENV=production
) - Environment configuration in
.env
- Environment configuration in
.env.defaults
Precedence is taken by the environment configuration files, environment variables, then the .env
file.
Basically dotenv won't set an environment variable if it already detects it was passed as an environment variable.
Take a look at the config folder contents and also at the defaults at .env.defaults.
NODE_ENV
- (options:development
,production
default:development
) - the node environment the app is running inPROXY_PORT
- (default:8080
) - proxy port used to proxy requests (see ladjs/proxy)HTTP_PROTOCOL
- (defaults:http
recommend:https
) - protocol used for http requestsHTTP_PORT
- (defaults:80
recommend:443
) - http port used for http requestsWEB_PROTOCOL
- (default:http
) - ladjs/web application protocolWEB_HOST
- (default:localhost
) - ladjs/web application hostWEB_PORT
- (default:3000
) - ladjs/web application portWEB_URL
- (default:{{WEB_PROTOCOL}}://{{WEB_HOST}}:{{WEB_PORT}}
) - web application absolute URIWEB_SSL_KEY_PATH
- ladjs/web file path to your SSL key fileWEB_SSL_CERT_PATH
- ladjs/web file path to your SSL certificate fileWEB_SSL_CA_PATH
- ladjs/web file path to your SSL certificate authority fileAPI_HOST
- (default:localhost
) - ladjs/api hostAPI_PORT
- (default:4000
) - ladjs/api portAPI_PROTOCOL
- (default:http
recommend:https
) - ladjs/api protocolAPI_URL
- (default:{{API_PROTOCOL}}://{{API_HOST}}:{{API_PORT}}
) - ladjs/api absolute URIAPI_SSL_KEY_PATH
- ladjs/api file path to your SSL key fileAPI_SSL_CERT_PATH
- ladjs/api file path to your SSL certificate fileAPI_SSL_CA_PATH
- ladjs/api file path to your SSL certificate authority fileAPI_RATELIMIT_WHITELIST
- ladjs/api ratelimiter whitelisted ips (see: koa-simple-ratelimit)APP_NAME
- (default:Lad
) - application name (see usage)APP_COLOR
- application color theme (see usage)TWITTER
- (default:@niftylettuce
) twitter handleSEND_EMAIL
- (default:false
) - whether to send email or preview (see outbound email configuration)TRANSPORT_DEBUG
- (default:false
) - email transport debug logging (see debugging)EMAIL_DEFAULT_FROM
- (default:[email protected]
) - default emailfrom
addressSHOW_STACK
- (default:true
) - whether or not to output a stack trace when logging (see cabinjs options)SHOW_META
- (default:true
) - whether or not to output metadata to logger methods (see cabinjs options)SUPPORT_REQUEST_MAX_LENGTH
- (default:500
) - support request max message size in charactersERROR_HANDLER_BASE_URL
- (default:{{WEB_URL}}
) error handling base url (see koa-better-error-handler)I18N_SYNC_FILES
- (default:true
) - sync locale information across all files (see ladjs/i18n options)I18N_AUTO_RELOAD
- (default:false
) - watch for changes in json files to reload locale on updates (see ladjs/i18n options)I18N_UPDATE_FILES
- (default:true
) - write new locale information to disk (see ladjs/i18n options)AUTH_LOCAL_ENABLED
- (default:true
) - enable passport local strategy (see ladjs/passport)AUTH_FACEBOOK_ENABLED
- (default:false
) - enable authenticating with Facebook using the OAuth 2.0 (see ladjs/passport)AUTH_TWITTER_ENABLED
- (default:false
) - enable authenticating with Twitter using the OAuth 1.0 (see ladjs/passport)AUTH_GOOGLE_ENABLED
- (default:false
) - enable authenticating with Google using OAuth 2.0 (see google auth)AUTH_GITHUB_ENABLED
- (default:false
) - enable authenticating with Github using OAuth 2.0 (see ladjs/passport)AUTH_LINKEDIN_ENABLED
- (default:false
) - enable authenticating with LinkedIn using OAuth 1.0 (see ladjs/passport)AUTH_INSTAGRAM_ENABLED
- (default:false
) - enable authenticating with Instagram using OAuth 2.0 (see ladjs/passport)AUTH_OTP_ENABLED
- (default:false
) - enable authenticating with OTP, a form of two-factor authentication (see ladjs/passport)AUTH_STRIPE_ENABLED
- (default: false) - enable authenticating with Stripe using OAuth 2.0 (see ladjs/passport)GOOGLE_CLIENT_ID
- google oauth2 client id (see google auth)GOOGLE_CLIENT_SECRET
- google oauth2 secret (see google auth)GOOGLE_CALLBACK_URL
- google oauth2 callback url (see google auth)GOOGLE_APPLICATION_CREDENTIALS
- path to google cloud platform credentials (see gcp credentials)GITHUB_CLIENT_ID
- github oauth client id (see ladjs/passport)GITHUB_CLIENT_SECRET
- github oauth secret (see ladjs/passport)GITHUB_CALLBACK_URL
- github oauth callback URL (see ladjs/passport)POSTMARK_API_TOKEN
- postmark api token (see outbound email configuration)CODECOV_TOKEN
- codecov api token (see continuous integration and code coverage)MONGO_USER
- mongodb usernameMONGO_PASS
- mongodb passwordMONGO_HOST
- (default:localhost
) - mongodb hostnameMONGO_PORT
- (default:27017
) - mongodb portMONGO_NAME
- (default:{{APP_NAME}}_{{NODE_ENV}}
) - mongodb nameMONGO_URI
- (default:mongodb://{{MONGO_HOST}}:{{MONGO_PORT}}/{{MONGO_NAME}}
) - mongodb connection URIWEB_MONGO_USER
- ladjs/web mongodb usernameWEB_MONGO_PASS
- ladjs/web mongodb passwordWEB_MONGO_HOST
- ladjs/web mongodb hostnameWEB_MONGO_NAME
- ladjs/web mongodb nameWEB_MONGO_PORT
- ladjs/web mongodb portWEB_MONGO_URI
- ladjs/web mongodb connection URIAPI_MONGO_USER
- ladjs/api mongodb usernameAPI_MONGO_PASS
- ladjs/api mongodb passwordAPI_MONGO_HOST
- ladjs/api mongodb hostnameAPI_MONGO_NAME
- ladjs/api mongodb nameAPI_MONGO_PORT
- ladjs/api mongodb portAPI_MONGO_URI
- ladjs/api mongodb connection URIBREE_MONGO_USER
- breejs/bree mongodb usernameBREE_MONGO_PASS
- breejs/bree mongodb passwordBREE_MONGO_HOST
- breejs/bree mongodb hostnameBREE_MONGO_NAME
- breejs/bree mongodb nameBREE_MONGO_PORT
- breejs/bree mongodb portBREE_MONGO_URI
- breejs/bree mongodb connection URIREDIS_PORT
- (default:6379
) - redis portREDIS_HOST
- (default:localhost
) - redis hostnameREDIS_PASSWORD
- redis passwordWEB_REDIS_PORT
- ladjs/web redis portWEB_REDIS_HOST
- ladjs/web redis hostnameWEB_REDIS_PASSWORD
- ladjs/web redis passwordAPI_REDIS_PORT
- ladjs/api redis portAPI_REDIS_HOST
- ladjs/api redis hostnameAPI_REDIS_PASSWORD
- ladjs/api redis passwordBREE_REDIS_PORT
- breejs/bree redis portBREE_REDIS_HOST
- breejs/bree redis hostnameBREE_REDIS_PASSWORD
- breejs/bree redis passwordMANDARIN_REDIS_PORT
- mandarin redis portMANDARIN_REDIS_HOST
- mandarin redis hostnameMANDARIN_REDIS_PASSWORD
- mandarin redis passwordCERTBOT_WELL_KNOWN_NAME
- letsencrypt wellknown name (see certbot options)CERTBOT_WELL_KNOWN_CONTENTS
- letsencrypt wellknown contents (see certbot options)VERIFICATION_PIN_TIMEOUT_MS
- (default:5m
) - email verification pin expiryVERIFICATION_PIN_EMAIL_INTERVAL_MS
- (default:1m
) - email verification pin email intervalAPI_SECRETS
- (default:secret
) - list of restricted api secretsCACHE_RESPONSES
- (default:false
) - cache specified responses (see ladjs/koa-cache-responses)SLACK_API_TOKEN
- slack api token (see slack web api)
SSL Configuration
To configure SSL for the web or API server simply set them in your .env
file or pass them as environment variables.
Web server:
WEB_PROTOCOL
- you must set this tohttps
WEB_SSL_KEY_PATH
- file path to your SSL key file (e.g./home/deploy/.ssl/web-key.pem
)WEB_SSL_CERT_PATH
- file path to your SSL certificate file (e.g./home/deploy/.ssl/web-cert.pem
)WEB_SSL_CA_PATH
(optional) - file path to your SSL certificate authority file (e.g./home/deploy/.ssl/web-ca-cert.pem
)
API server:
API_PROTOCOL
- you must set this tohttps
API_SSL_KEY_PATH
- file path to your SSL key file (e.g./home/deploy/.ssl/api-key.pem
)API_SSL_CERT_PATH
- file path to your SSL certificate file (e.g./home/deploy/.ssl/api-cert.pem
)API_SSL_CA_PATH
(optional) - file path to your SSL certificate authority file (e.g./home/deploy/.ssl/api-ca-cert.pem
)
Outbound Email Configuration
By default in the development environment we simply render the email in your browser.
However in other environments such as production, you definitely want emails to be sent.
We built-in support for Postmark by default (though you can swap in your own transport
provider in the jobs/email.js
file):
-
Go to https://postmarkapp.com β Start Free Trial
-
Create a free trial account, then click Get Started, and proceed to create a "Server" and "Sender Signature"
-
Copy/paste the "Server API token" under "Credentials" in your
.env
file (example below)-POSTMARK_API_TOKEN= +POSTMARK_API_TOKEN=ac6657eb-2732-4cfd-915b-912b1b10beb1
-
Modify the
SEND_EMAIL
variable in.env
fromfalse
totrue
Favicon and Touch Icon Configuration
You can customize the favicon and touch icons β just generate a new set at https://realfavicongenerator.net and overwrite the existing in the assets folder.
Just make sure that any relative paths match up in the assets/browserconfig.xml
and assets/manifest.json
files.
Authentication Methods
We use Lad's auth package under the hood; so if you want to configure authentication providers you'll want to read more or contribute to @ladjs/auth.
Google Auth
In order to add Google sign-in to your app (so users can log in with their Google account):
-
Go to https://console.developers.google.com β Create a project (and fill out your project information β if you need a 120x120px default image, you can use this one with a CDN path of https://cdn.rawgit.com/ladjs/lad/82d38d64/media/lad-120x120.png
-
Under your newly created project, go to Credentials β Create credentials β OAuth client ID β Web application
-
Set "Authorized JavaScript origins" to
http://yourdomain.com
(replace with your domain) and alsohttp://localhost:3000
(for local development) -
Set "Authorized redirect URIs" to
http://yourdomain.com/auth/google/ok
(again, replace with your domain) and alsohttp://localhost:3000/auth/google/ok
(again, for local development) -
Copy and paste the newly created key pair for respective properties in your
.env
file (example below)-GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_ID=424623312719-73vn8vb4tmh8nht96q7vdbn3mc9pd63a.apps.googleusercontent.com -GOOGLE_CLIENT_SECRET= +GOOGLE_CLIENT_SECRET=Oys6WrHleTOksqXTbEY_yi07
-
In
.env
, make sure thatAUTH_GOOGLE_ENABLED=true
to enable this authentication method.
Translation Configuration
- Go to https://console.developers.google.com
- Enable the Google Translate API
- Copy your API key and set it as the environment variable
GOOGLE_TRANSLATE_KEY=******
Continuous Integration and Code Coverage
We strongly recommend that you use SemaphoreCI for continuous integration and Codecov for code coverage.
Here are the simple steps required to setup SemaphoreCI with Codecov:
-
Go to SemaphoreCI and sign up for a free account
-
Once your repository is pushed to GitHub, add it as a project on SemaphoreCI
-
Configure your project on SemaphoreCI with the following build settings:
Replace
npm
withyarn
if you're using yarn as your package manager- Language:
JavaScript
- Node.js version:
10+
(latest LTS)Note you can also add to
Setup
the scriptnvm install latest
to install latest version if SemaphoreCI does not provide it from the drop-down - Setup:
npm install
- Job 1:
npm run test-coverage
- After job:
npm run coverage
- Language:
-
Go to Codecov and sign up for a free account
-
Add your project on Codecov and copy to your clipboard the token
-
Go to SemaphoreCI's Project Settings for your project and add
CODECOV_TOKEN
as an environment variable (with the contents from your clipboard) -
Run a test build ("Rebuild last revision") on SemaphoreCI and check to make sure your code coverage report uploads properly on Codecov
-
Ensure your
README.md
file has the build status and code coverage badges rendered properly (you will need to use a different badge link from each provider if your GitHub repository is private)
Amazon S3 and CloudFront Asset Setup
In order for your assets to get properly served in a production environment, you'll need to configure AWS:
-
Go to https://console.aws.amazon.com/iam/home#security_credential β Access Keys β Create New Access Key
-
Copy and paste the newly created key pair for respective properties in your
.env
file (example below)-AWS_IAM_KEY= +AWS_IAM_KEY=AKIAJMH22P6W674YFC7Q -AWS_IAM_SECRET= +AWS_IAM_SECRET=9MpR1FOXwPEtPlrlU5WbHjnz2KDcKWSUcB+C5CpS
-
Enable your API by clicking on Overview and then clicking the Enable button
-
Go to https://console.aws.amazon.com/s3/home β Create Bucket
-
Create a bucket and copy/paste its name for the property in
.env
(example below)-AWS_S3_BUCKET= +AWS_S3_BUCKET=lad-development
-
Go to https://console.aws.amazon.com/cloudfront/home β Create Distribution β Get Started
-
Set "Origin Domain Name" equal to your S3 bucket name (their autocomplete drop-down will help you find it)
-
Leave the remaining defaults as is (some fields might be blank, this is OK)
-
Copy/paste the newly created Distribution ID and Domain Name for respective properties in your
.env
file (example below)-AWS_CF_DI= +AWS_CF_DI=E2IBEULE9QOPVE -AWS_CF_DOMAIN= +AWS_CF_DOMAIN=d36aditw73gdrz.cloudfront.net
Tutorials
Community
- Follow us on Twitter
- Join our Slack channel
- Subscribe to our Twitch channel
- Visit Koa's Community section.
- Join Mongoose's Slack channel
Architecture
The following bash output is the directory structure and organization of Lad:
tree template -I "build|node_modules|coverage|test"
template
βββ LICENSE
βββ README
βββ ansible
βΒ Β βββ playbooks
βΒ Β βΒ Β βββ aws-credentials.yml
βΒ Β βΒ Β βββ bree.yml
βΒ Β βΒ Β βββ certificates.yml
βΒ Β βΒ Β βββ deployment-keys.yml
βΒ Β βΒ Β βββ ecosystem.yml
βΒ Β βΒ Β βββ env.yml
βΒ Β βΒ Β βββ gapp-creds.yml
βΒ Β βΒ Β βββ http.yml
βΒ Β βΒ Β βββ mongo.yml
βΒ Β βΒ Β βββ node.yml
βΒ Β βΒ Β βββ python.yml
βΒ Β βΒ Β βββ redis.yml
βΒ Β βΒ Β βββ security.yml
βΒ Β βΒ Β βββ ssh-keys.yml
βΒ Β βΒ Β βββ templates
βΒ Β βΒ Β βββ aws-credentials.j2
βΒ Β βΒ Β βββ before.rules.j2
βΒ Β βΒ Β βββ ecosystem-api.json.j2
βΒ Β βΒ Β βββ ecosystem-bree.json.j2
βΒ Β βΒ Β βββ ecosystem-web.json.j2
βΒ Β βΒ Β βββ env
βΒ Β βΒ Β βββ hosts.yml
βΒ Β βΒ Β βββ security-limits.d-mongod.conf
βΒ Β βββ requirements.yml
βββ ansible-playbook.js
βββ ansible.cfg
βββ api.js
βββ app
βΒ Β βββ controllers
βΒ Β βΒ Β βββ api
βΒ Β βΒ Β βΒ Β βββ index.js
βΒ Β βΒ Β βΒ Β βββ v1
βΒ Β βΒ Β βΒ Β βββ index.js
βΒ Β βΒ Β βΒ Β βββ log.js
βΒ Β βΒ Β βΒ Β βββ users.js
βΒ Β βΒ Β βββ index.js
βΒ Β βΒ Β βββ web
βΒ Β βΒ Β βββ admin
βΒ Β βΒ Β βΒ Β βββ index.js
βΒ Β βΒ Β βΒ Β βββ users.js
βΒ Β βΒ Β βββ auth.js
βΒ Β βΒ Β βββ index.js
βΒ Β βΒ Β βββ my-account.js
βΒ Β βΒ Β βββ otp
βΒ Β βΒ Β βΒ Β βββ disable.js
βΒ Β βΒ Β βΒ Β βββ index.js
βΒ Β βΒ Β βΒ Β βββ keys.js
βΒ Β βΒ Β βΒ Β βββ recovery.js
βΒ Β βΒ Β βΒ Β βββ setup.js
βΒ Β βΒ Β βββ report.js
βΒ Β βΒ Β βββ support.js
βΒ Β βββ models
βΒ Β βΒ Β βββ index.js
βΒ Β βΒ Β βββ inquiry.js
βΒ Β βΒ Β βββ user.js
βΒ Β βββ views
βΒ Β βββ 404.pug
βΒ Β βββ 500.pug
βΒ Β βββ _breadcrumbs.pug
βΒ Β βββ _footer.pug
βΒ Β βββ _nav.pug
βΒ Β βββ _pagination.pug
βΒ Β βββ _register-or-login.pug
βΒ Β βββ about.pug
βΒ Β βββ admin
βΒ Β βΒ Β βββ index.pug
βΒ Β βΒ Β βββ users
βΒ Β βΒ Β βββ index.pug
βΒ Β βΒ Β βββ retrieve.pug
βΒ Β βββ change-email.pug
βΒ Β βββ dashboard
βΒ Β βΒ Β βββ index.pug
βΒ Β βββ donate.pug
βΒ Β βββ forgot-password.pug
βΒ Β βββ home.pug
βΒ Β βββ layout.pug
βΒ Β βββ my-account
βΒ Β βΒ Β βββ index.pug
βΒ Β βΒ Β βββ profile.pug
βΒ Β βΒ Β βββ security.pug
βΒ Β βββ otp
βΒ Β βΒ Β βββ enable.pug
βΒ Β βΒ Β βββ keys.pug
βΒ Β βΒ Β βββ login.pug
βΒ Β βΒ Β βββ setup.pug
βΒ Β βββ privacy.pug
βΒ Β βββ register-or-login.pug
βΒ Β βββ reset-password.pug
βΒ Β βββ spinner
βΒ Β βΒ Β βββ 1.pug
βΒ Β βΒ Β βββ 10.pug
βΒ Β βΒ Β βββ 11.pug
βΒ Β βΒ Β βββ 2.pug
βΒ Β βΒ Β βββ 3.pug
βΒ Β βΒ Β βββ 4.pug
βΒ Β βΒ Β βββ 5.pug
βΒ Β βΒ Β βββ 6.pug
βΒ Β βΒ Β βββ 7.pug
βΒ Β βΒ Β βββ 8.pug
βΒ Β βΒ Β βββ 9.pug
βΒ Β βΒ Β βββ spinner.pug
βΒ Β βββ support.pug
βΒ Β βββ terms.pug
βΒ Β βββ verify.pug
βββ assets
βΒ Β βββ browserconfig.xml
βΒ Β βββ css
βΒ Β βΒ Β βββ _btn-auth.scss
βΒ Β βΒ Β βββ _custom.scss
βΒ Β βΒ Β βββ _email.scss
βΒ Β βΒ Β βββ _markdown.scss
βΒ Β βΒ Β βββ _responsive-backgrounds.scss
βΒ Β βΒ Β βββ _responsive-borders.scss
βΒ Β βΒ Β βββ _responsive-rounded.scss
βΒ Β βΒ Β βββ _swal2.scss
βΒ Β βΒ Β βββ _variables.scss
βΒ Β βΒ Β βββ app.scss
βΒ Β βββ fonts
βΒ Β βββ img
βΒ Β βΒ Β βββ android-chrome-192x192.png
βΒ Β βΒ Β βββ android-chrome-384x384.png
βΒ Β βΒ Β βββ apple-touch-icon.png
βΒ Β βΒ Β βββ favicon-16x16.png
βΒ Β βΒ Β βββ favicon-32x32.png
βΒ Β βΒ Β βββ favicon.ico
βΒ Β βΒ Β βββ github-logo.svg
βΒ Β βΒ Β βββ google-logo.svg
βΒ Β βΒ Β βββ logo-square.svg
βΒ Β βΒ Β βββ mstile-150x150.png
βΒ Β βΒ Β βββ social.png
βΒ Β βΒ Β βββ twitter.png
βΒ Β βββ js
βΒ Β βΒ Β βββ core.js
βΒ Β βΒ Β βββ logger.js
βΒ Β βΒ Β βββ uncaught.js
βΒ Β βββ robots.txt
βΒ Β βββ site.webmanifest
βββ bree.js
βββ config
βΒ Β βββ api.js
βΒ Β βββ bree.js
βΒ Β βββ cookies.js
βΒ Β βββ env.js
βΒ Β βββ filters.js
βΒ Β βββ i18n.js
βΒ Β βββ index.js
βΒ Β βββ koa-cash.js
βΒ Β βββ locales.js
βΒ Β βββ logger.js
βΒ Β βββ meta.js
βΒ Β βββ phrases.js
βΒ Β βββ utilities.js
βΒ Β βββ web.js
βββ emails
βΒ Β βββ _content.pug
βΒ Β βββ _footer.pug
βΒ Β βββ _nav.pug
βΒ Β βββ account-update
βΒ Β βΒ Β βββ html.pug
βΒ Β βΒ Β βββ subject.pug
βΒ Β βββ change-email
βΒ Β βΒ Β βββ html.pug
βΒ Β βΒ Β βββ subject.pug
βΒ Β βββ inquiry
βΒ Β βΒ Β βββ html.pug
βΒ Β βΒ Β βββ subject.pug
βΒ Β βββ layout.pug
βΒ Β βββ recovery
βΒ Β βΒ Β βββ html.pug
βΒ Β βΒ Β βββ subject.pug
βΒ Β βββ reset-password
βΒ Β βΒ Β βββ html.pug
βΒ Β βΒ Β βββ subject.pug
βΒ Β βββ two-factor-reminder
βΒ Β βΒ Β βββ html.pug
βΒ Β βΒ Β βββ subject.pug
βΒ Β βββ verify
βΒ Β βΒ Β βββ html.pug
βΒ Β βΒ Β βββ subject.pug
βΒ Β βββ welcome
βΒ Β βββ html.pug
βΒ Β βββ subject.pug
βββ env
βββ gitignore
βββ gulpfile.js
βββ helpers
βΒ Β βββ email.js
βΒ Β βββ get-email-locals.js
βΒ Β βββ i18n.js
βΒ Β βββ logger.js
βΒ Β βββ markdown.js
βΒ Β βββ passport.js
βΒ Β βββ policies.js
βΒ Β βββ send-verification-email.js
βΒ Β βββ to-object.js
βββ index.js
βββ jobs
βΒ Β βββ account-updates.js
βΒ Β βββ index.js
βΒ Β βββ translate-markdown.js
βΒ Β βββ translate-phrases.js
βΒ Β βββ two-factor-reminder.js
βΒ Β βββ welcome-email.js
βββ lad.sh
βββ locales
βΒ Β βββ ar.json
βΒ Β βββ cs.json
βΒ Β βββ da.json
βΒ Β βββ de.json
βΒ Β βββ en.json
βΒ Β βββ es.json
βΒ Β βββ fi.json
βΒ Β βββ fr.json
βΒ Β βββ he.json
βΒ Β βββ hu.json
βΒ Β βββ id.json
βΒ Β βββ it.json
βΒ Β βββ ja.json
βΒ Β βββ ko.json
βΒ Β βββ nl.json
βΒ Β βββ no.json
βΒ Β βββ pl.json
βΒ Β βββ pt.json
βΒ Β βββ ru.json
βΒ Β βββ sv.json
βΒ Β βββ th.json
βΒ Β βββ tr.json
βΒ Β βββ uk.json
βΒ Β βββ vi.json
βΒ Β βββ zh.json
βββ nodemon.json
βββ package-scripts.js
βββ package.json
βββ proxy.js
βββ routes
βΒ Β βββ api
βΒ Β βΒ Β βββ index.js
βΒ Β βΒ Β βββ v1
βΒ Β βΒ Β βββ index.js
βΒ Β βββ index.js
βΒ Β βββ web
βΒ Β βββ admin.js
βΒ Β βββ auth.js
βΒ Β βββ index.js
βΒ Β βββ my-account.js
βΒ Β βββ otp.js
βββ template
βββ web.js
βββ yarn-error.log
βββ yarn.lock
42 directories, 212 files
Principles
Lad is designed according to these principles:
- Always be developer-friendly
- Adhere to MVC, Unix, KISS, DRY, YAGNI, Twelve Factor, Occam's razor, and dogfooding
- Target the scrappy, bootstrapped, and ramen-profitable hacker
Related
- lipo - Free image manipulation API service built on top of Sharp
- cabin - Logging and analytics solution for Node.js, Lad, Koa, and Express
- lass - Scaffold a modern boilerplate for Node.js
Contributing
Interesting in contributing to this project or testing early releases?
-
Follow all of the above Requirements
-
You will need to fork and clone this repository locally
-
After forking, follow these steps:
cd lad yarn install cd template yarn install yarn start
If you'd like to preview changes to the README.md
file, you can use docute
.
yarn global add docute-cli
cd lad
docute ./
Then visit http://localhost:8080 in your browser.
Contributors
Name | Website |
---|---|
Nick Baugh | http://niftylettuce.com |
Shaun Warman | https://shaunwarman.com/ |
Trademark Notice
Lad, Lass, Cabin, Lipo, and their respective logos are trademarks of Niftylettuce LLC. These trademarks may not be reproduced, distributed, transmitted, or otherwise used, except with the prior written permission of Niftylettuce LLC. If you are seeking permission to use these trademarks, then please contact us.
License
MIT Β© Nick Baugh