This is a Node.js app (v22) running on Express with Nunjucks as a template engine. It uses the GOV.UK Frontend. ESBuild is used for bundling.
This app is heavily inspired from MoJ's hmpps-template-typescript.
- Installation
- Running
- Project Structure
- Language Support
- Tests
- Static Checks
- E2E Tests
- Pipeline
- Analytics
- Architecture
- Infrastructure
- Local Development Shortcuts
- Contributing
- Preview testing
- TODO
- Known issues
Install Node 22. It is recommended to use a versioning manager such as nvm.
To download the dependencies, run npm install.
If you want to run the application locally with a cache, install Docker Desktop.
To run the application, you will need to create a .env file. There is an example file that can be used.
To copy it, run
cp .env.example .envNow to run the app, run npm run start:dev, which will start the app (by default on port 8001), with hot reloading enabled.
When deployed to an environment with multiple pods we run applications with an instance of Redis/Elasticache to provide
a distributed cache of sessions. The app is, by default, configured not to use Redis when running locally. In order to
use Redis locally, set the CACHE_ENABLED environment variable to true, and start Redis by running
docker compose up -dThe app will now connect to Redis when running.
You can run the app in a docker container, so more closely simulate the hosted environment. To use docker for development, run
docker compose --profile dev upWith the app running, run tests locally in Docker, with the command
docker compose exec -e NODE_ENV=test app npm run testThe main app code lives in the server directory, where it is separated into folders based on functionality. Tests should
be at the same level as the file they test, and names <<file>>.test.ts.
E2E tests are in the e2e-tests directory. Test files should have the name <<file>>.spec.ts.
The app has support for English and Welsh. All text should be added to server/locales, instead of being added directly
to the Nunjucks template. If you have added an item home.title to the locales files, you can access it from the template:
<h1>{{ __('home.title') }}</h1>If there is no Welsh translation, the English value will be used as a fallback.
The Welsh support can be toggled on/off using the INCLUDE_WELSH_LANGUAGE environment variable, allowing us to do
releases before full Welsh translation is complete.
We use Jest for unit tests. To run them run npm run test.
Note: The integration tests assume the authentication is switched in the config. The default setups use the .env.test
file, where this is the case, but if you are modifying things you will need to ensure this is still used.
For full details on running tests and previewing PDF and HTML export output without going through the service journey, see the tests README.
To run the TypeScript compiler use npm run typecheck.
We use ESLint for linting. To run the check use npm run lint. npm run lint:fix can be used to automatically fix issues.
We use Prettier to ensure consistent styling. Run npm run prettier to check for issues, and npm run prettier:fix to fix them.
It is recommended to use your IDE to run ESLint and Prettier on save, to ensure files are formatted correctly.
We use Playwright for end-to-end tests. See the Playwright quickstart guide for a first-time walkthrough, or the E2E tests README for full reference. To run them:
npm run e2eLocally, tests run across all three browsers (Chromium, Firefox, WebKit). In CI, only Chromium is used for stability.
Husky runs two checks before each commit:
- Lint — runs
npm run lintand warns if there are issues - Playwright cross-browser check — warns if
playwright-results.xmlis missing or does not include results for all three browsers
Neither check blocks the commit. The Playwright results file is automatically deleted after each commit, so you will be reminded to re-run the tests before your next commit.
We have two pipelines. One runs for pull requests, and prevents the merge unless the tests and static analysis are passing.
The second runs on merges to the main branch, and runs these tests, then releases the app to the development environment.
There is a manual step in this pipeline to release to production.
Secrets used in the deployment pipeline are stored as GitHub Actions secrets, and are saved per-environment.
We used GA4 for tracking. GA4 will only be enabled if the environment variable GA4_ID exists.
If the user does not have a cookie_policy cookie, GA4 will not activate, and the cookie consent banner will load. Once
that cookie exists, tracking will be enabled depending on the consent setting within in.
For preview testing, we wish to get numbers using the service, and GA4 is not reliable for this due to ad-blockers or users denying consent. There are server logs which can be used for this purpose (although they may need de-duplicating based off IP address).
- To see users starting the service, count the numbers of successful logins:
Received successful login request - To see users completing the service, count the number of hits to the share page:
Responded to GET /share-plan with 200
For documentation on the project architecture, see here
For documentation on our infrastructure, see here
To avoid clicking through the entire service to test a later page, you can seed the session with pre-filled data using the dev seed route (only available when NODE_ENV is not production):
http://localhost:8001/dev/seed?redirect=/check-your-answers
The redirect query parameter accepts any valid path in the service. If omitted, it defaults to the task list (/make-a-plan). Some examples:
http://localhost:8001/dev/seed?redirect=/make-a-plan
http://localhost:8001/dev/seed?redirect=/check-your-answers
http://localhost:8001/dev/seed?redirect=/decision-making/plan-review
http://localhost:8001/dev/seed?redirect=/share-plan
The seed populates the session with two children (Alex and Jamie) and two adults (Sarah and Tom), with all tasks completed.
See CONTRIBUTING.md for guidance on adding new questions and other common development tasks.
The service underwent private preview testing, which ended on 30th April 2025. The PREVIEW_END environment variable
controls this date. After this date, all requests to the service return a page explaining that the preview has ended.
To move the service into an open beta, the following changes should be made:
- Remove the password page and authentication middleware
- Remove the service no longer available middleware
- Sonar/some SAST tool
-
Continue behaviour does not always make sense
If I go to a question from the check your answers page, and then press continue, I should be taken back to the check your answers page, not back into the full question flow
-
Some characters are missed in the PDF
Some characters such as Ǝ are not printed in the pdf, as the GDS transport font does not support them
-
PDF does not have heading structures
The exported pdf has not been rendered using accessible heading structures.
