This is a modified version of the engineering documentation I wrote for an application where I was the lead developer. In addition to the typical setup-run-test-deploy tasks, I explain a few bigger choices and guide new devs through a few common tasks, such as:
- Folder layout
- Database migrations
- Adding new (HTTP) API endpoints
- Adding permissions on resources
- React concerns:
- Major React contexts provided
- Component authoring guidelines & naming conventions
- Why not Redux
- Build & Release config variables
- Monitoring dashboards
- Bigger migrations for eventual consideration, along with possible strategies for how
- Create React App to Next/Redwood/Vite
- MUI to other UI kit
- Library choices, like Mantine for hooks and Luxon for dates.
This is the monorepo that holds the code for the API server and frontend.
Projects are managed using npm workspaces. These are:
Each project has its own README for more docs and guides.
- Install Node.js 16+ and npm 8+.
- Install docker.
- Install dependencies by running
npm install
from the repository root directory. - Initialize the local dev stack by running
npm run system:init
in the repository root directory. - Go through the steps in Running the dev server to make sure the system runs locally.
- (Optional) Install VSCode and recommended extensions for this project (the list should be visible from VSCode's extensions pane).
- (Optional) If you're using VSCode, go through the steps in Full-stack debugging to make sure you can use breakpoints correctly.
You can also install VS Code and recommended extensions to get autoformatting, test results, and linting feedback in your editor.
Run the stack locally via npm system:start
. This starts:
- A PostgreSQL database, via docker compose, at localhost:5432
- The NestJS app server on http://localhost:3000
- The ReactJS frontend on http://localhost:3001
- A PostgreSQL admin UI (also via docker compose) on http://localhost:3002. Use database
app
and passwordlocaldevpass
to access it.
To stop the local system, press Ctrl+C. The local database container will keep its data. To drop and re-create the database schema, and re-seed data, run npm run system:init
.
- Build all projects:
npm run build --workspaces
- Run all tests:
npm test --workspaces --if-present
There are more npm tasks, but they vary by workspace. Run npm run --workspaces
to see them all. sdk, for instance, has no test
task because the code is all generated. api has a start:prod
task while web doesn't because it's a static site.
To use breakpoints across both api
and web
, run the system locally via npm run system:start
, then run the Attach to system:start debug task from VSCode.
To make sure it works on your machine, follow these steps:
- Start the system locally via
npm run system:start
. - Set a breakpoint in web/src/healthCheck/StatusPage.tsx right after the line including
useStatus()
. - Set a breakpoint in api/src/health/health.controller.ts on the line calling
this.healthService.getDBTime()
. - Open the debug pane in VSCode and run the debug task titled Attach to system:start.
- Wait for a new Chrome window to open, and navigate to http://localhost:3001/status.
- Verify that the UI shows the loading spinner, VSCode opens the StatusPage.tsx (frontend) file, and indicates that it is stopped on the breakpoint.
- Verify that the VARIABLES section in VSCode's debug pane shows an
isLoading: true
variable in scope. - Click the continue button (or press F5) in the debug controls to continue executing the program. Due to the way react-query loads data, you should hit the frontend breakpoint again.
- Continue clicking the continue button a few more times until VSCode stops at your breakpoint in health.controller.ts (backend).
- Click continue again and verify that VSCode stops in the frontend file again.
- Continue until the UI shows the loaded status page.
To debug tests, open VSCode, set a breakpoint in test or production code, then navigate to the test file and click the "Debug" text above the test definition. This should run the test in question and stop at any breakpoints hit during testing.
Every PR against main
will deploy to an ad-hoc URL which will be added as a comment on the pull request. This is a preview environment to test changes, but it will still connect to the staging database.
Every commit to main
will trigger a deploy to stage. This will happen automatically after you merge your approved pull requests.
When we get a production environment, we plan to create a production
branch from which to automatically deploy to prod. In that case, production deployments will happen via a PR from main
or a stage/release branch to production
. At that time we may also add more control around when staging deployments happen too.
This should only be done if the git workflow isn't possible for some reason.
To deploy manually:
- Install the gcloud CLI.
- Initialize and authenticate
gcloud
. - Make sure you have the App Engine Deployer role or higher on the ourapp-prod GCP project.
- Create a file named deploy-env.yaml in the repository root with the following contents:
(Replace "staging_db_password" with the actual staging DB password)
env_variables: MIKRO_ORM_PASSWORD: staging_db_password
- Run
npm run build --workspaces
from the repository root. - To deploy to an ad-hoc environment, run
gcloud app deploy --version=adhoc-myenv --no-promote
, replacingadhoc-myenv
with a name of your choice. This will deploy to a custom URL but it will still connect to the staging database. - To deploy to staging, run
gcloud app deploy
.