- Ruby 3.2.4
- PostgreSQL (we deploy on 11.x)
- NodeJS 18.18.0
- Yarn 1.12.x
- Docker
- Redis 6.2
- Run
bundle install
to install the gem dependencies - Run
yarn
to install node dependencies - Create
.env
file - copy.env.template
. Set your database password and user in the.env
file - Run
bin/rails db:setup
to set up the database development and test schemas, and seed with test data - Run
./bin/dev
to launch the app on http://localhost:3000, sidekiq and auto-compile assets. To run with a Sidekiq worker enabled run./bin/dev -j
- For most work, you will need to seed the database with
rails db:seed
. For school data, see Importing School data
There is a separate Dockerfile for local development. It isn't (currently) very widely used - if it doesn't work, make sure any recently changes to Dockerfile have been applied to Dockerfile.dev where appropriate.
- Create
.env
file - copy.env.template
. Set your database password and user from the docker-compose file in the.env
file - Run
docker-compose build
to build the web image - Run
docker-compose run --rm web bundle exec rake db:setup
to setup the database - Run
docker-compose up
to start the service
It should be possible to run just the database from docker, if you want to.
Check docker-compose file for username and password to put in your .env
file.
If you want to seed the database you can either run db:drop
and db:setup
tasks with your preferred method,
or db:seed
.
The API documenation is a Middleman app contained in the docs
directory. In production it's
built at deploy time and available at /api-reference. We can't use middleman serve
because
the Middleman application assumes it's embedded and references the Rails application's assets, so instead we need to
build it using the following steps:
- install entr using your package manager of choice (eg.
brew install entr
) - use the Makefile to keep building the documentation whenever a file is changed
make -C docs
orcd docs && make watch
Register on GOV.UK Notify.
Ask someone from the team to add you to our service.
Generate a limited api key for yourself and set it in your .env
file.
bundle exec rake
bundle exec rspec
bundle exec rake parallel:create
bundle exec rake parallel:migrate
bundle exec rake parallel:spec
It auto-generates swagger/*/api_spec.json from the schema files located in spec/docs
bundle exec rake rswag:specs:swaggerize
To import the JSON spec into Postman (or equivalent) copy from:
https://github.com/DFE-Digital/early-careers-framework/blob/develop/swagger/v1/api_spec.json
Ideally change baseUrl to http://localhost:3000, since sandbox is used for testing. A bearer token is required per request and should be created in each respective environment e.g. development, sandbox
We use Capybara for end-to-end tests. These can be found in the scenarios folder within ./spec/features/.
The E2E scenarios currently covered are:
- Transferring a participant to a new School
- Onboarding a withdraw participant to a new School
Scenarios tests use the :end_to_end_scenario
tag so that they get excluded from the standard rspec command
For more information on how we now write feature scenarios please our feature testing documentation
RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load
To run the complete set of scenario tests use either:
bundle exec bin/scenarios_ci
or
bundle exec bin/scenarios_ci --fail-fast
To run a specific scenario test include the environment variable SCENARIOS
, for example to run scenarios 2, 12 and 20 use:
SCENARIOS=2,12,20 bundle exec bin/scenarios_ci
Please note: --fail-fast
is recommended when running scenarios locally due to the length of time they can all take to run.
We run smoke tests against review apps. After a review app is deployed, a smoke test will be run against it automatically.
Tests are written in rspec, so if you need to debug them, you can run them locally - just make sure to set the domain to the review app you want to debug against.
Review apps are automatically created when a PR is opened. A link to the app will be posted on the review.
The database of the review app will be truncated and reseeded on each commit and subsequent deploy. This is to aid in manual testing using scenarios set up using seeds.
To further aid manual testing and review of certain circumstances and behaviours, there are a number of magic values that can be used in the date of birth field when adding or validating an ECT or mentor participant. Using these values returns a "spoofed" response from the DQT API integration that enables us to proceed without calling the API or needing to know exactly what and how their test data is configured. These magic values are only available in development environments.
Date of birth | Validation response |
---|---|
1/1/1900 | All data matches and eligible participants |
2/1/1900 | Participant found but the Name and NiNo do not match |
3/1/1900 | No match found |
4/1/1900 | Participant matched but no QTS date recorded |
5/1/1900 | Participant matched but no induction recorded |
6/1/1900 | Participant matched but active alerts present |
21/1/1900 | Participant matched and has a 2021 cohort induction start date |
22/1/1900 | Participant matched and has a 2022 cohort induction start date |
23/1/1900 | Participant matched and has a 2023 cohort induction start date |
24/1/1900 | Participant matched and has a 2024 cohort induction start date |
- review, which has
RAILS_ENV=review
- staging, which has
RAILS_ENV=staging
, internal url - sandbox, which has
RAILS_ENV=sandbox
, internal url - production, which has
RAILS_ENV=production
, internal url
These are deployed using terraform. See the documentation for details on terraform and debugging in deployed environments.
In addition to a web app, some environments have a worker app for running background jobs. For details, see the terraform code.
The /healthcheck
endpoint on each deployed app will give details on things like version number, commit SHA, background jobs, and database migrations.
- Follow the debugging instructions to gain SSH access to the instance and cd to the app dir
- Run
/usr/local/bin/bundle exec rake "admin:create[user name,email@example.com]"
. For example, the command for a user namedJohn Smith
with the emailjohn.smith@example.com
would be/usr/local/bin/bundle exec rake "admin:create[John Smith,john.smith@example.com]"
.
The format here is important! Notice that there are no extra spaces in the square brackets, and no quote marks inside the square brackets
- Make sure you have copied
.env.template
to.env
and filled in the GIAS information with details from a teammate - Run
bundle exec rake schools_data:import
to import the latest schools data from GIAS. This takes around 10 minutes - Run
bundle exec rake sparsity:import
to populate the sparsity tables - Run
bundle exec rake pupil_premium:import
to populate the pupil premium tables
Note: running db:seed
schedules the schools_data:import
as a background. You can run bundle exe sidekiq
to execute this in the background.
Much like review apps, the dev database is truncated and reseeded on every merge to develop.
If the database needs to be reset for testing, there is a github action for this called Run task in dev space
.
The default parameters will reset the dev database. This action can also be used to run a rake task on dev or any review app.
Background jobs are run using sidekiq, which relies on redis. You will need to install redis and run it using:
redis-server
This should run on *:6379
, which sidekiq will expect outside of
cloudfoundry.
And start sidekiq running using:
bin/sidekiq
We use Gov.UK Notify to send emails.
We have a variety of emails that we send to schools on a regular basis. This are currently triggered manually, via rake task. The rake tasks are defined in schools.rake, for example:
bundle exec rake 'schools:send_invites[urn1 urn2 ...]'
bundle exec rake lead_provider:generate_token "name or id"
Run payment calculator for a given lead provider with an optional number of participants (default is 2,000) to generate the payment breakdown
bundle exec rake payment_calculation:breakdown "<name or id>" "<number of participants>"
Where "name or id"
is a name or id from the lead_providers
table.
- Get into Rails console for the environment you want to generate the token for.
- Run
EngageAndLearnApiToken.create_with_random_token!
- Rails console should output a string, that's your unhashed token, you can keep it and use it to access E&L endpoints.
Certain aspects of app behaviour are governed by a minimal implementation of feature flags. Feature flag states are persisted in the database with a name and an active state. To activate a new feature you can run Feature.create!(name: 'rate_limiting', active: true)
.
The available flags are listed in app/services/feature_flag.rb
, and available in the constant FeatureFlag::FEATURES
. Each one is tested with a dedicated spec in spec/features/feature_flags/
.
The code inlib/payment_calculator/ecf/
performs payment calculations for ECFs (Early Career Framework) using commercial information so that training providers can be paid the correct amount.
The calculator can generate each intermediary step in the calculation so that any questions over how the final totals were reached can be answered by interested parties.
Output from PaymentCalculation.new(contract: <ContractObject>)
will instantiate a calculator for that specific contract. This can then be called, passing in the retention event type, and total number of participants to calculate for. (There is also a class level call shortcut for this.) which means that for a one off calculation you can call PaymentCalculation.new(contract: <ContractObject>).call(event_type:, total_participants:)
, or PaymentCalculation.call({contract: <ContractObject>}, event_type:, total_participants:)
. (Note the brackets around the first hash. In this call format, that is what determines what is passed to the initializer and what goes to the call.)
Here are the names we are using in the code and specs for the different concepts involved in the calculations by way of an example:
Per participant price £995 >> per participant service fee £398 (40%) >> monthly service fee £27k >> total service fee £796k
Per participant price £995 >> per participant output payment £597 (60%) >> per participant output payment for a retention period £119 (20% (or 15% depending on the period) of 60%) >> output payment total for the retention period with 1900 retained participants £226k
- "Participants" includes both teachers and mentors.
- "Output payments" are payments made based on the performance of the training provider (i.e. their output).
- "Payment type" for start/retention_x/completion output payments.
Sometimes, we need to make manual changes to data. The reason for this change may not be obvious to those looking in the future. We version changes using PaperTrail, and when making an unusual change, we can set a reason to help those reading the change history.
To set a reason for an entire console session:
PaperTrail.request.controller_info = {reason: "some reason"}
To set a reason for a block:
PaperTrail.request(controller_info: {reason: "some reason"}) do
# do something
end
This procedure is used after a batch from manual validation has been complete. The data also needs to be uploaded to the NPQ application as it uses a different database and there is no syncing procedure in place.
- Log in to a container instance
- Save CSV data to disk via
vi
and remember the path - Start rails console
- Instantiate service with
svc = Importers::NPQManualValidation.new(path_to_csv: Rails.root.join("batchX.csv"))
- Call service with
svc.call
- Exit rails console
- Delete CSV as no longer needed
We use sentry.io for error tracking and performance monitoring. Ask a team member for access - this is done through digi-tools.
We use statuscake for uptime monitoring. Ask a team member for access - this is done with a service now ticket.
We use a gem called tech_docs_template
to generate govuk-style documentation. It is heavily inspired by Teacher Training API.
You can find it, with its readme, in docs
directory.
The project in docs
directory can be used to generate a static site, which we put in public/api-reference
to make our app serve it.