Skip to main content
Version: 2.3

Configuration properties

The tSM system is built on top of Spring Boot, which allows it to leverage Spring’s powerful externalized configuration capabilities. In tSM, configuration is primarily managed through the application.yml file, which defines common properties that apply to all microservices. These configurations can be easily customized for different environments such as development, testing, and production.

tSM also supports optional usage of Spring Cloud Config to centralize configuration across multiple microservices. This setup ensures consistency and easier management of shared properties like data sources, messaging services (Kafka), and environment-specific settings.

Please consult Spring Externalized Configuration for more info.

Common Configuration for tSM Microservices

In tSM, every microservice shares some common configuration properties, which can be centrally managed. This is especially useful when using Spring Cloud Config, where you can maintain one application.yml for all services. Here’s an example of a minimal common configuration:

# ----------------------------------------------------------------------------
# Common configuration
# ----------------------------------------------------------------------------
tsm:
prefix: projectX
datasource:
host: my.postgres.database:5401
database: tsm
username: tsm_admin
password: myPass
elastic:
address: tsm-elastic
username: elastic
password: elasticdata
kafka:
address: my.kafka.cluster:9092
autocreate:
enabled: true
partitions: 2
elk:
enabled: true
logstash:
url: tsm-log-server:5044
locale:
locale: cs-CZ
timezone: "Europe/Prague"

Explanation of Common Properties:

  • tsm.prefix: A unique identifier for the project, which is used to distinguish between different projects in the same environment. It is used as a prefix for all Kafka topics, elasticsearch indexes, and other project-specific settings.
  • tsm.datasource: Defines the database connection details for tSM microservices.
  • tsm.elastic: Specifies the ElasticSearch configuration for logging and searching within tSM.
  • tsm.kafka: Configures Kafka settings, including the address of the Kafka broker and topic autocreation. Topic autocreation runs only when tsm.kafka.autocreate.enabled is explicitly set to true — the beans that create the topics are conditional on that property being present, so setting partitions alone has no effect. partitions defaults to 10 and replicas to 0.
  • tsm.elk: Controls ELK stack logging, including connection to Logstash.
  • tsm.locale: Sets locale and timezone settings for tSM microservices.

These properties are common across all tSM microservices and ensure consistency in the way services connect to databases, messaging queues, and logging systems.

Deployment Options

When deploying tSM microservices, you have multiple options to manage configurations. The most common approach is using Spring Cloud Config for cloud environments, such as Kubernetes (K8s), where configurations are managed centrally and shared across all microservices. For on-premise deployments, configurations are typically managed locally via application.yml files.

Cloud Config Deployment

In cloud-based deployments, such as Kubernetes, Spring Cloud Config can be used to manage configuration files centrally. This enables easy scaling and maintenance of configurations across all microservices.

To use Spring Cloud Config, you need to specify the configuration source using the spring.config.import environment variable. This can be done directly in the Kubernetes deployment spec.

Example: Kubernetes Deployment with Spring Cloud Config

spec:
containers:
- env:
- name: spring.config.import
value: 'configserver:http://tsm-config-server'
image: 'registry.datalite.cz/tsm/tsm-calendar:2.2'

In this example:

  • spring.config.import points to the Spring Cloud Config server URL, which provides the configurations for the microservice.
  • The tsm-calendar microservice image is pulled from the registry and uses the configurations provided by the config server.

To deploy the Spring Cloud Config server, you need to ensure that it is configured to pull configurations from a Git repository or other storage. Here's an example Kubernetes configuration for deploying the config server:

spec:
containers:
- env:
- name: JAVA_TOOL_OPTIONS
value: '-Xms150m -Xmx150m'
- name: spring.cloud.config.server.git.uri
value: https://gitlab.datalite.cz/tsm/config.git
- name: spring.cloud.config.server.git.username
value: user
- name: spring.cloud.config.server.git.password
value: pass
- name: encrypt.key
value: myPass
image: 'registry.datalite.cz/tsm/tsm-config-server:2.2'

Make sure you have the Spring Cloud Config Server up and running and pointing to the correct repository where your application.yml files are stored.

On-Premise Deployment

For on-premise deployments, configurations are typically managed locally by placing the application.yml file directly in the classpath of the microservice. No external configuration server is required, and each microservice will load its configuration from the local file system.

Built in Configuration Properties

The following properties are common to all profiles, environments, and customizations.

They are included to all microservices and can be overridden by the environment or profile.

The block below mirrors tsm-commons/src/main/resources/application-commons.yml on the tSM 2.3 line, with internal development notes removed. It is the authoritative list of built-in defaults; when in doubt, check that file for the exact version you deploy.

# ------------------------------------------------------------
# Base shared settings (apply to every profile and environment)
# ------------------------------------------------------------

tsm:
kafka:
# Global topic prefix injected from an env variable or parent YAML
prefix: ${tsm.prefix} # e.g. “prod”, “test”, “local”
# Dead-letter queue: messages that failed processing are routed here
dlqTopic: ${tsm.kafka.prefix}-tsm-dlq
# Default consumer-group name for all listeners in this service
consumerGroupId: ${tsm.name}
# Interval for retrying the poll after a Kafka auth/SSL failure (e.g. an SSL
# handshake error once a broker is restarted); the listener self-heals as
# soon as the broker is reachable again. null = fail-fast: the consumer
# thread is stopped permanently and only a full service restart brings it
# back. Keep below max.poll.interval.ms.
authExceptionRetryInterval: 30s # default
# List of common topics
topics:
# Cache-invalidation events across micro-services
tsmCacheMaintanance: ${tsm.kafka.prefix}-tsm-cache-maintanance
tsmMaintenanceElasticRefresh: ${tsm.kafka.prefix}-tsm-elastic-refresh
elastic:
index:
# Index name prefix in Elasticsearch
prefix: ${tsm.prefix}
storedScript:
autoUpdate:
# Auto-upload stored scripts to Elasticsearch on startup
enabled: true

scripts:
events:
enabled: true # Enable event scripts (https://tsm.datalite.cz/docs/configuration/tsm-languages/SpEL/spel-bindings)
# ------------------------------------------------------------
# Embedded server (Spring Boot)
# ------------------------------------------------------------
server:
port: ${tsm.port} # Listening port
max-http-request-header-size: 64KB # Max size of HTTP request headers

# ------------------------------------------------------------
# Spring Boot – global configuration
# ------------------------------------------------------------
spring:
application:
name: ${tsm.name} # Service name (logs, Actuator /info, etc.)
threads:
virtual:
enabled: true # Run application tasks on lightweight virtual threads (Java 21, JEP 444)

# ---------- Kafka ----------
kafka:
bootstrap-servers: ${tsm.kafka.address} # Comma-separated broker list
consumer:
group-id: ${tsm.kafka.consumerGroupId} # Default group-id
auto-offset-reset: earliest # No offset? Start from beginning
# ErrorHandlingDeserializer catches (de)serialization errors
key-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializer
value-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializer
properties:
spring.deserializer.key.delegate.class: org.apache.kafka.common.serialization.StringDeserializer
spring.deserializer.value.delegate.class: org.apache.kafka.common.serialization.StringDeserializer
max.poll.interval.ms: 3600000 # Long-running message processing
max.poll.records: 200 # Messages fetched per poll
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
properties:
batch.size: 262144 # 256 KB
linger.ms: 5 # wait up to 5 ms to fill the batch
compression.type: snappy

# ---------- REST ----------
http:
client:
read-timeout: 5m

# ---------- Data source ----------
datasource:
# JDBC URL built from env variables (host, database, schema, extra params)
url: jdbc:postgresql://${tsm.datasource.host}/${tsm.datasource.database:tsm}?currentSchema=${tsm.datasource.schema}${tsm.datasource.params:}
username: ${tsm.datasource.username}
password: ${tsm.datasource.password}
hikari:
maximum-pool-size: 30 # Max connections in the pool
minimum-idle: 2 # Minimum idle connections
data-source-properties.reWriteBatchedInserts: true # Help in multiple commands
leak-detection-threshold: 60000 # Log "leaked" connections after 60 s (not returning within this timeout)
max-lifetime: 1800000 # But allow even longer queries

# ---------- JPA / Hibernate ----------
jpa:
properties:
hibernate:
# JSON (B) mapper for Kotlin + Jackson → PostgreSQL jsonb type
type.json_format_mapper: cz.datalite.tsm.db.KotlinJacksonFormatMapper
jdbc:
lob.non_contextual_creation: true # Fix for large-object creation
batch_versioned_data: true # batch even @Versioned entities
batch_size: 1000 # batch for high performance
default_batch_fetch_size: 1000 # batch for high performance
order_inserts: true # group inserts
order_updates: true # group updates
hibernate:
ddl-auto: none # Flyway manages the schema
open-in-view: true # Keep session open for lazy-load

# ---------- Jackson ----------
jackson:
mapper:
DEFAULT_VIEW_INCLUSION: true # Fields without @JsonView are always included

# ---------- FreeMarker ----------
freemarker:
template-loader-path: classpath:/templates
suffix: .ftl

# ---------- Flyway ----------
flyway:
default-schema: ${tsm.datasource.schema}
schemas: ${tsm.datasource.schema}
locations: classpath:db/release-*/**/{vendor} # Multiple version folders
group: true # Group migrations with the same version
placeholder-prefix: $$FLYWAY$${ # Placeholder syntax in SQL scripts
validate-migration-naming: true
baseline-on-migrate: true
baseline-version: 10.01.0.001 # Initial baseline if DB is empty
baseline-description: TSM Init
out-of-order: true # Allow hot-fix versions out of sequence

# ---------- Redis / Redisson ----------
redis:
redisson:
file: classpath:redisson.yaml # Deployment-provided Redisson config

# ---------- Auto-configuration exclusions ----------
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration
- org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration
- org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
# Boot's Kafka metrics listeners run on a platform-thread scheduler; tSM registers
# equivalent listeners on a virtual-thread scheduler instead
- org.springframework.boot.actuate.autoconfigure.metrics.KafkaMetricsAutoConfiguration

# ---------- Spring Cloud ----------
cloud:
openfeign:
httpclient.enabled: true # Use Apache HttpClient (supports PATCH)
lazy-attributes-resolution: true # Delay Feign bean initialization
cache.enabled: false # Work-around for occasional startup loop
client:
config: # Global timeouts for all Feign clients
default:
exception-propagation-policy: UNWRAP
logger-level: FULL
connectTimeout: 30000 # 30 s
readTimeout: 300000 # 5 m
discovery:
reactive.enabled: false # Force blocking discovery client

# ------------------------------------------------------------
# Feign (outside Spring Cloud) – enable Apache HttpClient
# ------------------------------------------------------------
feign:
httpclient.enabled: true

# ------------------------------------------------------------
# JaVers – auditing library
# ------------------------------------------------------------
javers:
auditable-aspect-enabled: false
packages-to-scan: cz.datalite.tsm
sqlSchemaManagementEnabled: false

# ------------------------------------------------------------
# Camunda (workflow engine) – defaults
# ------------------------------------------------------------
camunda:
bpm:
database:
schema-update: false # Enable only if admin grants are in place
auto-deployment-enabled: false # Process definitions are deployed via process designer
application:
scan-for-process-definitions: false
defaultNumberOfRetries: 1 # Avoid automatic retries for REST calls
defaultSerializationFormat: application/json
tenant-id-provider: cz.datalite.tsm.process.camunda.TsmCamundaTenantIdProvider
generic-properties:
properties:
historyTimeToLive: P365D # Keep process history for one year
loggingContextActivityId: tsm.camunda.activityId
loggingContextBusinessKey: tsm.camunda.businessKey
loggingContextProcessDefinitionId: tsm.camunda.processDefinitionId
loggingContextProcessInstanceId: tsm.camunda.processInstanceId
loggingContextApplicationName:
loggingContextTenantId:
job-execution: # Camunda jobs (async, timer etc.). Time is set in milliseconds
max-pool-size: 10 # Maximum number of parallel threads to execute jobs (Java virtual threads)
lock-time-in-millis: 900000 # Time for which jobs are locked, default is 15 minutes to allow long-running jobs to finish
max-jobs-per-acquisition: 20 # The batch size of the acquisition query: how many jobs the acquisition thread locks in one hit
wait-time-in-millis: 1000 # Base sleep time after an acquisition cycle that found fewer jobs than requested.
max-wait: 10000 # Upper ceiling for the exponential back-off sleep
cache:
process-definition:
enabled: false # Enable caching of process definitions
timeout: 100 # Number of milliseconds to cache process definitions.
# The cache is not synchronized in a cluster, after quick repeated deployment it can create
# duplicates. Set a very short time to avid user duplicate deploy on different instances.
# Enable only on environments with thousands of processes per second.


# ------------------------------------------------------------
# Spring Boot Actuator – endpoints and health checks
# ------------------------------------------------------------
management:
tracing:
baggage:
# remote-fields: propagated as OpenTracing baggage in outgoing HTTP / Kafka headers
# correlation.fields: also written into MDC automatically by Micrometer Tracing
remote-fields: x-traceid,x-correlation-id,x-debug-level
correlation:
fields: x-requestid,x-traceid,x-correlation-id,x-debug-level
endpoint:
health:
show-details: always # Show full health details to everyone
probes.enabled: true # Enable liveness / readiness view
endpoints:
web:
exposure.include: flyway,loggers,logfile,env,info,health,configprops,metrics,scheduledtasks,threaddump,heapdump,prometheus
health:
camunda.enabled: false # Enable after upgrading to Camunda 7.20.1
redis.enabled: false # Turn on only if Redis is actually used

# ------------------------------------------------------------
# Custom bean toggles
# ------------------------------------------------------------
bean:
RequestLoggerConfiguration.enabled: true # Log every inbound/outbound HTTP request
Baggage does not cross Kafka

The inline comment on management.tracing.baggage.remote-fields in the 2.3 file claims the fields are propagated in outgoing HTTP and Kafka headers. Only HTTP clients instrumented by Brave (Feign included) carry them. spring.kafka.{template,listener}.observation-enabled is left at its default false, so neither the trace context nor the baggage crosses a topic. x-traceid is inert in both cases — nothing writes that field; the trace id travels in the standard traceparent header.

tsm-user-management

tsm:
# HTTP port on which the TSM User-Management service listens
port: 8088

# Application name (used in logs, tracing, etc.)
name: tsm-user-management

datasource:
# Database schema that holds TSM tables
schema: um # “um” = user-management schema

kafka:
# Kafka consumer group for all listeners in this service
consumerGroupId: tsm-user-management
topics:
# Topic with user-related events (create / update / delete)
tsmUser: ${tsm.kafka.prefix}-tsm-user
# Topic with WorkForce Management work-resource updates
tsmWfmWorkresource: ${tsm.kafka.prefix}-wfm-workresource
# Topic with calendar events (holidays, shifts, etc.)
tsmCalendar: ${tsm.kafka.prefix}-tsm-calendar

planner:
# When true, send updates about work-resources to the external planner
update-workresource: true

security:
ad-config:
# Toggle LDAP authentication against Active Directory
ldap-auth-enabled: false # true → users are authenticated via AD
# Toggle scheduled sync of users / groups from AD to local DB
ldap-sync-enabled: false # true → periodic sync runs
# LDAP endpoint (protocol + host + port)
url: ldap://todo.todo:389 # e.g. ldap://ad.company.com:389
# Kerberos / AD DNS domain; leave blank to infer from base-dn
domain: # e.g. company.com
# Root DN under which all user / group objects reside
base-dn: OU=TODO,DC=in,DC=customer,DC=domain
# Optional narrower subtree to search (overrides base-dn if set)
search-base:
# Service account (bind DN or UPN) used to query the directory
mng-user: Service-account@customer.com
# Password for the service account — keep this secure!
mng-password:

radius: # Auth via RADIUS server; roles sync on login
radius-auth-enabled: false # true → enable RADIUS authentication
# One or more RADIUS servers separated by “|”
server: 127.0.0.1 # Ensure ports 1812 (auth) & 1813 (acct) are open
# Shared secret that must match the RADIUS server configuration
sharedSecret: testing123

database:
# Allow classic username/password auth against internal DB
password-auth-enabled: true # Set false to disable local fallback

management:
health:
ldap:
# Include LDAP in Actuator /health only if LDAP is used and should affect status
enabled: false # true → app hits LDAP to report health


# common config
spring:
flyway:
out-of-order: true
jmx:
enabled: false
banner:
location: classpath:tsm-banner.txt
application:
name: ${tsm.name}

javers:
sqlSchema: um

# Remove too verbose logging.
# These levels have to be set per service: the shared configuration is loaded too late
# during startup to affect them.
logging:
level:
org.apache.kafka: WARN
org.springframework.cloud.openfeign.FeignClientFactoryBean: WARN
org.flywaydb.core.internal.license.VersionPrinter: WARN
com.zaxxer.hikari.HikariDataSource: WARN