1. Overview
1.1. Accessing Swagger UI
Many services expose a Swagger UI on port 80 and the path
/swagger-ui/index.html. Use docker ps to find the host port mapping:
docker ps --format 'table {{.Names}}\t{{.Ports}}'
If a container’s port 80 is mapped to 9130 you would access Swagger using the
URL http://localhost:9130/swagger-ui/index.html.
1.2. Folder Structure
This project has the following folders:
| Folder | Content | Description |
|---|---|---|
client/ |
Client-side components |
Simulated client applications |
├─ card-terminal-client-simservice/ |
Electronic health card terminal simulator |
|
└─ vsdm-client-simservice-java/ |
VSDM2 client simulator |
|
server/ |
Server-side components |
Backend services and proxies |
├─ popp-server-mockservice/ |
PoPP token generation service |
|
├─ vsdm-server-simservice/ |
VSDM2 data provider |
|
├─ zeta-pdp-server-mockservice/ |
Zero Trust Policy Decision Point |
|
└─ zeta-pep-server-mockservice/ |
Zero Trust Policy Enforcement Point |
|
lib/ |
Reusable libraries |
Shared functionality across services |
├─ card-client-lib-java/ |
Card terminal operations library |
|
├─ popp-client-lib-java/ |
PoPP authentication client library |
|
├─ vsdm-fhir-lib-java/ |
FHIR resource handling for VSDM |
|
└─ zeta-client-lib-java/ |
ZeTA integration utilities |
|
test/ |
Test suites |
Integration and end-to-end tests |
└─ vsdm-testsuite/ |
VSDM2 workflow test suite |
|
doc/ |
Documentation and scripts |
Build and deployment automation |
├─ bin/vsdm/ |
Build and Docker Compose scripts |
|
├─ docker/vsdm/ |
Docker Compose configuration |
|
└─ k8s/ |
Kubernetes deployment manifests |
|
images/ |
Static assets |
Images for README documentation |
jenkinsfiles/ |
CI/CD pipelines |
Jenkins pipeline definitions |
2. Example Workflows using Curl
2.1. VSDM Data Retrieval
curl -X GET 'http://localhost:8220/vsdm/data' \
-H 'Authorization: Bearer <ACCESS_TOKEN>'
2.2. Card Terminal Operations
curl -X POST 'http://localhost:8000/card/load' \
-H 'Content-Type: application/json' \
-d '{"cardPath": "cards/egk/valid-egk.xml"}'
2.3. Token Exchange (OAuth 2.0 RFC 8693)
curl -X POST 'http://localhost:9100/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token=<SMC_B_TOKEN>&subject_token_type=urn:ietf:params:oauth:token-type:access_token'
3. Configuration
3.1. Environment Variables
Each service can be configured via environment variables. Key configuration options:
3.1.1. ZeTA PEP Services
-
PROXY_HTTP_URL- Backend HTTP URL to proxy requests to -
PROXY_WS_URL- Backend WebSocket URL to proxy requests to -
PROXY_POPP_REQUIRED- Whether PoPP token validation is required (true/false) -
WK_ISSUER- OAuth 2.0 issuer URL -
WK_AUTH_EP- Authorization endpoint -
WK_TOKEN_EP- Token endpoint
3.2. Docker Compose Profiles
The Testhub supports different startup profiles for various use cases:
| Profile | Description |
|---|---|
(default) |
Backend + Tiger-Proxies + Clients via proxy. Use this for normal development and testing. |
|
Backend + Tiger-Proxies + Clients with direct backend access. Use this for performance testing as it bypasses the Tiger-Proxy. |
|
Backend services only (no Tiger-Proxies, no clients). Use this when you want to run your own client implementation against the backend. |
3.2.1. Starting with Profiles
Use Docker Compose with the appropriate profile:
# Build Docker images first
./mvnw clean install -Pdocker -DskipTests
# Start full stack (default)
docker compose -f doc/docker/compose-local.yaml up -d
# Start with performance profile (clients bypass Tiger-Proxy)
docker compose -f doc/docker/compose-local.yaml --profile perf up -d
# Start backend only (no clients)
docker compose -f doc/docker/compose-local.yaml --profile backend-only up -d
# Stop all containers (all profiles)
docker compose -f doc/docker/compose-local.yaml --profile perf --profile backend-only down -v
4. Architecture
The Testhub implements a Zero Trust Architecture with multiple layers of services communicating through authenticated channels.
4.1. Key Components
The Testhub consists of several interconnected services:
Client Services:
-
VSDM Client SimService - Simulates VSDM2 client operations
-
Card Terminal Client SimService - Simulates electronic health card (eGK) terminal operations
Server Services:
-
VSDM Server SimService - Provides VSDM2 data for testing
-
PoPP Server MockService - Simulates Proof of Possession authentication server
-
ZeTA PDP Server MockService - Policy Decision Point for Zero Trust Architecture
-
ZeTA PEP Server MockService - Policy Enforcement Point proxy service
Libraries:
-
Card Client Library - Reusable card terminal operations
-
PoPP Client Library - PoPP authentication client functionality
-
VSDM FHIR Library - FHIR resource handling for VSDM
-
ZeTA Client Library - ZeTA integration utilities
All components are designed as mock/simulation services for development and testing purposes, not for production use.
4.3. Service Descriptions
| Service | Purpose |
|---|---|
Card Terminal Client |
Simulates electronic health card (eGK, SMC-B, HBA) terminal operations with PACE protocol support |
VSDM Client |
Simulates VSDM2 client operations including data retrieval and PoPP token validation |
ZeTA PEP PoPP |
Policy Enforcement Point proxy for PoPP validates tokens and forwards requests |
ZeTA PDP PoPP |
Policy Decision Point for PoPP performs OAuth 2.0 token exchange (RFC 8693) |
PoPP Server |
Backend PoPP service generates and validates Proof of Possession tokens |
VSDM Server |
Backend VSDM service provides VSDM2 data from YAML test fixtures |
Tiger Proxy UI |
Local Tiger Proxy between PS-Simulation and PoPP and VSDM-Servers |
The services are exposed on different ports to the local environment.
To access the containers when applicable, use the following script to find the host port mapping:
docker ps --format 'table {{.Names}}\t{{.Ports}}'
5. How to integrate custom PS (Primärsystem)
|
ZETA is only configured for the VSDM-Server, not the PoPP-Server. |
Integrating a custom Primärsystem (PS) is a primary design goal of the TI 2.0
Testhub. Currently, however, it requires some manual steps:
-
Start the Testhub with the
backend-onlyprofile to disable the built-in PS-Simulators (VSDM Client and Card Terminal Client):
docker compose -f doc/docker/compose-local.yaml --profile backend-only up -d
-
The custom PS has to be started (e.g. add as a new service in
doc/docker/backend/compose-local.yaml, but could simply be started outside of
docker compose as well) -
Optional: To use the PS with the VSDM-Testsuite it has to implement the same
API as the existing vsdm-client (which can be seen at
http://localhost:8220/v3/api-docs)
You can connect to the resource servers as follows:
- VSDM-Server
-
Use the port that is forwarded to the internal port 443 of
vsdm-zeta-ingress. If the port is 9119 you can connect from the Docker host
using https://localhost:9119/. - PoPP-Server
-
Use the port that is forwarded to the internal port 80 of
popp-ingress.
The usage of the Zeta-SDK can be seen in the existing
vsdm-client-simservice-java implementation. The class ZetaSdkClientAdapter.java
uses the client while VsdmZetaSdkClientConfig.java configures it.
6. How to integrate VSDM services
6.1. Scenario 1: Replace the Resource Server behind ZetaGuard
If you only want to replace the Resource Server (keeping ZetaGuard as PEP/proxy), follow these steps.
6.1.1. Prerequisites
-
The external resource server must be started and reachable from the Testhub instance.
6.1.2. Steps
-
Make sure the vsdm server simulation is not started in the compose setup.
# File: compose-vsdm-server.yaml (or the compose file that contains the vsdm server)
# Example: comment out the block for the vsdm-server
# vsdm-server:
# image: ...
# ports:
# - "80:8080"
-
In the Testhub compose settings: under the block that describes the PEP (e.g.
vsdm-zeta-pep), remove or comment out the dependency on the internalvsdm-server(depends_on).
# Example: in compose-vsdm-server.yaml or compose-local.yaml
# under vsdm-zeta-pep:
# depends_on:
# - vsdm-server
# => comment out or remove
-
Configure the PEP so that it forwards to the external (real) Resource Server.
Edit the vsdm-zeta-pep.conf file and replace the proxy_pass line:
# Before (local vsdm-server in compose):
proxy_pass http://vsdm-server:80/;
# After (real resource server):
proxy_pass http://URL_TO_REAL_SERVER/;
Tip: Pay attention to the trailing / and to TLS (https://…;) when required.
6.2. Scenario 2: Replace the complete domain service (ZetaGuard + Resource Server)
If the complete domain service (ZetaGuard and the Resource Server) is operated externally, follow these steps.
6.2.1. Prerequisites
-
The external domain service (ZetaGuard + Resource Server) must be started and reachable from the Testhub instance.
6.2.2. Steps
-
Do not start the internal simulations: both the vsdm server simulation and the internal ZetaGuard must not be started in the compose configuration.
# In compose-local.yaml: comment out the include of compose-vsdm-server.yaml
# - include: compose-vsdm-server.yaml
-
Replace the
vsdm-zeta-ingressentry intiger.yaml(or the file that defines the ingress / routing for vsdm) with the URL of the domain service.
# File: tiger.yaml
# Before:
vsdm-zeta-ingress: http://vsdm-zeta-ingress
# After:
vsdm-zeta-ingress: http://URL_TO_DOMAIN_SERVICE
-
Adjust the client configuration: in
vsdm-client/application-local.yamlconfigure theresourceServerUrlto the URL of the external vsdm-zeta-pep service or directly to the domain service, depending on your architecture.
# File: vsdm-client/application-local.yaml
resourceServerUrl: "http://URL_TO_VSDM_ZETA_PEP/"
Note: If the external domain service uses TLS, use https://…; and make sure certificates / CA trust are configured accordingly.
6.3. Examples and useful commands
-
Search the compose files for
vsdm-server,vsdm-zeta-peporvsdm-zeta-ingressto quickly find the relevant blocks:
grep -R "vsdm-server\|vsdm-zeta-pep\|vsdm-zeta-ingress" -n .
-
Example: simple change with sed (local; check with git diff first):
# Replace proxy_pass line in vsdm-zeta-pep.conf (create backup first!)
cp vsdm-zeta-pep.conf vsdm-zeta-pep.conf.bak
sed -i.bak "s|proxy_pass http://vsdm-server:80/;|proxy_pass http://URL_TO_REAL_SERVER/;|g" vsdm-zeta-pep.conf
6.4. Notes / Troubleshooting
-
After changes to compose files always restart the affected containers (e.g.
docker compose down && docker compose up -dfor the changed services). -
Test reachability of the external service from the Testhub instance (e.g.
curlfrom the host/container). -
Pay attention to CORS, authentication and TLS settings if clients report errors when accessing the external service.
6.5. Summary
This document shows the minimal changes required to either replace only the Resource Server behind ZetaGuard or to operate the complete domain service (ZetaGuard + Resource Server) externally.
The main changes are:
-
Commenting out/removing the internal simulations in the compose files
-
Adjusting
proxy_passinvsdm-zeta-pep.conf -
Replacing ingress/URL references in
tiger.yamlandvsdm-client/application-local.yaml
7. FAQ / Troubleshooting
7.1. Testhub
7.1.1. Why are there so many files in the SMC-B ZIP file?
The ZIP file structure is used for many other processes connected with the Gematik.
It’s currently not possible to change this process for Testhub.
7.1.2. An Ant BuildException has occured…
This is usually caused by a configuration issues when building the Docker images.
Look further up for the relevant error message around the task create-docker-image and check the Docker section below.
7.1.3. E2E tests are not starting with port exception
When running the E2E tests you can run into an error claiming that a port is taken:
*************************** APPLICATION FAILED TO START *************************** Description: Web server failed to start. Port 6800 was already in use. Action: Identify and stop the process that's listening on port 6800 or configure this application to listen on another port. TGR Workflow UI is active, please press quit in browser window... TGR Destroying spring boot context after testrun... TGR Tiger shut down orderly [ERROR] Failed to start bean 'webServerStartStop'
This happens when you are using the Tiger Workflow UI and you didn’t press the power off button in the Workflow UI. To fix the issus:
-
Press the red power button in the Workflow UI and try again
-
Kill the process listening on the port mentioned by YOUR error message. Note that port configurations can change and the above error message is for illustration only.
7.1.4. The Tiger Workflow UI runs into timeouts on startup
Due to performance constraints it’s possible that there is not enough time for the Workflow UI and E2E tests to start in a timely manner:
15:29:57.034 [main ] INFO d.g.t.t.c.w.TigerBrowserUtil - Starting Workflow UI via 'xdg-open http://localhost:6800' 15:29:57.052 [main ] INFO d.g.t.t.c.w.TigerBrowserUtil - Workflow UI http://localhost:6800 15:29:57.052 [main ] INFO d.g.t.t.l.TigerDirector - Waiting 10 seconds for workflow Ui to fetch status...
You can try:
-
to increase the setting
lib.workflowUiStartTimeoutInSecondsin the filetiger.yaml. -
to set
lib.activateWorkflowUi: falsein the filetiger.yaml.
For more information on how to configure Tiger check the Tiger User Manual.
7.2. Docker
7.2.1. The name "xyz" is already in use by container …
Occasionally you might encounter an error like:
Error response from daemon: Conflict. The name "vsdm-client" is already in use by container f9e5798a82e0.
-
It’s possible that you are running a container with the same name.
You have to rename or remove it. -
It’s possible that a previous Testhub start wasn’t cleaned properly.
First remove the remaining containers and then restart Testhub:docker compose -f ./doc/docker/compose-local.yaml down -v docker compose -f ./doc/docker/compose-local.yaml --profile full up -d --remove-orphans
7.2.2. Authentication for pulling Docker images
Testhub components are povided as public Docker images.
Authentication with a registry is not neccessary.
Depending on your Docker configuration you may run into authentication issues such as these:
ERROR: (gcloud.auth.docker-helper) There was a problem refreshing your current auth tokens: Reauthentication failed. cannot prompt during non-interactive execution. Please run: $ gcloud auth login
This issue is NOT related to Testhub.
To fix the problem either:
-
Authenticate using your credential helper such as the
gcloudCLI -
Remove the relevant settings from your docker configuration
7.2.3. No feedback from workflow Ui, aborting!
If you see this error, the tiger framework was not able to reach the browser within the expected time.
This usually happens when the Testhub is started on a machine with limited resources or the browser setup is somewhat slow.
You should have a browser window open with the Testhub UI, but it might stay blank for a while.
If this happens try to reload that tab.
If you don’t see this tab at all, check if the Testhub is running and try to open http://localhost:6800/ in your browser.
The timeout is set to 120 seconds, so if you can open the UI within that time frame, you should be able to start the workflow without any issues.
If you are still running into problems, try to increase the timeout in the file tiger.yaml (search for "workflowUiStartTimeoutInSeconds" and increase the value).
7.2.4. permission denied while trying to connect to the Docker daemon socket…
Ensure you are following the post-install steps as outlined by dockerdocs, especially on how to use Docker as a non-root user:
https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user
7.3. Windows PowerShell
7.3.1. Issues with running commands with parameters in PowerShell
If you are running into issues with running commands with parameters in PowerShell, try to use PowerShell’s passthrough mechanism for arguments with the "stop parsing" symbol --% to prevent PowerShell from interpreting the parameters as its own.
For example, instead of running
./mvnw -pl test/vsdm-testsuite/ -Dit.test="Vsdm*IT" -Dskip.inttests=false verify
which may lead to
[ERROR] Unknown lifecycle phase "Vsdm*IT". You must specify a valid lifecycle phase [...]
try to run it with the passthrough --% symbol
./mvnw --% -pl test/vsdm-testsuite/ -Dit.test="Vsdm*IT" -Dskip.inttests=false verify
which should prevent PowerShell from interpreting the -Dit.test parameter as its own and instead pass it correctly to the mvnw command.