Service that supports the creation of FHIR Packages using GitLab API for storing information as repo
78
Backend service for the Template Editor.
See ReleaseNotes.md for all information regarding the (newest) releases.
This open source project was developed in cooperation with the German Federal Institute for Drugs and Medical Devices (BfArM) on the basis of Section 355 (12-14) of the German Social Code Book V (SGB V). As part of the projects implementation, the fbeta GmbH and Fraunhofer FOKUS were commissioned to provide software development services.
We would like to thank all parties involved for their constructive and trusted collaboration.
You can build the project from the command line using Gradle.
Note: Make sure to have Gradle installed and configured in your PATH.
gradle build
Benchmarks are implemented using JMH (Java Microbenchmark Harness). To run the benchmarks, follow the instructions from: Benchmark Setup
oauth2-proxy handles user authentication before traffic reaches this service.
The backend does not start an OAuth flow, does not exchange authorization codes, and does not issue or manage its own tokens.
Every protected request must contain the GitLab access token forwarded by
oauth2-proxy:
X-Forwarded-Access-Token: <gitlab-access-token>
The same token is forwarded unchanged to GitLab API calls.
The backend must not be exposed directly. It is expected to be reachable only
through oauth2-proxy. The proxy must strip or overwrite incoming
X-Forwarded-* headers from clients.
oauth2-proxy should also forward user headers:
X-Forwarded-User: <username>
X-Forwarded-Email: <email>
X-Forwarded-Groups: reviewers,dev/publishers
X-Forwarded-Groups is used for reviewer checks. If the groups header is not
present, the service falls back to GitLab /oauth/userinfo with the Bearer token.
| Variable | Default | Description |
|---|---|---|
GITLAB_BASE_URL | https://gitlab.terminologien.bfarm.de | GitLab base URL |
GITLAB_USERINFO_PATH | /oauth/userinfo | Userinfo path used as fallback for groups/user data |
GITLAB_GROUP_PATH_ID | 17954 | GitLab group/project path used by the adapters |
GITLAB_REVIEWERS_GROUP | Reviewers | Reviewer group name/path suffix |
CORS_ALLOWED_ORIGINS | http://localhost | Allowed browser origin |
SERVER_PORT | 8080 | Application HTTP port |
MANAGEMENT_PORT | 8081 | Actuator port |
HTTP_CONNECTION_TIMEOUT | 120 | GitLab HTTP timeout in seconds |
Only infrastructure and documentation endpoints are public:
/actuator/**/ping/v3/api-docs/v3/api-docs.yaml/swagger-ui.html/swagger-ui/**All application endpoints require a forwarded GitLab access token.
The system implements a two-tier role model:
GITLAB_REVIEWERS_GROUPCORS is configured to allow requests only from CORS_ALLOWED_ORIGINS, with methods limited
to GET, POST, DELETE. This means PUT and PATCH are not allowed from the browser.
| Method | Path | Description |
|---|---|---|
GET | /auth/userinfo | Information about the currently authenticated user, including backend reviewer mapping. |
| Method | Path | Description |
|---|---|---|
GET | /projects | Returns a paginated, searchable list of terminology projects |
| Method | Path | Description |
|---|---|---|
GET | /projects/{projectId}/versions | Lists available terminology versions for a project |
DELETE | /projects/{projectId}/versions/{version} | Deletes a terminology version (not available to reviewers) |
| Method | Path | Description |
|---|---|---|
GET | /workspaces | Lists branches (workspaces) for a repository |
GET | /workspaces/details | Returns full workspace details for a branch and version |
POST | /workspaces/commit | Commits a batch of file changes; optionally creates a merge request |
POST | /workspaces/commitFile | Uploads, validates and commits a single file (ZIP / FHIR JSON / FHIR XML) |
POST | /workspaces/review | Opens a merge request for a branch (without commit) |
GET | /workspaces/openByMR | Opens a workspace using a merge request IID |
The POST /workspaces/commitFile endpoint validates the uploaded file, based on its content type:
.zip files are validated by checking the ZIP magic bytes.json files are validated as FHIR JSON (root resourceType must be ValueSet, ConceptMap, or CodeSystem).xml files are validated as FHIR XML (root element must be ValueSet, ConceptMap, or CodeSystem)To avoid excessive heap memory usage during large file uploads, the commitFile
endpoint uses a temp-file streaming strategy instead of buffering the entire file in memory:
UPLOAD_TEMP_DIR (default: /tmp) via FilePart.transferTo(). This keeps heap
usage near zero during the upload phase.InputStream-based methods — only
the minimum data needed is read (e.g., 4 bytes for ZIP magic number checks). The raw file
bytes are never fully loaded into heap memory.Base64.getEncoder().wrap()), producing the encoded string via a scoped
ByteArrayOutputStream. The intermediate buffer is eligible for GC immediately after the
string is produced, keeping peak memory to roughly 1× the Base64 output size.GitLabCommitAction, bypassing the intermediate CommitRequest / CommitChange
wrapper chain to avoid unnecessary object copies.Mono.usingWhen).As the only requirement, the UPLOAD_TEMP_DIR must point to a writable volume, typically larger more than twice than
the defined VALIDATION_COMMIT_CONTENT_MAX_SIZE.
| Method | Path | Description |
|---|---|---|
GET | /workspaces/comments | Lists inline review comments for a merge request |
POST | /workspaces/comments | Creates an inline review comment |
POST | /workspaces/comments/reply | Replies to an existing comment thread; optionally resolves it |
| Method | Path | Description |
|---|---|---|
GET | /reviews | Lists merge requests across the group (filterable by state) |
POST | /reviews/approve | Approves and auto-merges a merge request (reviewer role required) |
Runs separately on port 8081 with base path
/actuator. All management endpoints are read-only.
| Method | Path | Description |
|---|---|---|
GET | /actuator | Overview of available management endpoints |
GET | /actuator/health | Health status (liveness + readiness probes) |
GET | /actuator/metrics | Lists metrics |
GET | /actuator/prometheus | Prometheus metrics export |
GET | /actuator/info | Info endpoint (includes management.info.env.enabled) |
GET | /actuator/sbom | Software Bill of Materials (when available) |
| Method | Path | Description |
|---|---|---|
GET | /v3/api-docs | OpenAPI specification (JSON) |
GET | /v3/api-docs.yaml | OpenAPI specification (YAML) |
GET | /swagger-ui.html | Swagger UI |
The service applies several safeguards to minimize heap memory usage, especially during file uploads and workspace-detail fetching.
A PayloadSizeLimitFilter (WebFilter) rejects non-multipart POST/PUT requests whose
Content-Length exceeds 10 MB, the same limit as spring.http.codecs.max-in-memory-size.
This provides early rejection before the body is deserialized, preventing oversized JSON
payloads from consuming heap memory. Multipart uploads are excluded because they are streamed
to disk.
FileTypeValidator provides InputStream-based overloads for all validation methods
(isFileTypeZip, isValidFhirJson, isValidFhirXml). These avoid loading the full file
byte[] into heap:
A new DocumentBuilder is created per XML parse call to avoid thread-safety issues
with the shared (non-thread-safe) DocumentBuilder class.
GitLabClient.fetchFileText() uses a StringBuilder-based Flux.collect() instead of
collectList() + joinToString(). This avoids creating an intermediate List<String> and
a second full copy of the file content.
All unbounded flatMap calls in DetailFetcher (template JSONs, markdown files, input
file metadata) are limited to a concurrency of 4. This bounds the number of files held
in memory simultaneously, preventing heap exhaustion when workspaces contain many templates.
GitLabClient caches the base WebClient instance (built from the injected
WebClient.Builder) and uses mutate() for per-request authorization headers. This avoids
rebuilding the WebClient on every API call and reduces GC pressure under high concurrency.
An up-to-date OpenAPI specification can be found at:
dokumentation/openapi.yaml
It describes all existing endpoints including request/response structures.
The current workflow specification can be found at:
dokumentation/mermaid/*.mmd
If you want to contribute, please check our CONTRIBUTING.md.
Copyright 2026 gematik GmbH
Apache License, Version 2.0
See the LICENSE for the specific language governing permissions and limitations under the License
We take open source license compliance very seriously. We are always striving to achieve compliance at all times and to improve our processes. This software is currently being tested to ensure its technical quality and legal compliance. Your feedback is highly valued. If you find any issues or have any suggestions or comments, or if you see any other ways in which we can improve, please reach out to: [email protected].
Content type
Image
Digest
sha256:1ec84e1c9…
Size
192.7 MB
Last updated
7 days ago
docker pull gematik1/template-editor-service