{"id":21888604,"url":"https://github.com/swisscom/cdr-client","last_synced_at":"2025-08-10T03:37:46.486Z","repository":{"id":244775858,"uuid":"800407356","full_name":"swisscom/cdr-client","owner":"swisscom","description":"The Swisscom Health Confidential Data Routing (CDR) Client","archived":false,"fork":false,"pushed_at":"2025-08-04T16:43:55.000Z","size":9091,"stargazers_count":1,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2025-08-04T20:02:59.356Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/swisscom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-05-14T09:21:06.000Z","updated_at":"2025-08-04T09:48:29.000Z","dependencies_parsed_at":"2025-03-22T02:29:31.333Z","dependency_job_id":"f6012905-9047-4468-b478-4b36c105a0b2","html_url":"https://github.com/swisscom/cdr-client","commit_stats":null,"previous_names":["swisscom/cdr-client"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/swisscom/cdr-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swisscom%2Fcdr-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swisscom%2Fcdr-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swisscom%2Fcdr-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swisscom%2Fcdr-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/swisscom","download_url":"https://codeload.github.com/swisscom/cdr-client/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swisscom%2Fcdr-client/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269672472,"owners_count":24457115,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-28T11:16:03.949Z","updated_at":"2025-08-10T03:37:46.474Z","avatar_url":"https://github.com/swisscom.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CDR Client\n\nThe Swisscom Health curaLINE Data Routing (CDR) Client.\n\nThe project is split into two parts:\n1. the client service, which is the actual client that connects to the CDR API and\n2. the client UI, which can be used to configure the client service and monitor its status\n\nOn a Linux system, the service part runs as a systemd unit. On a Windows system it runs as a Windows service \n(wrapped by [winsw](https://github.com/winsw/winsw)).\n\nOn macOS, the client UI application starts the client service and shuts it down again when itself is shut down.\n\n## Installation / Run the client\n\n\u003e Improvements for the installation are work in progress. For now, the client is only available as a jar file with\n\u003e manual\n\u003e steps\n\u003e required for the installation.\n\nPre-Requirements:\n\n* Java 17 (or higher) installed\n\nGo to the [releases](https://github.com/swisscom/cdr-client/releases) github page and click on the maven assets for the newest release:\n![releases assets overview](./installation/releases-overview.png)\nDownload the jar file:\n![release jar download](./installation/single-release-overview.png)\nPlace a file named application-customer.yaml in the same directory as the jar file. The application-customer.yaml file\nshould contain the configuration for the client. An example can be found [here](#application-customer-yaml-example).\n\nOpen a terminal and navigate to the directory where the jar file is located. Run the following command to start the\nclient (check the jar name and replace it in the command or rename the jar itself):\n\u003e The -D parameters need to be placed before the \"-jar cdr-client.jar\".\u003cp\u003e\n\u003e The quotes are necessary for Windows, but not for Unix systems\n\n```shell\njava \"-Dspring.config.additional-location=./application-customer.yaml\" -jar cdr-client.jar\n```\n\nCheck that no error messages are present in the terminal (or have a look at the \"cdr-client.log\" file that is created in\nthe same directory as you've placed the jar file) and that the client is running.\n\nConfigure an OS appropriate service to run the client as a background service.\n\n## API\n\nA scheduler triggers document downloads from the CDR API. Document uploads are triggered by file system events (if\navailable) and a scheduler.\n\n### Functionality\n\nFor each defined connector, the CDR Client calls the CDR API endpoints for document download and document upload.\n\nOptionally, the client can be configured to automatically renew its client credentials every 365 days.\n\n#### Client Credential Renewal\n\nThe client can be configured to renew its credentials every 365 days. The default behavior is to not renew the\ncredential.\n\nCredential renewal only works if the client credential is configured in a properties or YAML file. If the client detects\nmultiple sources (system property, environment variable, etc.) for the credential or the source is not of either of the\ntwo file types, then credential renewal won't be attempted. Likewise, if the user that runs the client process does not\nhave write permissions on the file.\n\nDuring a successful client credential renewal, all pre-existing client credentials are deleted. So, if you source the\nclient credential from a secure location (Hashicorp Vault, Azure Keyvault, etc., like you should) as part of your\ndeployment process, then, you should not enable credential renewal. A re-deployment would restore a previous credential\nthat is no longer valid, and you would be locked out of the client account until you manually re-create a credential on\nthe CDR website.\n\n#### Document Download\n\nFor each connector, one file after the other is pulled. Each file is written into a temporary directory defined as\n'local-folder'. The file is named after the received 'cdr-document-uuid' header that is a unique identifier created by\nthe CDR API. After saving the file to the temporary folder, a delete request for the given 'cdr-document-uuid' is sent\nto the CDR API. After successfully deleting the file in the CDR API, the file is moved to the connector defined\n'target-folder'.\n\nThe temporary directories need to be monitored to make sure that no files get stranded there (should only happen if the\nmove to the destination directory is failing).\n\n#### Document Upload\n\nDocument upload uses a combination of directory polling and event driven uploads. The polling process inspects the\ncontents of every source directory at the configured interval and uploads all `.xml` files to the CDR API that it finds\nthere. The event driven process listens for filesystem events from the same directories and uploads all `.xml` files as\nthey are created. The two approaches are combined so\n\n* at the start of the client all files are uploaded that might have arrived while the client was not running\n* directories on (remote) filesystems that do not support filesystem events can be used as source directories\n\nIf the filesystem that hosts a source directory supports filesystem events, then the polling process normally won't find\nany files to process and immediately goes back to sleep. If the polling process wakes up right at the moment a new file\narrives, it might happen that both processes pick up the same file for processing. However, only one of the two will\ncontinue to process the file, depending on which one is first to register the file for processing.\n\nAfter the file is successfully uploaded, it is either deleted or archived, depending on the connector configuration. If\nthe upload failed with a response code of 4xx, the file will be appended with '.error' and an additional file with the\nsame name as the file sent, but with the extension '.log', will be created and the received response body will be saved\nto this file. If the upload failed with a response code of 5xx, the file will be retried indefinitely, assuming the root\ncause is an infrastructure issue that will ultimately be resolved (and uploading another file would fail too, for the\nsame reason). See retry-delay in the [application-client.yaml](./src/main/resources/config/application-client.yaml)\nfile.\n\n## Local development\n\n### Client Service Configuration\n\nTo test some use cases, there is a [docker-compose.yaml](./docker-compose/docker-compose.yaml) with wiremock that\nsimulates the CDR API. Run with \n```\ndocker compose down \u0026\u0026 docker compose up --build\n```\n\nIf you want to work with a deployed CDR API you need to change\nthe [application-dev.yaml](./src/main/resources/config/application-dev.yaml)\n\nSet the following spring profile to active: dev\n\nThe following environment variables can be set (to override their `dev` profile defaults):\n\n| Variable                 | Default Value                |\n|--------------------------|------------------------------|\n| CDR_CLIENT_LOCAL_FOLDER  | $HOME/Documents/cdr/inflight |\n| CDR_CLIENT_TARGET_FOLDER | $HOME/Documents/cdr/target   |\n| CDR_CLIENT_SOURCE_FOLDER | $HOME/Documents/cdr/source   |\n| CDR_B2C_TENANT_ID        | test-tenant-client-id        |\n| CDR_CLIENT_ID            | fake-id                      |\n| CDR_CLIENT_SECRET        | Placeholder_dummy            |\n\nThe application JRE has to be started with the following system properties:\n\n* `-Djdk.net.hosts.file=cdr-client-service/src/test/resources/msal4j_hosts`\n* `-Djavax.net.ssl.trustStore=cdr-client-service/src/test/resources/caddy_truststore.p12`\n* `-Djavax.net.ssl.trustStorePassword=changeit`\n\nThe first property sets a custom hosts file to resolve external servers that MSAL4J has hardcoded as valid IdPs and\nredirect them to `localhost`. The other properties are used to make the JRE trust the SSL certificate presented by the  \n[caddy proxy](https://caddyserver.com/) server that we use to impersonate those servers.\n\n### Hydraulic Conveyor\n\nYou can use [Hydraulic Conveyor](https://conveyor.hydraulic.dev) to build installable artifacts\n\nRun following to build the project and create and install the package on your DEBIAN system:\n```\n./gradlew clean build -x test \u0026\u0026 conveyor -f conveyor-dev.conf make site \u0026\u0026 sudo dpkg -i output/debian/swisscom-schweiz-ag-cdr-client_1.0.0_amd64.deb\n```\n\n### Running the Fat-JAR\n\nIf the built SpringBoot fat-jar should be run directly, the following command can be used:\n`java -jar cdr-client.jar`\nThe jar can be found in build/libs.\n\nThe following environment variables need to be present (and correctly configured) so that the application can start\nsuccessfully:\n\n```\nSPRING_CONFIG_ADDITIONAL_LOCATION=/path/to/application-customer.yaml\"\nLOGGING_FILE_NAME=/path/to/logs/cdr-client.log\"\n```\n\nSee [application-customer.yaml](#application-customer-yaml-example) below for an example configuration file.\n\nIf you do not provide a value for `LOGGING_FILE_NAME` the log file gets auto created in your current working directory.\n\n## application-customer YAML example\n\n```\nclient:\n  local-folder: /tmp/download/in-flight # temporary directory for files that are currently downloaded from CDR API\n  idp-credentials:\n    tenant-id: swisscom-health-tenant-id # provided by Swisscom Health\n    client-id: my-client-id # Self-service on CDR website\n    client-secret: my-secret # Self-service on CDR website\n    renew-credential: false\n    max-credential-age: 365d\n    last-credential-renewal-time: 2025-06-05T14:01:42Z\n  cdr-api:\n    host: cdr.health.swisscom.ch\n  retry-delay: \n    - 1s # delay on first retry\n    - 2s\n    - 8s\n    - 32s\n    - 10m # delay after fifth retry and all following retries\n  file-busy-test-strategy: never_busy # valid values are `never_busy` and `file_size_changed`\n  customer:\n    - connector-id: 8000000000000 # provided by Swisscom Health\n      content-type: application/forumdatenaustausch+xml;charset=UTF-8\n      target-folder: /tmp/download/test/8000000000000\n      source-folder: /tmp/upload/test/8000000000000\n      mode: test\n    - connector-id: 8000000000000 # provided by Swisscom Health\n      content-type: application/forumdatenaustausch+xml;charset=UTF-8\n      target-folder: /tmp/download/8000000000000\n      source-folder: /tmp/upload/8000000000000\n      mode: production\n```\n\nSome information can also be set as environment variables.\nSee [application-client.yaml](./src/main/resources/config/application-client.yaml) for variable names.\n\nIf the host is not set to production, but to stg instead, then the CDR_CLIENT_SCOPE_PREFIX environment variable needs to\nbe set to `tst.`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswisscom%2Fcdr-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswisscom%2Fcdr-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswisscom%2Fcdr-client/lists"}