This is the backend for the Single Accommodation Service (SAS) FE
- We need
redisfor cacheing - so you will need to run a local docker infrastructure
docker compose up -d- Start application locally in
IntelliJ IDEA:- Create a
Run Configurationby runningSingleAccommodationServiceApi- This will attempt start the
SAS APISpring boot application and fail due to missing configuration
- This will attempt start the
- Edit this new
SingleAccommodationServiceApirun configuration- Set the
Active profilesfield's value tolocal - Set the
Environment variablesfield's value to:SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_DEFAULT_CLIENT-ID=<secret-value>;SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_DEFAULT_CLIENT-SECRET=<secret_value>
- Set the
- Swap out the
<secret-value>values above for the actual secrets held ink8s secrets- seeInfrastructuresection below for how to runk8scommands RuntheSingleAccommodationServiceApirun configuration again- the result should be a running application (you should see in the application logs that it is deployed on port
8080)
- the result should be a running application (you should see in the application logs that it is deployed on port
- Create a
- We need a test database running - so you will need to run a local docker infrastructure
docker compose up -d- The following
gradle commandwill build the application and run the tests
./gradlew check- At the early stages of this project it's best to look at
CaseController.getCases()endpoint as this follows the standards set out below implementing the correctn-tier architecturerequired (i.e.CaseController -> CaseService -> CaseOrchestration - AggregatorService) - Best practice testing standards have been included for this endpoint (inc. unit tests / integration tests)
-
All HTTP calls to upstream services are made through the
AggregatorService- The
AggregatorServiceis located in theaggregatorsubmodule of this repository - You will see examples of how this is achieved in the
CaseOrchestrationservice - Regardless of whether you are making a number of async calls, or a single synchronous one, the standard is to make all calls through the public function in the
AggregatorService- you should not need to make any changes to the
AggregatorService— hopefully it gives you everything you need!
- you should not need to make any changes to the
- Only services in the
Orchestration layershould inject theAggregatorService
- The
-
Orchestration layerinn-tier architecture- Resulting flow:
*Controller -> *Service -> *OrchestrationService -> AggregatorService - Example in repository:
CaseController -> CaseService -> CaseOrchestration -> AggregatorService - The
Orchestration layerwill be made up of@Serviceclasses named*OrchestrationServiceand their job is to:- Inject the
AggregatorService - Help orchestrate the async (and synchronous) calls using the
AggregatorService - Return an
*OrchestrationDtodata class that holds*Dtoresponses from the upstream services - Hard rules:
- Only retrieve and return the data in this layer please!
- No business-logic should sit in this layer
- Do not unit test this layer (covered by integration tests)
- The big plus here is that when we release a new version of the
AggregatorServicein theaggregatorsubmodule it will:- Only have rippling effects on the
Orchestration layer- We will only need to refactor implementation code in the
Orchestration layer - No unit test refactoring will be neccesary
- The integration tests will give us coverage on the
AggregatorServiceitself and need no refactoring either
- We will only need to refactor implementation code in the
- Only have rippling effects on the
- Inject the
- Resulting flow:
-
The
Servicelayer that sits in between the*Controllerand*OrchestrationServicecan be unit tested in the usual way with themockklibrary
- There are linting and static analysis checks in the build pipeline. You can lint and check for issues by running
./gradlew ktlintFormat && ./gradlew detektThe service is deployed to the MoJ Cloud Platform. This is
managed by Kubernetes and Helm Charts which reside within this repo at ./helm_deploy.
To get set up with Kubernetes and configure your system so that the kubectl command authenticates, see this
[MoJ guide to generating a 'kube' config].
You should then be able to run kubectl commands, e.g. to list the 'pods' in a given 'namespace':
$ kubectl -n hmpps-community-accommodation-dev get pods
NAME READY STATUS RESTARTS AGE
hmpps-single-accommodation-service-api-655968557b-5qlbc 1/1 Running 0 83m
hmpps-single-accommodation-service-api-655968557b-bp7v9 1/1 Running 0 83m
hmpps-single-accommodation-service-ui-67b49b8dcd-p85pt 1/1 Running 0 125m
hmpps-single-accommodationn-service-ui-67b49b8dcd-tgjd5 1/1 Running 0 125mNB: this kubectl cheatsheet is a good reference to
other commands you may need.
Details of the different environments and their roles can be found in Confluence.
Our release process aligns with the other CAS teams and as such lives in Confluence. The steps are also available in the pull request checklistPULL_REQUEST_TEMPLATE.