The Pairwise codebase includes a React app client application, a NestJS server application, and other various services, all bundled up in a monorepo using Lerna and Yarn workspaces.
Pairwise failed to gain enough user traction and is no longer operating as a business. All the code here is now open source and the app has been converted to a frontend-only application, which is still running for anyone to see. Thanks for visiting!
This project is managed using Lerna, and contains the following packages:
Package | Description |
---|---|
admin | React admin client application |
client | React client application |
common | Shared code, utils, and types |
cypress | Cypress end-to-end test suite |
e2e | End-to-end API test suite |
external-services | 3rd party APIs for testing and development |
server | NestJS backend application |
We use the following libraries across the codebase, here are some quick links to their docs:
- TypeScript: Types!
- React: The best.
- Redux: Yes, Redux.
- RxJS: Futuristic stuff.
- Redux Observable: Truly epic.
- React Router: Meh.
- BlueprintJS: Modern, fashionable.
- NestJS: Feels like SpringBoot.
- Redis: Shared state and data caching layer.
- SocketIO: Real time server events.
- TypeORM: Postgres ORM.
- Passport: (Easy) authentication.
- Jest: The Test Runner.
- Cypress: Automate UI testing.
- ESLint: Write code according to the rules.
- Prettier: Make the code pretty.
- Lerna: All the code, all the repos.
- VS Code: Highly recommended, great experience.
- GitHub Actions: Automate!
- Netlify: Host the Pairwise client workspace and admin dashboard.
- Google Cloud Platform: Deploy the production backend.
To work with Pairwise you will need Node, npm, yarn, and Docker installed. We recommend using nvm to manage different versions of Node (we recommend Node 12, e.g. 12.16.1
).
We recommend using the latest version of Yarn and Node LTS:
# Install Node LTS
$ nvm install lts/*
# Set Node LTS as default Node version with nvm
$ nvm alias default lts/*
We also recommend using Visual Studio Code and installing the recommended project extensions.
All the important information about how Pairwise works should be covered in the repo README
documents. These documents serve as a quick reference to learn about how the entire codebase works, and are linked in the above repo structure section.
To run the app you will need Docker and Node installed. All of the packages tend to have commands of the structure [package]:[dev|start|watch|build|prod]
so you can generally modify the following scripts depending on how you want to start different packages.
Some setup steps you will need to run after cloning the repo:
# Install Lerna
$ npm i -g lerna
# Install dependencies
$ lerna bootstrap
# Create .env files in relevant packages
$ yarn setup
# Build all packages
$ yarn build
# Start the database
$ yarn db
# Run database migrations
$ yarn db:setup
To run all the services separately:
# Start the database
$ yarn db
# Start Redis
$ yarn redis
# Start the server
$ yarn server:dev
# Start the client workspace
$ yarn client
# Start the admin client
$ yarn admin
# Start the client in development mode (no server required)
$ yarn client:dev
# (Optional) Run the common package
$ yarn common:watch
# (Optional) Run the external services
$ yarn services:watch
To run the backend application (database, server, and external services). This can be useful when just developing the client application, or when working on Cypress tests.
# Build the Docker image which has all dependencies installed
$ yarn docker:dependencies
# Run the application with Docker Compose
$ yarn up
# Run the client app
$ yarn client
We use Codepress to develop course content. Codepress is an internal CMS tool built into the Pairwise Workspace. You can run it with the command yarn client:codepress
. Then, just open the app in your browser to get started. Codepress changes will write directly to the JSON course content file.
Each package contains unit tests relevant to that package. The backend APIs are tested with a series of e2e tests which are located in the e2e/
package, and the entire application is also tested using Cypress. The e2e tests include tests for APIs which depend on Redis and SocketIO.
# Use Lerna to run the test script for each package
$ yarn test
# Build the Docker image which has all dependencies installed
$ yarn docker:dependencies
# Build the applications
$ yarn docker:build
# Run the unit tests for all packages using Docker
$ yarn docker:test
# Run the e2e test suite (be sure to run docker:dependencies first)
$ yarn e2e
# Run the Cypress end to end test suite (be sure to run docker:dependencies first)
$ yarn cypress
# With the application running locally, this command will run the e2e and Cypress tests
$ yarn ci
To troubleshoot or develop tests locally, you can run the necessary application services using instructions from above and then run the tests locally from their respective package, e2e
or cypress
. You can also run yarn up
and then run the tests locally (see each test package README for further instructions).
A quick note to keep in mind about running docker-compose
commands. There are multiple docker-compose.yml
configurations in the project, if you run docker-compose
commands you need to reference the file you want to run the command for, or be in the directory where that file is.
We use the passport module for defining single-sign-on provider logins with common social account providers like Google, Facebook, and GitHub. Authorization through one of these strategies creates a user account which is uniquely identified by the email address. After authentication, a user is granted a long-lived jwt
to stay signed into Pairwise.
To test authentication locally, you will need to run the client and server using https
, which can be done using the yarn client|server|services:https
commands. Also, you may need to visit chrome://flags/#allow-insecure-localhost
in Chrome and enable the option to prevent warnings about insecure https on localhost.
On the server, you will need to ensure the environment variables which specify URL overrides for the SSO providers are removed/disabled: variables of the format FACEBOOK_..._URL
. These are only used to override the default behavior in the test/development environment and are not necessary to use the actual integration.
All of the SSO provider logins have mock API implementations in the external-services
package, which are used when running e2e/Cypress tests. These can be enabled locally by running the
external services server and by loading all of the SSO provider environment variables which point to the local external service mock APIs (see server/sample.env
) when running the application server.
We are using Stripe to process user payments. Currently, the application redirects to a hosted Stripe checkout page which then sends a webhook event to our server if the user completes the checkout process successfully. The user is then redirected back to Pairwise and sees a payment confirmation. Here are some instructions and resources for working locally if you need to work on the Stripe payments integration feature.
The docker-compose files deploy a stripe
service which runs the Stripe CLI docker image which handles processing Stripe events. This allows the payment integration to simply work in development mode when running Pairwise locally or in a CI environment. Stripe provides several options for easily testing payments in development. For instance, you can enter the card number 4242424242424242
with any future date as an expiration and any 3 digit CVC to submit a test successful payment.
To run the Stripe CLI locally, outside of Docker, you can run the following command:
# Run the Stripe CLI and forward requests to localhost:9000/payments/stripe-webhook
$ yarn stripe:dev
Please note that it is necessary to have the Stripe CLI running for the payment checkout to complete successfully and submit the webhook to our server.
If the database schema changes or you want to simply remove all the data in your local database you can do the following:
# Drops database tables and re-runs the latest migrations
$ yarn db:reset
These steps will be necessary if for instance the node_module
dependencies for any package have changed.
# Install any missing dependencies
$ yarn
# Runs the builds for all packages, building @pairwise/common first
# NOTE: You may need to increase the memory allocation for Docker on your
# local machine for the build to execute successfully. If you see out of
# memory errors from the client build, this is probably why.
$ yarn build
# Build the base Docker image which has all dependencies installed
$ yarn docker:dependencies
# Rebuild the docker compose for running the app
$ yarn up:build
# Shut down docker-compose services
$ yarn down
If you feel like you having issues with Docker or it is running slowly, you can run docker system prune
to remove any older unused resources and images.
We follow a normal git workflow. Commit your changes to a branch, make a pull request, and merge the code after the tests pass.
The client workspace is deployed using Netlify and the backend server is deployed using Google Cloud Run, which should provide generous scaling benefits. The backend also relies on a Redis instance deployed on Redis Labs. Updates are shipped continuously by commits to the main
branch, and configured in the deploy-production.yml
GitHub Actions workflow file. Some additional services are deployed separately and managed in other pairwise/
repositories. You can simulate the production backend deployment locally by running the following commands:
# Build the production server container
$ yarn docker:prod-server-build
# Run the production server
$ yarn docker:prod-server-start
On occasion you may need to connect directly to the production database. You can do this by whitelisting your local IP in the Google Cloud SQL console and then using a local Postgres client to connect.