Java service built with the Spring WebFlux reactive stack.
Requires the all but backend to be running in docker:
# optionally add -d or --detached for detached mode
../run.sh dev --no-backend
Start backend with IntelliJ:
- Use the checked in run config in
../.idea/runConfigurations/
. If you open just thisbackend
folder with IntelliJ, you will need to copy and adjust it.
Start backend with VS Code:
- The launch config in
.vscode/launch.json
should be used automatically
Start backend from CLI:
SPRING_PROFILES_ACTIVE=local ./gradlew bootRun
Note
The application depends on a Java package from a private GitHub package repository. To be able to download it in the Gradle build process, you'll need to set up your local env as described in the root readme.
Some dropdown menus in the frontend get populated via calls to the backend that query the respective database tables. If you are developing locally and want to see values in those dropdown menus you need to do this one-time step: trigger the import of XML files to these database tables. Furthermore, some e2e tests are testing this behaviour. Those will fail locally if your lookup tables are not populated.
To import the XML files, follow these steps:
- Download the XML files
doktyp.xml
,gerichtdata_gesamt.xml
,buland.xml
,sachneudata_gesamt.xml
,zitartdata_gesamt.xml
(Link in the Engineering Onboarding Wiki) - Start the application (see root README), open it in your browser and log in
- Copy the
SESSION
cookie value from the Browser Developer Tools --> Application Tab --> Cookies (If you prefer using Postman, it also supports importing cookies from your browser.)
Fill these variables with your values:
export PATH_TO_XML_FILES="/path/to/xml/files" # where you placed the xml files
export SESSION_VALUE="your-session-cookie-value" # copied from Browser Developer Tools
export HOST="http://127.0.0.1" # backend host
Then do the requests with curl:
curl -v -X PUT -H 'Content-Type: application/xml' -H "cookie: SESSION=$SESSION_VALUE" --data "@$PATH_TO_XML_FILES/doktyp.xml" $HOST/api/v1/caselaw/lookuptableimporter/doktyp
curl -v -X PUT -H 'Content-Type: application/xml' -H "cookie: SESSION=$SESSION_VALUE" --data "@$PATH_TO_XML_FILES/gerichtdata_gesamt.xml" $HOST/api/v1/caselaw/lookuptableimporter/gerichtdata
curl -v -X PUT -H 'Content-Type: application/xml' -H "cookie: SESSION=$SESSION_VALUE" --data "@$PATH_TO_XML_FILES/buland.xml" $HOST/api/v1/caselaw/lookuptableimporter/buland
curl -v -X PUT -H 'Content-Type: application/xml' -H "cookie: SESSION=$SESSION_VALUE" --data "@$PATH_TO_XML_FILES/sachneudata_gesamt.xml" $HOST/api/v1/caselaw/lookuptableimporter/fieldOfLaw
curl -v -X PUT -H 'Content-Type: application/xml' -H "cookie: SESSION=$SESSION_VALUE" --data "@$PATH_TO_XML_FILES/zitartdata_gesamt.xml" $HOST/api/v1/caselaw/lookuptableimporter/zitart
curl -v -X PUT -H "cookie: SESSION=$SESSION_VALUE" http://127.0.0.1/api/v1/caselaw/normabbreviation/refreshMaterializedViews
The application uses Flyway for maintaining and versioning database migrations. In order to create a change in the database you should follow one of the two methods:
- If you want to create a migration using SQL:
- You should create a new sql file on the directory
src\main\resources\db\migration
. - The file should be named in the following format:
Vx.x__teamname_create_table_xyz.sql
wherex.x
is your migration version (make sure to pull first from the repository and see what is the latest version otherwise migrations wouldn't work properly).
- You should create a new sql file on the directory
- If you want to create a migration using Java:
- You should create a new Java class on the directory
src\main\java\db\migration
that extendsBaseJavaMigration
and implements the methodvoid migrate(Context context) throws Exception
. - The file should be named in the following format:
Vx_x__teamname_create_table_xyz.sql
wherex_x
is your migration version (make sure to pull first from the repository and see what is the latest version in the sql path and the java path otherwise migrations wouldn't work properly).
- You should create a new Java class on the directory
For both migration file names, the teamname
can be replaced with: whether caselaw
or norms
and is normally followed by a descriptive name for the migration.
Flyway automatically detects new files and run migrations accordingly on sprint boot start.
The project has distinct unit and integration test sets.
To run just the unit tests:
./gradlew test
To run the integration tests:
./gradlew integrationTest
Note
Running integration tests requires passing unit tests (in Gradle terms: integration tests depend on unit tests), so unit tests are going to be run first. In case there are failing unit tests we won't attempt to continue running any integration tests.
To run integration tests exclusively, without the unit test dependency:
./gradlew integrationTest --exclude-task test
Denoting an integration test is accomplished by using a JUnit 5 tag annotation: @Tag("integration")
.
Furthermore, there is another type of test worth mentioning. We're using ArchUnit for ensuring certain architectural characteristics, for instance making sure that there are no cyclic dependencies.
Check our Java Styleguides document. To set up IntelliJ IDEA follow these instructions. Consistent formatting, for Java as well as various other types of source code, is being enforced via Spotless.
Check formatting:
./gradlew spotlessCheck
Autoformat sources:
./gradlew spotlessApply
Continuous code quality analysis is performed in the pipeline upon pushing to trunk; it requires a
token provided as SONAR_TOKEN
repository secret that needs to be obtained from https://sonarcloud.io.
To run the analysis locally:
SONAR_TOKEN=[sonar-token] ./gradlew sonarqube
Go to https://sonarcloud.io for the analysis results.
Container images running the application are automatically published by the pipeline to the GitHub Packages Container registry.
To run the latest published image:
docker run -p8080:8080 "ghcr.io/digitalservicebund/ris-backend-service:$(git log -1 origin/main --format='%H')"
The service will be accessible at http://localhost:8080
.
We are using Spring's built-in support for producing an optimized container image:
./gradlew bootBuildImage
docker run -p8080:8080 ghcr.io/digitalservicebund/ris-backend-service
Container images in the registry are signed with keyless signatures.
To verify an image:
COSIGN_EXPERIMENTAL=1 cosign verify "ghcr.io/digitalservicebund/ris-backend-service:$(git log -1 origin/main --format='%H')"
If you need to push a new container image to the registry manually there are two ways to do this:
Via built-in Gradle task:
export CONTAINER_REGISTRY=ghcr.io
export CONTAINER_IMAGE_NAME=digitalservicebund/ris-backend-service
export CONTAINER_IMAGE_VERSION="$(git log -1 --format='%H')"
CONTAINER_REGISTRY_USER=[github-user] CONTAINER_REGISTRY_PASSWORD=[github-token] ./gradlew bootBuildImage --publishImage
Note: Make sure you're using a GitHub token with the necessary write:packages
scope for this to work.
Using Docker:
echo [github-token] | docker login ghcr.io -u [github-user] --password-stdin
docker push "ghcr.io/digitalservicebund/ris-backend-service:$(git log -1 --format='%H')"
Note: Make sure you're using a GitHub token with the necessary write:packages
scope for this to work.
Scanning container images for vulnerabilities is performed with Trivy
as part of the pipeline's build
job, as well as each night for the latest published image in the container
repository.
To run a scan locally:
./gradlew bootBuildImage
trivy image --severity HIGH,CRITICAL ghcr.io/digitalservicebund/ris-backend-service:latest
License scanning is performed as part of the pipeline's build
job. Whenever a production dependency
is being added with a yet unknown license the build is going to fail.
To run a scan locally:
./gradlew checkLicense
Can be used to show the latest release version for every dependency. Generate a report in build/dependencyUpdates/report.txt
.
To run a scan locally:
./gradlew dependencyUpdates -Drevision=release