Manage vaccinations in schools
This is a service used within the NHS for managing and recording school-aged vaccinations.
Environments
| Name | URL | Purpose | Care Identity login | Code | Deployment | RAILS_ENV |
|---|---|---|---|---|---|---|
| Test | test.mavistesting.com | Internal testing (manual) | ✅ | main branch (latest) |
automated | staging |
| QA | qa.mavistesting.com | Internal testing (automated) | ❌ | main branch (latest) |
automated | staging |
| Preview | preview.mavistesting.com | External testing | ❌ | release or release candidate |
manual | staging |
| Training | training.manage-vaccinations-in-schools.nhs.uk | External training | ❌ | release branch |
manual | staging |
| Production | www.manage-vaccinations-in-schools.nhs.uk | Live service | ✅ | release branch |
manual | production |
API Documentation
We have two RDoc versions:
-
next - useful for dev work (based off the
nextbranch). -
release - useful for ops to debug live issues (based off the
releasebranch).
Development
Prerequisites
This project depends on:
-
PostgreSQL with PostGIS
The instructions below assume you are using mise to manage the necessary versions of the above.
Application architecture
We keep track of architecture decisions in Architecture Decision Records (ADRs).
We use rladr to generate the boilerplate for new records:
bin/bundle exec rladr new title
Installing dependencies
This project uses mise to manage tool versions.
Prerequisites
Before you can run mise install you might need to install some system libraries and databases.
macOS with Homebrew
# Dependencies for Ruby brew install libyaml # PostgreSQL brew install postgresql postgis # Redis brew install redis # Mise brew install mise
Debian-based Linux
# Dependencies for Ruby sudo apt install build-essential autoconf libssl-dev libyaml-dev zlib1g-dev libffi-dev libgmp-dev libicu-dev rustc # PostgreSQL sudo apt install -y postgresql-common sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh sudo apt install postgresql-17 postgresql-contrib postgresql-17-postgis-3 sudo -u postgres psql -c "CREATE USER $(whoami); ALTER USER $(whoami) WITH SUPERUSER;" # Redis sudo apt install redis-server # Mise curl https://mise.run | sh
See installing Mise for more details on how to install Mise.
Using Mise
At this point it should now be possible to use mise to install the required versions of the tools.
mise install
Background services
For the application to start successfully, PostgreSQL and Redis/Valkey must be running.
macOS with Homebrew
brew services start postgresql redis
Debian-based Linux
sudo systemctl start postgresql.service sudo systemctl start redis.service
Manually
pg_ctl start psql -U postgres -c "CREATE USER $(whoami); ALTER USER $(whoami) WITH SUPERUSER;"
You may have to run this as root via sudo.
redis-server
Running the application
When running for the first time, bin/setup will automatically install Ruby dependencies and set up the database.
This application also comes with a Procfile.dev for use with foreman in development environments. Use the script bin/dev to run it:
$ bin/dev 13:07:31 web.1 | started with pid 73965 13:07:31 css.1 | started with pid 73966 13:07:31 js.1 | started with pid 73967 ...
Branching strategy
See the branching strategy documentation for more information.
Linting
The linters are configured to run using hk which is a tool for running hooks in a Git repository.
If using mise this should have already been installed as it’s listed in .tool-versions, but it can be installed manually by running:
mise use hk pkl
To run the linters you can use hk check and hk fix to check and fix any linting issues respectively. Alternatively bin/lint is provided as a way of running the linters without needing to know about hk.
hk allows for the linters to be installed as Git hook, ensuring they are run on each commit. This can be configured by running:
hk install
Intellisense
solargraph is bundled as part of the development dependencies. You need to set it up for your editor, and then run this command to index your local bundle (re-run if/when we install new dependencies and you want completion):
bin/bundle exec yard gems
You’ll also need to configure your editor’s solargraph plugin to useBundler:
+ "solargraph.useBundler": true,
Debugging with binding.pry
TTY echo can get mangled when using binding.pry in bin/dev. To work around this, you can run rails s directly if you’re not working with any JS or CSS assets.
Alternatively, you can install tmux and overmind which is compatible with our Procfile.dev:
overmind start -f Procfile.dev overmind connect web
Testing
To run the Rails tests:
bin/bundle exec rspec
or run them in parallel using the parallel_tests gem
# Setup rake parallel:create parallel:prepare rake parallel:spec
To run the JS unit tests:
yarn test
End-to-end, performance, security and accessibility tests can be found in the Mavis testing respository. There is also some additional documentation that describes how to run these via GitHub actions.
You can also run the end-to-end tests from this repository:
bin/e2e tests/test_start.py::test_start_page_elements_visible
This requires having the testing repository available locally at ../manage-vaccinations-in-schools-testing(an alternative location can be used by setting the MAVIS_E2E_REPO environment variable) and following the setup steps (installing uv and obtaining a .env file).
You can also include the --main argument when running tests to force using the latest main version of the testing repo.
This runs tests in the end_to_end rails environment which will not interfere with the development server/database. The database needs to be setup in this environment before the tests can be run.
RAILS_ENV=end_to_end bin/rails db:setup RAILS_ENV=end_to_end bin/rails feature_flags:enable_for_development RAILS_ENV=end_to_end bin/mavis gias import --input-file=spec/fixtures/dfe-schools.zip
Example programmes
You can generate an example programme by seeding the database with rails db:seed:replant.
Adding a test user
You can add a new user to an environment using the users:create rake task:
# With no arguments, it will prompt you for all the information it needs: rails users:create # Or, create a user belonging to the team with ODS code 'R1L' (this is created in db/seeds.rb): rails users:create['user@example.com','password123','John', 'Doe','R1L'] # Note that on some Mac machines, this syntax can throw an error saying something like 'zsh: bad pattern', in which case you may need to remove the single quotes and escape the square brackets: rails users:create\[user@example.com,password123,John,Doe,R1L\]
Previewing view components
ViewComponent previews are enabled in development and test environments. In development, they are here:
http://localhost:4000/rails/view_components
The previews are defined in spec/components/previews.
Notify
When developing locally, emails are sent using the :file delivery method, and logged to STDOUT.
If you want to use Notify, you’ll need to set up a test API key, and then set up a config/settings/development.local.yml file:
govuk_notify: enabled: true test_key: YOUR_KEY_HERE
You should set it to enabled: false when you’re done testing Notify locally, because it’s easier to work offline without it.
Reply-To
GOV.UK Notify can store reply-to email addresses and use them when sending mail. Once you’ve added the reply-to email in GOV.UK Notify, get the UUID and add it to the team.
Care Identity Service (CIS2)
This service uses NHS’s CIS2 Care Identity Authentication service to perform OIDC authentication for users.
You can retrieve the issuer URL from the appropriate endpoint listed on [CIS2 Guidance Discovery page] (digital.nhs.uk/services/care-identity-service/applications-and-services/cis2-authentication/guidance-for-developers/detailed-guidance/discovery) (note: the dev env is being deprecated and will be removed):
curl -s https://am.nhsint.auth-ptl.cis2.spineservices.nhs.uk/openam/oauth2/realms/root/realms/NHSIdentity/realms/Healthcare/.well-known/openid-configuration | jq .issuer "https://am.nhsint.auth-ptl.cis2.spineservices.nhs.uk:443/openam/oauth2/realms/root/realms/NHSIdentity/realms/Healthcare"
Clients in the INT environment can be configured via CIS2 Connection Manager, please contact other team members to get the details for that. Mavis can use either a client secret or a private key JWT when authenticating requests to CIS2, these are configured via the Connection Manager.
To configure Mavis, put non-secret configuration into Settings:
cis2: enabled: true issuer: https://am.nhsint.auth-ptl.cis2.spineservices.nhs.uk/openam/oauth2/realms/root/realms/NHSIdentity/realms/Healthcareopenam/oauth2/realms/root/realms/oidc"
And once you have your client secrets, either via the Connection Manager or from NHS support, put the client_id and secret/private_key into the Rails credentials file for the environment you are configuring.
cis2: client_id: # Client ID, as provided by NHS secret: # Client secret, as provided by NHS private_key: # ... or RSA private key in PEM format
The private_key will automatically be used to generate a JWK on the /oidc/jwks endpoint, which is used by CIS2 to validate the JWT we use to request the access token from CIS2.
Reporting
See docs/reporting.md.
Key Rotation
Keys should be rotated regularly. When a new key is introduced it’s JWK will automatically be added to the JWKS generated for /oidc/jwks, but the old public key can also be added to JWKSController::EXTRA_JWK to ensure a smooth roll-over.
Releasing
See the releasing documentation for more information.
Rake tasks
-
feature_flags:seed -
smoke:seed -
vaccines:seed[type]
See the Rake tasks documentation for more information.
Operations tasks
See the Ops tasks documentation for more information.
NHS Personal Demographic Service (PDS) Connection
Mavis is also configured to connect to PDS to retrieve patient information such as NHS numbers.
See the PDS documentation for more information.
Licence
MIT.