- Install node (latest).
- Install yarn
- Install docker
- Install TSlint plugin for your editor (vscode).
- Install editorconfig plugin for your editor (vscode).
Run yarn dev-server
and yarn dev-client
from the project's root to quickly start the development enviroment. Or run yarn dev
to start both concurrently.
cd client
Commands here are relative to the client directory.
yarn
- Install dependencies.yarn start
- Starts the development environment.- Navigate to http://localhost:3000 to see the client in the browser.
Optional: Install vscode's "Project Snippets" extension (search for in the extension sidebar) to have access to some react project snippets.
# Snippets Tab completions
rc: React component
rcr: Routed React Component ("view")
rcs: Statless React Component
rcp: Pure React Component
- To generate the translation typings file run
yarn translation
. - To run a production build run
yarn build
. - To test the serviceworker run a http 2 server with simplehttp2server on the
build/
folder. - To analyze the build package dependencies run
yarn build && yarn analyze
.
Important note: Require lodash depencies by specifing the function you will use. For example. Use:
import get from 'lodash-es/get'
Don't use:
import { get } from 'lodash-es'
Tree shaking with lodash does not work (yet). Not using this style of import will bundle all of lodash (100kb) into the build package.
cd server
All commands are relative to the server directory.
yarn
- Install dependencies.cp .env.example .env
- Copy over developent .env settings.yarn start-db
- Starts a postgres docker image (connection settings are in .env file).yarn dev
- Start a development server on http://localhost:5000- (optional) Set the node version in the
package.json
and.babelrc
to lock the node version.
- Start docker
- Start the database:
yarn start-db
- Start the dev server:
yarn dev
- Typeorm docs: http://typeorm.io/
- Yup (input validation) docs: https://github.com/jquense/yup
Database tables and columns are defined in the entities with typeorm's decorators. See TypeORM - Entities.
- Note I: Always run make sure the development server is running or run
yarn build
before using the typeorm cli, typeorm needs the compiled javascript files to run. - Note II: Foreign keys, cascades, and indexes are not always properly generated by
typeorm migrations:generate
. Always make sure these things are included in your migrations. - Note III: Always check if migrations can be reverted by running
typeorm migrations:revert
after creating one.
# Typeorm CLI commands:
typeorm migrations:run # Runs migrations
typeorm migrations:revert # Rollbacks the last migration
typeorm migrations:generate -n migrationFileName # Generates a migrations based on schema changes
typeorm migrations:create -n migrationFileName # Creates a new migration
Run seeders with yarn seeders
. To clear the database and run seeders run yarn seeders --fresh
. The repo includes faker to generate fake values for the database (See seeders/seedUsersTable.ts
) for an example.
dist/ -> compiled javascript files.
app/
commands/
config/
entities/
http/ -> api layer
graphql/
middleware/
routes/
repository
routes/
services/
ssr/ -> email templates etc.
utils/
index.ts -> main access point of the app
database/
migrations/
seeders/
# CLI commands:
yarn start-db # Start the database
yarn start-server # Start the server
yarn seeders # Run database seeders
yarn build # Compiles typescript and run babel to resolve paths.
yarn watch # Compile typescript and watch for changes
yarn dev # Compile typescript, start the server and watch for changes
yarn start # Starts the server (without babel)
yarn typeorm # Typeorm cli for creating entities, migrations and running migrations
yarn typeorm entity:create # Generates a new entity
yarn typeorm migrations:create # Creates a new migration file.
Typescript compiles to the latest version of ECMASCRIPT ("esnext"). Then using babel, compiles to the latest version of node. Babel provides more a fine grained control with babel-preset-env
over what gets transpiled for the version of node we are using.
- Entities hold business logic and the database schema
- Repositories deal with persisting (caching) and retrieving entities.
- Graphql resolve function act as entry points (controllers) for the app.
Authentication is done via Json Web Token (can be changed). Include a JWT token in a AUTHORIZATION Bearer xxxxx.yyyyy.zzzzz
Header. To authenticate users the JWT is included in the graphql context
.
Use logging! Use the logger included in services/
. Use correct log levels. Log info for general actions. Log debugs for debugging. Log errors when needed (errors logged need to be sent to sentry).
interface Response extends User {}
interface InputArgs {
username: string
email: string
fullname: string
}
export default makeGraphQLField<InputArgs, Response>({
type: UserType, // The response tyoe
args: {
username: { type: GraphQLString },
email: { type: GraphQLString },
fullname: { type: GraphQLString },
// ... additional arguments
},
resolve: async (root, args, context) => {
// AUTHENTICATION GUARD (throws AuthenticationError)
const user = await authGraphQLViewer(context)
// AUTHORIZATION GUARDS
// Checks if the user has permission to execute this action
if (!user.isAdmin) {
throw new AuthorizationError('User is no admin')
}
// VALIDATION GUARD (throws ValidationError)
await validateArgs(schema => ({
username: schema.string().trim().required(),
email: schema.string().trim().email()
.test('unique', '${path} already exists', async email => ! await getUserRepository().findOne({ email }))
.required(),
fullname: schema.string().trim().required()
}), args, { abortEarly: false })
// Do some business logic
const user = User.createNewUser(args)
// Persist the user.
return await getUserRepository().save(user)
}
})
- Use a better docker setup (bryan).
- File storage and mailing.
- Add event (pub/sub).
- Add a transaction id (session id) to generated logs.
- Log errors to sentry.
- Add validation typings (yup).
- Log to papertrail.
- Add redis (for caching/events).
Much love, Lifely team <3