Skip to main content

Property Reference

This document is regenerated from the physical configuration templates (*.properties) being deployed. The authoritative source of the templates is plantpulse-datalake-cli/config/templates, and the host's /etc/kopens/conf is bind-mounted to that location. Which template is rendered where is determined by config/render.map. The authoritative source for loading priority is plantpulse-core/src/plantpulse/core/engine/utils/PropertiesUtils.java.

If keys have been added, deleted, or renamed, the template—not this document—is the authoritative source. Do not fill in this document manually; extract it again from the template. The "Default" values in each table are exactly as written in the template, and ${PP_XXX} are placeholders substituted with environment variable values during rendering.

Value Flow: Source to Destination​

ItemLocationPermissionsHow to Change
Secrets — DB passwords · API keys/etc/kopens/plantpulse-platform.env0600bin/passwd.sh (Change server account → Update sidecar → Re-render → Restart as one sequence)
Node-specific values — PP_MASTER_IP · Kafka advertised address · Image tag pins/etc/kopens/platform.node.env0600Edit directly, then bin/restart-datalake.sh
Settings — Ports · Image tags · Locale · Data paths.env in repo (Commit .env.example only)—Edit directly, then restart
«Lines» of Engine Settings — postgresql.conf parameters, Kafka retention, Aster TSDB heap/etc/kopens/conf/<파일>.template—Edit template → pd config render → pd restart <서비스>
Directly editing component config files will cause changes to disappear on next startup

pd start renders the template every time and overwrites the configuration location of each component. Even if you open and edit cassandra.yaml, postgresql.conf, or kafka.properties, they will revert to their original state upon the next startup. The place to make changes is the template → How to change settings

Do not merge secrets and node values into a single file

Secret files are copied to app nodes during split installation, whereas node files must not be copied. Merging them will leak one box's PP_MASTER_IP and image tag pins to other boxes. Only one format is supported: VAR=값 — if export is appended, env_file: will fail to parse it.

Standard Template Change Procedure​

Modify values on the host and reflect them into pd inside the container.

vi /etc/kopens/conf/<템플릿> # 1. 호스트의 템플릿을 고칩니다

docker exec plantpulse-datalake pd doctor # 2. 검사 (선택)
docker exec plantpulse-datalake pd config diff # 3. 무엇이 달라지는지 봅니다
docker exec plantpulse-datalake pd config render # 4. 실제로 씁니다
docker exec plantpulse-datalake pd restart <서비스> # 5. 재시작
docker exec plantpulse-datalake pd status # 6. 확인

pd config render only rewrites the configuration file and does not restart the service. Until a restart occurs, the new configuration exists only on disk while the old process remains active. This is why steps 4 and 5 are a single set.

Configuration File Loading Priority​

Web applications (server / batch / cep / sql / data-gateway) search for configuration files in the following order. The implementation is PropertiesUtils.readExternalFirst().

  1. Directory specified as a -Dpp.conf.dir system property (constant PropertiesUtils.CONF_DIR_SYSTEM_PROPERTY = "pp.conf.dir")
  2. ${catalina.base}/../config — The config/ directory of the module
  3. Web app classpath (defaults included in WAR) — fallback

External files are read as UTF-8. If external configurations are loaded successfully, the following is printed in the startup log:

Properties loaded from external conf: <absolute-path>

If reading an external file fails, an error log is recorded, and it falls back to the classpath.

Logging configurations (log4j2.xml) are also externalized through the same chain (self-seeding — if no external file exists, WAR defaults are copied to the module config/log4j2.xml once and then used). When applied, Logging reconfigured from external conf: <absolute-path> is printed in the startup log. Changes to log levels are applied by modifying module config/log4j2.xml and restarting, which is preserved even after WAR redeployment. Refer to the configuration and deployment guide for details.

Caution: Do not directly modify internal web app files (server/webapps/ROOT/WEB-INF/classes/, etc.) — they will disappear upon WAR redeployment.

${ENV:기본값} Substitution Occurs Twice​

The ${PP_XXX} / ${PP_XXX:기본값} notation in templates is interpreted at two different points in time.

TimingAgentAction
At Startuppd config renderSubstituted with sidecar (plantpulse-platform.env · platform.node.env) and container environment. Order: Environment variable → :기본값 → Preserve original. Nested placeholders are not supported
At RuntimePropertiesUtils.resolveEnvPlaceholdersRe-interprets ${ENV_VAR[:default]} for all values in the loaded Properties

In other words, any ${...} remaining after deployment can still be filled by the process's environment variables. This is why Docker -e VAR=... injection takes precedence over template defaults.

PP_* Variables Not in Sidecar (Template defaults apply)​

The following variables are referenced by the template as ${PP_XXX:기본값} but are not defined in the sidecar file. Therefore, the template default is always used unless explicitly injected.

PP_EXTERNAL_DB_PASSWORD · PP_MAIL_SMTP_HOST · PP_MAIL_SMTP_PORT · PP_MAIL_SMTP_AUTH · PP_MAIL_SMTP_USER · PP_MAIL_SMTP_PASSWORD · PP_MAIL_SMTP_STARTTLS · PP_DIAGNOSTIC_EMAIL

PP_AI_* was on this list but now does nothing

Providing PP_AI_OPENAI_*, PP_AI_MCP_*, or PP_AI_CHAT_ENABLED will be silently ignored. The layer that read those values was removed on 2026-09-18 — see AI Configuration.

PP_STORAGE_PASSWORD · PP_METASTORE_PASSWORD were on this list but are «non-existent variables»

Neither the template nor the sidecar references those names. The actual names are as follows:

ItemActual Variable
Time series storage (Aster TSDB) connectionPP_CASSANDRA_HOST · PP_CASSANDRA_PORT · PP_CASSANDRA_USER · 🔑 PP_CASSANDRA_PASSWORD
Metastore (PostgreSQL) connectionPP_POSTGRES_HOST · PP_POSTGRES_PORT · PP_PG_USER · 🔑 PP_PG_PASSWORD

🔴 PP_MAIL_SMTP_* also now does nothing. The authoritative source for mail settings is pp.mm_config, and values are changed via the console (/config/index) or that table — Mail Configuration. This migration was made to ensure that values that must match as a set (host, port, authentication, account) are modified in one place only.

5 Types of Server Management Settings​

There are 5 configuration files defined by the ConfigTemplates.SERVER_CONFIGS array and deployed as plantpulse-server/config/.

#TemplateDeployment Path
1plantpulse-engine.properties/plantpulse-server/config/plantpulse-engine.properties
2plantpulse-storage.properties/plantpulse-server/config/plantpulse-storage.properties
3plantpulse-mq.properties/plantpulse-server/config/plantpulse-mq.properties

These three files are read all at once by PropertiesLoader.load() (engine/mq/storage), and typed configuration beans EngineConfig · StorageConfig · MqConfig are reconstructed.

Mail and AI settings are not files — pp.mm_config is the authoritative source

plantpulse-mail.properties and plantpulse-ai.properties were deleted on 2026-09-17, and the path that read old copies remaining in the external configuration directory and moved them to a table was completely removed on 2026-09-18. In other words, even if you create those files, nothing will be read.

The only paths for values are the console and PostgreSQL pp.mm_config. The authoritative source for key names and defaults is in the code's MailConfigKeys · AiConfigKeys; keys without a row in the table are read using those defaults — the key tables in the two sections below remain valid.

application.properties (Removed)​

application.properties was removed in June 2026. There is no code that reads this file (0 usages across all repos), and existing items were migrated as follows:

  • Console behavior settings such as theme / homepage → Console System > Configuration Management (PostgreSQL mm_config table)
  • alarm.duplicate.check.minutes → plantpulse-engine.properties series (read by EngineConfig)

plantpulse-engine.properties​

Path: plantpulse-server/config/plantpulse-engine.properties · Template: template/plantpulse-engine.properties

Controls the core operation of the data processing engine.

Async / Pipeline​

PropertyDefaultSubstitutionDescription (Template Comment)
engine.async.parallelism256—Async worker pool parallelism (total cores ~= 256)
engine.pipeline.threads36—Number of pipeline threads
engine.pipeline.ratelimit40000—Pipeline processing limit per second (rate limit)
engine.pipeline.queue.size1200000—Pipeline queue size (backpressure limit)
engine.pipeline.queue.o3.delay50—Out-of-order data allowed delay (ms)
engine.pipeline.task.modeSINGLE—Task execution mode (SINGLE / PARALLEL)

NTP​

PropertyDefaultSubstitutionDescription
engine.ntpdate.server.ip127.0.0.1—NTP server IP
engine.ntpdate.syncfalse—Whether to perform NTP synchronization on boot

Stream / CEP​

PropertyDefaultSubstitutionDescription
engine.stream.processorDIRECT—Stream processing mode (DIRECT/BUFFERED)
engine.cep.server.ip127.0.0.1${PP_CEP_HOST:127.0.0.1}CEP server IP
engine.cep.server.port7400${PP_CEP_CONNECT_PORT:7400}CEP server port (auto-align by protocol: http→7400, https→7401)
engine.cep.server.protocolhttp${PP_CEP_PROTOCOL:http}CEP protocol. Default http for internal communication, https for distributed/containers
engine.cep.server.api.key(None)${PP_CEP_API_KEY}For CEPClient X-API-Key header. Must match CEP server cep.api.key

Streaming Message Delivery​

PropertyDefaultSubstitutionDescription
engine.streaming.messaging.warning.ms5000—Message delivery delay warning (ms)
engine.streaming.messaging.timeout.ms10000—Message delivery timeout (ms)
engine.streaming.messaging.timeout.store.typeFILE_QUEUE—Timeout message storage method (FILE_QUEUE/MEMORY)
engine.streaming.messaging.timeout.recovery.typeDB—Timeout message recovery source (DB/FILE)

Job Worker Thread​

PropertyDefaultSubstitutionDescription
engine.job.thread.asset8—Number of asset job threads
engine.job.thread.point8—Number of point job threads

DDS​

PropertyDefaultSubstitutionDescription
engine.dds.enabledtrue—Global DDS activation
engine.dds.data.tag.enabledtrue—Tag data DDS publishing
engine.dds.data.asset.enabledtrue—Asset data DDS publishing

Anomaly Detection / Data Flow​

PropertyDefaultSubstitutionDescription
engine.data.anomaly.enabledfalse—Anomaly detection activation (external service integration)
engine.data.anomaly.urlhttps://127.0.0.1:8970—Anomaly detection service URL
engine.dataflow.classplantpulse.core.engine.pipeline.dataflow.BaseDataFlow—Data flow implementation class
engine.dataflow.server-timestamp.overridefalse—Whether to force server timestamp (true: collection time, false: original)
engine.dataflow.negative-timestamp.overridetrue—Whether to correct negative timestamps
engine.factory.model.updater.classplantpulse.core.engine.model.impl.DefaultFactoryMetaModelUpdater—Factory metamodel updater
engine.event.handler.classplantpulse.core.engine.event.DefaultEventHanlder—Event handler implementation (typo in class name Hanlder is as per actual class name)
engine.javagc.enabledfalse—Whether to allow explicit System.gc() calls

Flow Engine​

PropertyDefaultSubstitutionDescription
flow.debug.execution.logfalse—Node execution INFO log. true for debugging sessions only
flow.stats.prune.interval.ms86400000—Counter cleanup execution cycle (ms, 24 hours). Aster TSDB counter tables cannot use default_time_to_live, so cleanup is at the application level
flow.stats.prune.hourly.days30—Retention period (days) of hour_bucket in tm_flow_stats_hourly
flow.stats.prune.daily.days90—Retention period (days) of day_bucket in tm_flow_stats_daily
flow.health.check.interval.ms600000—Flow health check cycle (ms, 10 minutes). ERROR if current time bucket errors > 0, otherwise NORMAL (KST based)
flow.webhook.api.keydev-webhook-19ba7a54-1132-49f2-967e-3c6f5cd989a0${PP_FLOW_WEBHOOK_API_KEY:...}Flow engine external webhook authentication

Aster TSDB tables used by Flow health check: tm_flow_health_status (flow_id, hour_bucket — current time accumulator), tm_flow_health_status_10m (flow_id, min10_bucket — 10-minute time series).

Edge Health Check​

PropertyDefaultSubstitutionDescription
edge.health.check.interval.ms600000—Edge health check cycle (ms, 10 minutes)

The determination source is the _ON / _NORMAL flags in the Aster TSDB tm_edge_status payload. There is no RT REST call, so the load is zero and it completes within 1 second. Tables: tm_edge_health_status (edge_id, hour_bucket), tm_edge_health_status_10m (edge_id, min10_bucket).

Authentication / Security​

PropertyDefaultSubstitutionDescription
api.key(None)${PP_API_KEY}Platform internal API key (Server ↔ Edge Agent authentication)
engine.api.v5.auth.bruteforce.enabledtrue—V5 API authentication brute force defense
engine.api.v5.auth.bruteforce.ip_limit30—Attempt limit per IP
engine.api.v5.auth.bruteforce.user_limit10—Attempt limit per user
engine.api.v5.auth.bruteforce.window.seconds60—Counting window (seconds)
engine.api.v5.trusted_proxies(Empty)—Trusted proxy IP whitelist. Only when configured, if remoteAddr is on the list, the first IP of X-Forwarded-For is used as client IP. If empty, only getRemoteAddr() is used (fail-safe)
engine.session.bruteforce.enabledtrue—/login/login browser session brute force defense
engine.session.bruteforce.ip_limit30—Attempt limit per IP
engine.session.bruteforce.user_limit10—Attempt limit per user
engine.session.bruteforce.window.seconds300—Counting window (seconds)

The session brute force counter is Caffeine in-memory — multi-node sharing (Redis) is not implemented.

API Token​

PropertyDefaultSubstitutionDescription
engine.api.token.cleanup.enabledtrue—Expiry(expires_at < now)/Revocation(revoked_at IS NOT NULL) token cleanup
engine.api.token.cleanup.retention_days30—Hard delete from mm_token after this period expires. Once every 24 hours (first run 60s after boot)
engine.api.token.default_ttl_days90—Default expiry (days) when issuing new tokens. 0 = permanent token. If the issuance request provides ttl_days, that value takes precedence → Issue API Token

Existing tokens where expires_at is NULL are maintained as permanently active (backward compatibility).


plantpulse-storage.properties​

Path: plantpulse-server/config/plantpulse-storage.properties · Template: template/plantpulse-storage.properties

Manages connections and storage policies for Metastore (PostgreSQL), Cache (Valkey), Time Series (Aster TSDB), TSE, and Data Gateway.

⚠️ Typo keys actually exist in this file. Three keys have spellings different from what the code reads — you must read the Typo Key Warning section.

PostgreSQL Metastore​

PropertyDefaultSubstitutionDescription
metastore.driverorg.postgresql.Driver—JDBC driver class
metastore.urljdbc:postgresql://...${PP_POSTGRES_HOST} · ${PP_POSTGRES_PORT} · ${PP_DB_NAME}Metastore JDBC URL. Includes query string ?characterEncoding=UTF-8&reWriteBatchedInserts=true
metastore.user—${PP_PG_USER}Metastore account
metastore.password—${PP_PG_PASSWORD}Metastore password

Cache (Valkey / Redis Compatible)​

PropertyDefaultSubstitutionDescription
cache.host—${PP_REDIS_HOST}Cache host
cache.port—${PP_REDIS_PORT}Cache port (internal plaintext Valkey backend)
cache.password—${PP_REDIS_PASSWORD}Cache password
cache.ssl.enabledfalse—Cache TLS. Internal clients default to redis://
cache.ssl.truststore.location/var/security/plantpulse/master/master.truststore.p12—Truststore path
cache.ssl.truststore.passwordkopens123!${PP_TLS_TRUSTSTORE_PASSWORD:kopens123!}Truststore password
cache.ssl.truststore.typePKCS12—Truststore type
cache.ssl.endpoint.identification.enabledfalse—Endpoint identity verification

The authoritative source for key constants is InMemoryConfigKeys in plantpulse-inmemory.

TSE (TimeSeries Engine)​

PropertyDefaultSubstitutionDescription
tse.protocolhttp${PP_TSE_PROTOCOL:http}TSE protocol. Default plaintext http for internal communication (2026-08)
tse.host—${PP_TSE_HOST}TSE host
tse.port7800${PP_TSE_CONNECT_PORT:7800}TSE port. Default plaintext listener 7800
tse.usertse${PP_TSE_USER:tse}TSE account
tse.passwordtse123!${PP_TSE_PASSWORD:tse123!}TSE password

Aster TSDB Time Series Storage​

PropertyDefaultSubstitutionDescription
storage.db_typeCASSANDRA—DB type. CASSANDRA/DSE/SCYLLADB remain in template comments, but the only currently supported value is CASSANDRA
storage.db_version5.0—Not the server version, but «feature compatibility level» — see note below
storage.host—${PP_CASSANDRA_HOST}Contact point host
If storage.db_version is 5.0, but nodetool version appears as 6.0.0

Both are correct. They are not values referring to the same thing.

ValueWhat
storage.db_version5.0Compatibility level determining which feature set the driver speaks with
Actual Bundled Server6.0.0apache-cassandra-timeseries-6.0.0.jar — Internal fork of cassandra-6.0

Do not read 5.0 and assume «the server is 5.0». Information regarding the server is in Time Series Database. Do not arbitrarily increase this value to 6.0 — driver behavior will change.

| storage.port | 9042 | ${PP_STORAGE_PORT:9042} | Native protocol port | | storage.keyspace | — | ${PP_KEYSPACE} | Keyspace used | | storage.user | — | ${PP_CASSANDRA_USER} | Connection account | | storage.password | cassandra | ${PP_STORAGE_PASSWORD:cassandra} | Password. PP_STORAGE_PASSWORD is not exported in env.sh → default applied | | storage.durable_writes | true | — | Use commit log (⚠️ No reading code — see below) | | storage.append_columns | [] | — | Auto-add user-defined columns | | storage.replication | { 'class' : 'NetworkTopologyStrategy', 'datacenter1' : 1 } | — | Replication strategy (Single node default) | | storage.data.disk.name | — | ${PP_DATA_DISK_NAME} | Data disk name |

TTL (Unit: Days)​

PropertyDefaultDescription
storage.tag.point.ttl62Tag time series original
storage.tag.point.map.ttl1Tag point map
storage.tag.point.sampling.ttl93Tag sampling
storage.tag.point.snapshot.ttl93Tag snapshot
storage.tag.point.aggregation.ttl93Tag aggregation
storage.tag.point.archive.ttl365Tag archive (long-term retention)
storage.tag.blob.ttl93Tag BLOB
storage.asset.data.ttl10Asset data
storage.asset.data.sampling.ttl31Asset sampling

Asset Snapshot Cycle​

PropertyDefaultDescription
storage.asset.data.snapshot.interval10 SECONDSRecords the tag map (data_map) of assets before each cycle to the asset_data series (data/second/timestamp + min/hour/day boundaries)

Template comments explain the reasoning: 1 SECONDS was congested with approx 22K writes per minute based on 121 assets (approx 4% of total Aster TSDB). Since tag originals (second unit) are fully preserved in tm_tag_point/TSE, asset view snapshots were lowered to 10s (matching code default) — reducing writes by 90% while maintaining record integrity.

This value becomes the ASSET_DATA_JOB cycle of the scheduler. It must be in "<n> <unit>" 2-token format; refer to the scheduler architecture for rules.

Internal Metastore Synchronization (Experimental)​

PropertyDefaultDescription
storage.internal.metastore.enabledfalseInternal metastore synchronization activation
storage.internal.metastore.thread.count4Number of synchronization worker threads
storage.internal.metastore.queue.size12000000Synchronization queue size
storage.internal.metastore.point.retation.days10Point retention period (⚠️ Typo key — see below)

Row Cache​

PropertyDefaultDescription
storage.asset.data.row.cache.sizeNONEAsset data row cache (NONE/ROWS_ONLY/ALL) — ⚠️ No reading code
storage.tag.point.row.cache.sizeNONETag point row cache — ⚠️ No reading code

Compaction​

PropertyDefaultDescription
storage.table.compaction.strategyUCSDefault strategy (TWCS: TimeWindow, UCS: Unified). Read by CassandraCreateDAO (Code fallback: TWCS)
storage.table.compaction.strategy.twcs.window_size1TWCS window size — ⚠️ No reading code
storage.table.compaction.strategy.twcs.window_unitDAYSTWCS window unit — ⚠️ No reading code
storage.table.compaction.strategy.ucs.scailing_parameterT8UCS scaling parameter (T8 = tiered 8 levels). Key spelling scailing matches code
storage.table.compaction.strategy.ucs.min_sstable_size128MiBUCS minimum sstable size (Code fallback: 100MiB)
storage.table.compaction.strategy.ucs.target_sstable_size512MiBUCS target sstable size
storage.table.compaction.strategy.ucs.base_shard_count8UCS base shard count
storage.table.compaction.strategy.ucs.max_sstables_to_compact6Maximum number of sstables to compact at once
storage.table.compaction.strategy.ucs.sstable_growth0.7UCS sstable growth ratio

Compression / Query Limits / Backup / Data Gateway​

PropertyDefaultSubstitutionDescription
storage.compresion.zstd.level3—zstd compression level (1~22) — ⚠️ Typo key, see below
storage.tag.point.select.limit.size1000000—Max rows for single tag point select
storage.doamin.model.changed.to.metastore.backuptrue—Metastore backup upon domain model change — ⚠️ Typo key + No reading code
data.gateway.protocolhttp${PP_DATA_GATEWAY_PROTOCOL:http}Data Gateway protocol
data.gateway.host127.0.0.1${PP_DATA_GATEWAY_HOST:127.0.0.1}Data Gateway host (assumes local co-location)
data.gateway.port5500${PP_DATA_GATEWAY_CONNECT_PORT:5500}Data Gateway port (Code fallback: 5501)
data.gateway.api.key—${PP_DATA_GATEWAY_API_KEY}Data Gateway API key

⚠️ Typo Key — Ignored even if edited​

The following 3 keys actually existing in the template have spellings different from what the code reads. Even if an administrator changes the values in these lines, they will be silently ignored, and the code defaults will be applied.

Key in Template (Typo)Key actually read by codeCode DefaultRead Location
storage.compresion.zstd.levelstorage.compression.zstd.level3StorageConfig → CassandraCreateDAO
storage.internal.metastore.point.retation.daysstorage.internal.metastore.point.retention.days10StorageConfig → PointDAO
storage.doamin.model.changed.to.metastore.backupNone (No code reads this even with correct spelling)——

To actually change the value, add the key with the correct code spelling to the same file. For example, to increase the zstd level to 6, you must add storage.compression.zstd.level=6 (do not just fix the typo key, but add a new line with the correct spelling). Leaving the typo line is harmless, but fixing the template itself is the fundamental solution.

No code reads storage.doamin.model.changed.to.metastore.backup regardless of spelling. Backup during domain model change is handled by MetastoreBackupDeployer (cron 0 0 12 1 1/1 ? *, 1st of every month 12:00), not this key — refer to the scheduler architecture.

Storage Keys Read by Code but Missing from Template​

PropertyCode DefaultDescription
storage.compression.zstd.typeZstdCompressorCompressor class name

Storage Template Keys with No Reading Code (Invalid if edited)​

storage.durable_writes · storage.asset.data.row.cache.size · storage.tag.point.row.cache.size · storage.table.compaction.strategy.twcs.window_size · storage.table.compaction.strategy.twcs.window_unit (+ the 3 typo keys above)

Even if the two keys related to TWCS are changed to storage.table.compaction.strategy=TWCS, they cannot control window size/unit.


plantpulse-mq.properties​

Path: plantpulse-server/config/plantpulse-mq.properties · Template: template/plantpulse-mq.properties

Manages Kafka / MQTT broker connections and DDS publishing topics. The code-side SSOTs are MqConfig (connections) and UNSTopicDefaults (topics).

Broker Connection​

PropertyDefaultSubstitutionDescription
mq.host—${PP_KAFKA_HOST}Broker host (Shared by Kafka/MQTT)
mq.user—${PP_MQ_USER}Broker admin account
mq.password—${PP_MQ_PASSWORD}Broker password
mq.kafka.port9092${PP_KAFKA_PORT:9092}Kafka port
mq.kafka.security.protocolSASL_PLAINTEXT—Kafka security protocol
mq.ssl.truststore.location/var/security/plantpulse/master/master.truststore.p12—Messaging TLS truststore (MQTT + optional Kafka TLS)
mq.ssl.truststore.passwordkopens123!${PP_TLS_TRUSTSTORE_PASSWORD:kopens123!}Truststore password
mq.ssl.truststore.typePKCS12—Truststore type
mq.ssl.endpoint.identification.algorithm(Empty)—Hostname verification algorithm (Empty = No verification)
mq.mqtt.port—${PP_MQTT_TLS_PORT}MQTT connection port
mq.mqtt.ssl.enabledtrue—MQTT TLS use

In addition to the keys above, MqConfig also reads Kafka-specific truststore overrides mq.kafka.ssl.truststore.location / .password / .type and mq.kafka.ssl.endpoint.identification.algorithm (not in template, defaults to mq.ssl.* if absent).

DDS Topics​

14 Kafka types (mq.dds.kafka.topic.*) + 14 MQTT UNS types (mq.dds.mqtt.topic.*) + 2 SparkplugB types (mq.dds.mqtt.sparkplugb.*).

The complete list of keys and defaults is organized in Messaging Architecture → DDS Publishing Topics. Topic values are Kafka/MQTT wire contracts, and UNSTopicDefaultsContractTest freezes the literals, so arbitrary changes are prohibited.

${PP_TOPIC_PREFIX} simultaneously determines the prefix of Kafka topics (pp-), the root of MQTT UNS paths (pp/), and the SparkplugB group ID.


Mail Configuration (pp.mm_config)​

Authoritative source: PostgreSQL pp.mm_config · Key authoritative source: plantpulse.core.config.MailConfigKeys. Reading side: SMTPMailSender.loadMailConfig().

🔴 PP_MAIL_* environment variables also do nothing

Same as AI — the substitution layers for plantpulse-mail.properties and ${PP_MAIL_*} were removed on 2026-09-17~18. Providing them via sidecar or docker run -e will be silently ignored. Enter values in the console Configuration Screen(/config/index) or the pp.mm_config table.

Config KeyDefaultDescription
MAIL_SEND_ENABLEDfalseMaster Sending Gate. If off, skip without SMTP connection and leave only WARN
MAIL_SMTP_HOSTsmtp-relay.brevo.comSMTP relay address
MAIL_SMTP_PORT587587 = STARTTLS, 465 = Implicit TLS (with MAIL_SMTP_SSL_ENABLE)
MAIL_SMTP_AUTHtrueWhether to use SMTP login. Even if on, if MAIL_SMTP_USER is empty, no login is performed
MAIL_SMTP_USER(Empty)SMTP account. May differ from sender address as it is the name issued by the relay. Can be saved as empty
🔑 MAIL_SMTP_PASSWORD(Empty)SMTP password or API key. Authentication will be rejected if empty on a login-requiring relay
MAIL_SMTP_STARTTLS_ENABLEtrueWhether to upgrade to STARTTLS on 587
MAIL_SMTP_SSL_ENABLEfalseWhether to connect via TLS from the start like 465. In this case, starttls is disabled
MAIL_SMTP_CONNECTIONTIMEOUT10000Connection timeout (ms). If absent, JavaMail default is «infinite wait»
MAIL_SMTP_TIMEOUT10000Read timeout (ms). 〃
MAIL_SMTP_WRITETIMEOUT10000Write timeout (ms). 〃
MAIL_FROM(Empty)Sender address. If empty, MAIL_SMTP_USER is used, but relay account names are often not valid addresses and may be rejected by the recipient — use a real address
sms.sender.classplantpulse.core.service.support.alarm.sms.DefaultSMSSenderSMS sender implementation FQN. If a non-existent class is entered, it reverts to default implementation

TLS only uses 1.3 · 1.2 and verifies server certificate names.

SMTP credentials are no longer in defaults

The defaults for MAIL_SMTP_USER · MAIL_SMTP_PASSWORD are empty values. Since MAIL_SEND_ENABLED is the default false, sending will not be attempted until an operator enables it.

Sending via Gmail SMTP Relay​

Google Workspace SMTP relay (smtp-relay.gmail.com) can be authorized by the sending server's IP address. In this case, since there is no account, leave login disabled. First, register the outgoing IP of this server in the Google Admin Console's SMTP relay settings.

Config KeyValue
MAIL_SEND_ENABLEDtrue
MAIL_SMTP_HOSTsmtp-relay.gmail.com
MAIL_SMTP_PORT587
MAIL_SMTP_AUTHfalse
MAIL_SMTP_USER(Empty)
MAIL_SMTP_STARTTLS_ENABLEtrue
MAIL_SMTP_SSL_ENABLEfalse
MAIL_FROMActual address of Workspace domain

After saving, click Re-apply on the configuration screen.

Alarm Mail​

  • The product logo is included in the mail header (CID inline image). It is visible even without a console address and is not fetched externally.
  • The location line of the mail is written starting from the site (Site › Area › Line › Equipment; company is excluded).
  • The «Go to check alarm» link is PP_UI_CONSOLE_URL (<콘솔 주소>/alarm/view/<알람 번호>). If empty, the mail is sent as is, but only the link is omitted — Address Configuration.
diagnostic.log.email is gone

It was removed from the table as there is no code that reads it (product testing prevents that key from returning). Even if it remains somewhere, it does nothing.


AI Configuration (pp.mm_config)​

Authoritative source: PostgreSQL pp.mm_config · Key authoritative source: plantpulse.core.config.AiConfigKeys. Reading side: AiConfig (+ AiConfig.mcpSettings()).

🔴 PP_AI_* environment variables do nothing

Old plantpulse-ai.properties was deleted on 2026-09-17, and the path that read that file and the ${PP_AI_*} substitution layer were both removed on 2026-09-18. Providing names like PP_AI_OPENAI_ENABLED via sidecar or docker run -e will be silently ignored — no errors or warnings.

This is why the product removed those names instead of keeping them «just in case». Names that exist but are ignored are worse than non-existent names because the server appears to be configured.

There are only two ways to enter values — the configuration screen in the console (/env), or directly modifying the pp.mm_config table. Keys without a row are read as the defaults in the table below; a row is created when a value is entered.

LLM Gateway​

PropertyDefaultDescription
ai.llm.enabledfalseGlobal AI switch. If off, all AI screens and endpoints are closed
ai.llm.base.urlhttps://api.openai.comOpenAI compatible gateway (LiteLLM/vLLM). Do not append / to the end
ai.llm.chat.path/v1/chat/completionsChange only when the gateway uses a different path
ai.llm.responses.path/v1/responses〃
🔑 ai.llm.api.key(Empty)Gateway key. Calls will be rejected with 401 if empty
ai.llm.modelgpt-5-miniModel name exposed by the gateway. If base.url is changed, change this as well
ai.llm.timeout.ms60000LLM call timeout (ms)
ai.llm.max.output.tokens4000Maximum response tokens
ai.llm.temperature-1If negative, omit entirely from the request to use the model's default
Old name ai.openai.* is no longer read

The prefix has changed to ai.llm.. Even if a ai.openai.base.url row remains in pp.mm_config, the code doesn't read it and uses the default (https://api.openai.com) — this creates a situation where it looks like the gateway is configured, but it attempts to go to OpenAI and fails. Check these rows on upgraded installations.

Why is ai.llm.temperature negative by default

The gpt-5 series does not support temperature and returns 400 Unsupported value if a value other than the default 1 is sent. Therefore, a negative value meaning «do not send» is used as the default. Increase it to 0 or above only when using other models behind LiteLLM/vLLM.

Feature Switches​

🔴 Defaults changed on 2026-09-16. The only AI feature remaining on the screen is Chat; others were removed by the product. Returning values to true will bring back the features, but those screens are not in a validated state for this version.

PropertyDefaultDescription
ai.chat.enabledtrueAI Chat Console — This is the only AI feature remaining on the screen
ai.chat.history.ttl.days90Chat history retention (days). Applied as Cassandra TTL and reflected from «new» messages after restart
ai.alarm.rca.enabledfalseAlarm RCA — if on, AI root cause analysis is added to alarm details
ai.alarm.eql.enabledfalseAlarm EQL Assistant — if on, a draft button is added to the alarm configuration form
ai.uns.topic.enabledfalseUNS Topic Description — if on, a description panel is added to the UNS tree
ai.result.audit.enabledfalseAI Result Audit — Internal RCA component without a screen. Enable this when enabling RCA
ai.similar.incident.enabledfalseSimilar Incident Evidence Collection — 〃
ai.similar.incident.max.items5Maximum number of similar incidents to include as evidence
ai.similar.incident.min.score40Minimum score to be recognized as a similar incident
6 keys removed in 2026-08

3 keys for ai.diagnostic.summary.* (AI summary of diagnosis logs) and 3 keys for ai.operations.report.* (AI operation report) were removed from the product on 2026-08-25. Screens, JS, and controllers were also removed, so the features will not return even if values are restored. Leaving them causes no harm — no code reads them.

MCP​

🔴 MCP is «independent» from ai.llm.enabled. Since it is for external clients, not screens, /api/v5/mcp remains open even if the gateway is off. For details, see MCP Server.

PropertyDefaultDescription
AI_MCP_ENABLEDtrueIf false, then /api/v5/mcp returns 404
AI_MCP_ALLOWED_ORIGINS(Empty)Browser Origin whitelist (comma separated). If empty, all browser requests are rejected, allowing only native clients
AI_MCP_TREE_MAX_NODES2000Tree response node upper limit — dependent on model context window; increase as model size increases
AI_MCP_TREE_DEFAULT_DEPTH2Tree query default depth
AI_MCP_TREE_MAX_NODE_TAGS100Tag count upper limit per node
AI_MCP_TREE_ONTOLOGY_MAX_CHARS200000Ontology response character upper limit
AI_MCP_TREE_ONTOLOGY_DEFAULT_DEPTH3One level deeper than default tree depth — must reach equipment nodes with tag counts to answer «how many tags for this equipment» as a default response
AI_MCP_TREE_ONTOLOGY_MAX_TAGS500Tag row budget for the entire ontology response (separate from per-node limit). Since one slim tag is approx 85B, loading the entire site consumes 33~56% of the context window

Other Templates​

template/ contains application and infrastructure configuration templates in addition to the 5 types above. The authoritative deployment path mapping is ConfigTemplates.java.

TemplateDeployment PathPurpose
plantpulse-batch.properties/plantpulse-batch/config/Batch (Time series sync/aggregation)
plantpulse-cep.properties/plantpulse-cep/config/CEP Engine
plantpulse-jdbc.properties/plantpulse-data-gateway/config/JDBC Integrated Configuration
plantpulse-data-gateway.properties/plantpulse-data-gateway/config/Data Gateway Operation
plantpulse-warehouse.properties/plantpulse-warehouse/config/Aster TSDB → Iceberg(S3) Archive
plantpulse-datalake-admin-api.properties/plantpulse-datalake-admin-api/config/Admin Console API · JMX Collection
plantpulse-plugin-opcua.properties/plantpulse-plugin/opc-ua/config/OPC UA Server Plugin
plantpulse-plugin-aas.properties/plantpulse-plugin/aasx-server/config/AAS V3 (aasx-server) Plugin
kafka.properties/plantpulse-messaging/kafka/config/kafka.propertiesKafka(KRaft) Broker
kafka-jaas.conf/plantpulse-messaging/kafka/config/jaas.confKafka JAAS
hivemq.xml/plantpulse-messaging/mqtt/conf/config.xmlHiveMQ Broker
plantpulse-mq-auth.properties/plantpulse-messaging/mqtt/conf/auth.propertiesHiveMQ Auth Source
hive-auth.properties/plantpulse-analytics/spark/conf/Hive/Analysis Account Auth Source
plantpulse-timeseries-engine.conf/plantpulse-timeseries/engine/conf/ (2 locations)TSE
valkey.conf · postgresql.conf · pg_hba.conf · cassandra.yaml · jvm-server.options/plantpulse-storage/...Storage
spark-env.sh · spark-defaults.conf · hive-site.xml · kyuubi-defaults.conf · gravitino-iceberg-rest-server.conf/plantpulse-analytics/...Analysis
workflow.yaml · application.yaml/plantpulse-workflow/...Temporal / Kestra

plantpulse-websocket.properties also does not exist. There are no WebSocket/STOMP series configuration files. template/cluster/ is a worker-node-specific override — if the master template is modified, this must also be synchronized.

plantpulse-batch.properties​

Consists of connection blocks (Platform/Metastore/Cache/TSE/Kafka/Aster TSDB/Spark) and batch operation settings. Note that connection keys differ from storage/jdbc — e.g., Aster TSDB uses storage.db.host / storage.db.port / storage.db.keyspace (server uses storage.host / storage.port / storage.keyspace).

PropertyDefaultDescription
platform.host${PP_MASTER_IP}Platform(server-web) host
mq.port9092Kafka port (Literal — not substituted)
kafka.topicpp-batchBatch input topic
kafka.group.idPP-BATCH-GROUPBatch consumer group
batch.timer_schedule_delay5000Batch timer cycle (ms)
batch.thread_pool_batch_thread_size4Number of batch worker threads
batch.buffer_drain_limit_size10000Max items to empty at once
batch.sync.inmemory.enabledfalseIn-memory synchronization
batch.sync.inmemory.ttl.minute10In-memory synchronization TTL (minutes)
batch.sync.tse.enabledtrueDistribution to TSE
batch.sync.external.db.enabledfalseExternal DB synchronization
external.db.nameTIMESCALEDBExternal DB type. INFLUXDB/QUESTDB blocks are in comment state in the template
analytics.urljdbc:spark://${PP_SPARK_HOST}:${PP_KYUUBI_PORT}/defaultSpark Thrift JDBC

plantpulse-cep.properties​

PropertyDefaultDescription
cep.backendasterBackend to boot (aster · flink). Any other value causes boot failure — Backends
cep.aster.state.enabledtruePreserve Aster CEP rule states (window · aggregation · in-progress pattern) in cache.* Redis. Key is PP:CEP:ASTER-STATE:<문장>
cep.aster.state.snapshot_interval_ms60000Snapshot cycle — maximum state that can be lost during crash. Normal shutdown takes a final snapshot before exiting
cep.async.core_pool_size32Async core pool
cep.async.max_pool_size256Async max pool
cep.async.queue_capacity50000Async queue
cep.async.keep_alive_seconds60Thread keep-alive
cep.async.shutdown_timeout_seconds30Graceful shutdown wait
cep.consumer.thread_count16Consumer thread
cep.stream.shard_count16Stream shard count
cep.stream.drain_limit_size1000Drain limit
cep.stream.drain_warn_ms1000Drain warning (ms)
cep.monitor.initial_delay_seconds5Monitor initial delay
cep.monitor.interval_seconds1Monitor cycle
cep.monitor.store_interval_seconds60Aster TSDB metric storage cycle
cep.api.key${PP_CEP_API_KEY}EQL management endpoint authentication (X-API-Key)
cep.api.max_eql_text_length100000Max EQL text length (DoS defense)
cep.storage.request_timeout_seconds10Aster TSDB request timeout
cep.storage.connect_max_retries3Connection retry
cep.storage.ttl_seconds864000Metric TTL (seconds, 10 days)
cep.stream.pending_idle_threshold_ms60000Pending idle threshold
cep.stream.cleaner_initial_delay_ms60000Cleaner initial delay
cep.stream.cleaner_interval_ms10000Cleaner cycle
cep.stream.max_clean_duration_ms30000Max clean duration
cep.stream.cleaner_max_claim_count5000Max claim count
cep.stream.ack_chunk_size500ACK chunk size
cep.stream.max_deliveries3Events are sent to dead letter only after being delivered this many times without being processed
cep.stream.dead_letter.retention_ms86400000Dead letter retention age (24 hours)
cep.stream.dead_letter.max_bytes268435456Dead letter byte budget (256 MiB, total across shards). If exceeded, oldest entries are cut from each shard

plantpulse-jdbc.properties​

Integrated connection settings for external JDBC clients (SQL module · Data Gateway). Prefix is jdbc.<tech> (postgres/cassandra/spark/tse).

PropertyValueDescription
jdbc.postgres.driverorg.postgresql.DriverMETA / PQL
jdbc.postgres.urljdbc:postgresql://${PP_POSTGRES_HOST}:${PP_POSTGRES_PORT}/${PP_DB_NAME}?characterEncoding=UTF-8
jdbc.cassandra.driverplantpulse.cassandra.jdbc.CassandraDriverOLTP Time Series(CQL). Driver value is for configuration consistency (not used functionally)
jdbc.cassandra.urljdbc:cassandra://${PP_CASSANDRA_HOST}:${PP_CASSANDRA_PORT}/${PP_SCHEME}
jdbc.tse.driverplantpulse.timeseries.tql.TQLDriverOTAP / TQL
jdbc.tse.urljdbc:ts://${PP_TSE_HOST}:${PP_TSE_PORT}/${PP_SCHEME}⚠️ Fixed to plain http(ts/7800)
jdbc.spark.driverplantpulse.spark.jdbc.SparkSQLDriverOLAP Analysis
jdbc.spark.urljdbc:spark://${PP_SPARK_HOST}:${PP_KYUUBI_PORT}/default/${PP_SCHEME}
data.gateway.api.key${PP_DATA_GATEWAY_API_KEY}For JDBC call authentication

⚠️ Do not change jdbc.tse.url to https(tss/7801). The TQL JDBC driver uses the plaintext TSE listener (7800). TSE clients default globally to plaintext http/7800 (2026-08, env.sh TSE section). If caught as tss/7801, JDBC connection fails → data-gateway boot fails → all /api/v1/* return 404 → analytics catalog 404. Therefore, it is pinned to ts/PP_TSE_PORT.

jdbc.spark.username is the analysis-only account ${PP_ANALYTICS_USER}. It is separate from the Kyuubi internal metastore account (PP_HIVE_*). Optional keys jdbc.<tech>.pool.initial|min|max (postgres/spark/tse) and jdbc.<tech>.query.timeout|fetch-size can be used (full reference in plantpulse-jdbc/docs/configuration.md). jdbc.cassandra.local-datacenter is in a comment state in the template and is datacenter1 when unconfigured.

plantpulse-data-gateway.properties​

PropertyDefaultDescription
data.gateway.api.key${PP_DATA_GATEWAY_API_KEY:ADFA-URDV-QWED-1234}API authentication key (Required). Dev default to be replaced upon delivery
data.gateway.rate.limit1000Max requests per second (Based on IP + API key)
data.gateway.slow.query.ms10000Slow query warning threshold (ms)
data.gateway.slow.update.ms2000Slow update warning threshold (ms)
data.gateway.async.timeout.ms60000Async timeout (ms)

plantpulse-datalake-admin-api.properties​

Collection of JMX/management endpoints for each service based on a single node (type=MASTER). This is the only file that uses underscores (_) instead of dots (.) for keys.

PropertyDefaultDescription
typeMASTERSingle node or cluster master
db_typeCASSANDRAMonitored DB type
master / host${PP_MASTER_IP} / ${PP_HOST_IP}Master / Self host
db_host · db_port · db_keyspace · db_username · db_password · db_replication_factor${PP_CASSANDRA_*} · 9042 · ${PP_SCHEME} · 1Aster TSDB connection
tse_host · tse_port · tse_protocol · tse_username · tse_password${PP_TSE_*} · 7801 · https · tse · tse123!TSE connection (Metric loading)
kafka_jmx_uriservice:jmx:rmi:///jndi/rmi://${PP_KAFKA_HOST}:7299/jmxrmiKafka JMX
mqtt_jmx_uri...://${PP_MQTT_HOST}:7279/jmxrmiHiveMQ JMX
cep_jmx_uri...://${PP_HOST_IP}:6499/jmxrmiCEP JMX
datagateway_jmx_uri...://${PP_HOST_IP}:7499/jmxrmiData Gateway JMX
sql_jmx_uri...://${PP_HOST_IP}:7599/jmxrmiSQL JMX
tse_jmx_uri...://${PP_HOST_IP}:7899/jmxrmiTSE JMX
cassandra_jmx_uri...://${PP_CASSANDRA_HOST}:7199/jmxrmiAster TSDB JMX
spark_jmx_uri...://${PP_SPARK_HOST}:10010/jmxrmiSpark JMX
redis_jmx_uriredis://${PP_REDIS_HOST}:${PP_REDIS_PORT}?password=...Valkey connection URI
redis_ssl_truststore_location / _password / _type / redis_ssl_endpoint_identification_enabledp12 · ${PP_TLS_TRUSTSTORE_PASSWORD:kopens123!} · PKCS12 · falseValkey TLS
postgres_jmx_urijdbc:postgresql://.../${PP_DB_NAME}?user=...&password=...PostgreSQL connection URI

JMX Port Summary: HiveMQ 7279, Kafka 7299, CEP 6499, Data Gateway 7499, SQL 7599, TSE 7899, Aster TSDB 7199, Spark 10010.

plantpulse-warehouse.properties​

Aster TSDB → Iceberg(S3) archive batch. Only this file uses UPPER_SNAKE_CASE keys (UPPER_SNAKE).

GroupKeyDefault
TemporalTEMPORAL_SERVER · TEMPORAL_TASK_QUEUE · TEMPORAL_WORKFLOW_ID · TEMPORAL_SCHEDULE_ID · OPTIMIZER_SCHEDULE_ID · OPTIMIZER_WORKFLOW_ID${PP_TEMPORAL_HOST}:${PP_TEMPORAL_PORT} · PP-S3-QUEUE · PP-S3-ARCHIVER-DAILY-WORKFLOW · PP-S3-ARCHIVER-DAILY · PP-S3-OPTIMIZER-WEEKLY · PP-S3-OPTIMIZER-WEEKLY-WORKFLOW
ScheduleDAILY_HOUR · DAILY_MINUTE · OPTIMIZER_DAY_OF_WEEK · OPTIMIZER_HOUR · OPTIMIZER_MINUTE · TIMEZONE2 · 20 · 0(Sunday) · 3 · 0 · ${PP_TZ}
Execution ModeARCHIVER_MODESHELL (or KESTRA)
KestraKESTRA_SERVER · KESTRA_NAMESPACE · KESTRA_TASK_ID · KESTRA_USER · KESTRA_PASS${PP_KESTRA_HOST}:${PP_KESTRA_PORT} · plantpulse · plantpulse-daily-s3-archiver · admin@plantpulse.io · (Empty)
ScriptS3_SCRIPT_DIR · S3_SCRIPT_NAME · S3_OPTIMIZER_SCRIPT_NAME${PP_HOME}/plantpulse-warehouse/s3 · archive.sh · optimize.sh
SparkSPARK_APP_NAME · SPARK_MASTER · SPARK_JAR_PATH · SPARK_DRIVER_MEMORY · SPARK_EXECUTOR_MEMORY · SPARK_EXECUTOR_CORES · SPARK_NUM_EXECUTORS · ARCHIVER_PARALLELISM · SPARK_CHECKPOINT_DIRPP-SPARK-S3-LAKEHOUSE · local[*] · .../plantpulse-warehouse-s3.jar · 2g · 4g · 4 · 3 · 4 · s3a://${PP_S3_BUCKET:-plantpulse}/spark-checkpoint/
Source/TargetCASSANDRA_CATALOG · CASSANDRA_DATABASE · S3_BUCKET · ICEBERG_CATALOG · ICEBERG_DATABASEcassandra · ${PP_SCHEME:pp} · ${PP_S3_BUCKET:-plantpulse} · spark_catalog · ${PP_SCHEME:pp}
OptimizationSNAPSHOT_RETENTION_DAYS · OPTIMIZER_MIN_INPUT_FILES · OPTIMIZER_TARGET_FILE_SIZE_BYTES3 · 10 · 134217728 (128MB)
TimeoutARCHIVER_WF_EXECUTION/RUN/TASK_TIMEOUT_HOURS · OPTIMIZER_WF_EXECUTION/RUN/TASK_TIMEOUT_HOURS · ACTIVITY_MAX_ATTEMPTS · ACTIVITY_TIMEOUT_HOURS · OPTIMIZER_ACTIVITY_TIMEOUT_HOURS · SCRIPT_TIMEOUT_SECONDS · OPTIMIZER_TIMEOUT_SECONDS · HEARTBEAT_INTERVAL_SECONDS12/12/12 · 8/7/12 · 3 · 12 · 8 · 21600(6h) · 25200(7h) · 60
WebWEB_SERVER_PORT9600

Messaging / Auth Source Template​

plantpulse-mqtt.properties — HiveMQ broker configuration.

PropertyDefault
mqtt.host · mqtt.user · mqtt.password${PP_MQTT_HOST} · ${PP_MQ_USER} · ${PP_MQ_PASSWORD}
mqtt.port · mqtt.ssl.enabled${PP_MQTT_TLS_PORT} · true
mqtt.websocket_port8888
mqtt.data_dir/data1/pp-data/hivemq

plantpulse-mq-auth.properties — Auth source pointed to by HiveMQ security extension (FileAuthAuthenticator) via HIVEMQ_AUTH_FILE environment variable. Only two keys: mqtt.user / mqtt.password.

hive-auth.properties — Read by plantpulse-hive-auth (PasswordAuthenticator). Either HIVE_AUTH_FILE environment variable or $PP_HOME/plantpulse-analytics/spark/conf/hive-auth.properties. Notably, the key name itself is a placeholder.

${PP_HIVE_USER}=${PP_HIVE_PASSWORD}
${PP_ANALYTICS_USER}=${PP_ANALYTICS_PASSWORD}

kafka.properties — KRaft mode Kafka broker. Main values: process.roles=broker,controller, node.id=1, num.partitions=4, 3 types of listeners (SASL_PLAINTEXT/CONTROLLER/SASL_SSL), sasl.enabled.mechanisms=PLAIN, super.users=User:admin, allow.everyone.if.no.acl.found=false, log.dirs=${PP_DATA_DIR}/kafka/kraft_combined_logs, log.retention.ms=3600000 (1 hour), message.max.bytes=157286400, default.replication.factor=1, auto.create.topics.enable=true.

⚠️ log.retention.ms=3600000 = 1 hour. Based on the premise that Kafka acts as a buffer and persistence is handled by Aster TSDB/TSE. If a consumer stops for more than 1 hour, data is lost.

Plugin Template​

plantpulse-plugin-opcua.properties — PostgreSQL / Aster TSDB / Valkey / Kafka connections + OPC UA server endpoint.

PropertyDefaultDescription
kafka.topicpp-tag-point⚠️ Literal — not ${PP_TOPIC_PREFIX} substitution
kafka.thread · kafka.group.id8 · opcua-plugin-group
opc.ua.server.domain · opc.ua.server.port${PP_HOST_IP} · 8007
opc.ua.server.user · password · anonymousopcua · 설치-시-변경 · false
opc.ua.server.tcp.port · tls.port${PP_OPCUA_TCP_PORT:11004} · ${PP_OPCUA_TLS_PORT:11005}
redis.thread · redis.ssl.enabled4 · false

plantpulse-plugin-aas.properties — AAS V3 server + Kafka consumption settings.

PropertyDefaultDescription
aas.v3.port${PP_AAS_V3_PORT:8090}V3 HTTP port
kafka.topic${PP_TOPIC_PREFIX}-tag-pointReal-time tag point reception
kafka.thread · kafka.poll.count8 · 1000
group.id · auto.offset.reset · enable.auto.commitpp-plugin-aas-server · earliest · false
session.timeout.ms · auto.commit.interval.ms30000 · 1000
plugin.message.listenerplantpulse.plugin.opcua.messaging.KafkaPluginMessageListener

BaSyx V2 registry/AAS ports are hardcoded in code, not configured — REGISTRY_PORT=4800, AAS_PORT=4801 of AASServer.java.


Engine Keys Read by Code but Missing from Template​

EngineConfig also reads the following keys. Since they are not in the template (plantpulse-engine.properties), code defaults apply normally. To change a value, you must directly add a line to plantpulse-server/config/plantpulse-engine.properties.

Edge Clock / Status Polling​

PropertyCode Default
edge.clock.poll.term.sec60
edge.clock.skew.threshold.ms10000
edge.clock.rtt.max.ms2000
edge.clock.autosync.enabledtrue
edge.clock.autosync.cooldown.ms600000
edge.clock.warn.cooldown.ms600000
edge.clock.skip.warn.count5
edge.status.poll.seconds30
edge.status.poll.jitter.max.ms3000

edge.clock.poll.term.sec and edge.status.poll.seconds determine scheduler job cycles — refer to the Edge section of the scheduler architecture for value constraints.

DDS / Event Bus / Push / Buffer​

PropertyCode Default
engine.dds.queue.size80000
engine.dds.worker.threads4
engine.dds.latency.warn.ms1000
engine.eventbus.queue.capacity65536
engine.push.threads4
engine.push.queue.size10000
engine.storage.buffer.typeKAFKA
engine.streaming.timeout.backup.queue.capacity12000000

The code default for engine.dds.enabled · engine.dds.data.tag.enabled · engine.dds.data.asset.enabled is false. Since the template specifies them as true, they are enabled only in the deployed version — deleting these three lines will silently disable DDS.

Job Thread (Not listed in template)​

PropertyCode Default
engine.job.thread.oee10
engine.job.thread.ram5
engine.job.thread.ems5
engine.job.thread.system4
engine.job.asset.slow.threshold.ms20000

⚠️ The code default for engine.job.thread.point is 4, but the template is 8 (engine.job.thread.asset matches as 8 on both sides). Deleting the template line will halve the value.

Flow Engine (Not listed in template)​

PropertyCode Default
flow.engine.enabledtrue
flow.executor.parallelism64
flow.executor.queue.capacity10000
flow.executor.queue.size10000
flow.executor.poll.timeout.ms50
flow.scheduler.pool.size4
flow.timer.pool.size2
flow.jdbc.trigger.pool.size2
flow.shutdown.timeout.sec5
flow.enabled.cache.ttl.ms5000
flow.webhook.auth.enabledtrue

Alarm / ISO Metric / OEE​

PropertyCode Default
alarm.duplicate.check.minutes10
engine.oee.debounce.ms100
iso.oee.rolling.window.minutes10
iso.ems.rolling.window.minutes10
iso.ram.rolling.window.minutes1440

Anomaly Detection Details (Asset Point / System)​

Meaningful only when enabled via engine.data.anomaly.enabled=true.

PropertyCode Default
engine.data.anomaly.asset.point.intervalMINUTE
engine.data.anomaly.asset.point.lookback.minutes14400
engine.data.anomaly.asset.point.recent.seconds600
engine.data.anomaly.asset.point.limit2100
engine.data.anomaly.asset.point.context.length2048
engine.data.anomaly.asset.point.prediction.length96
engine.data.anomaly.asset.point.score.history60
engine.data.anomaly.asset.point.threshold.k3.5
engine.data.anomaly.asset.point.threshold.min0.80
engine.data.anomaly.asset.point.threshold.max0.98
engine.data.anomaly.asset.point.topk.request5
engine.data.anomaly.asset.point.topn.report5
engine.data.anomaly.system.lookback.minutes1440
engine.data.anomaly.system.recent.seconds60
engine.data.anomaly.system.limit2100
engine.data.anomaly.system.context.length2048
engine.data.anomaly.system.pred.length96
engine.data.anomaly.system.threshold.min0.80
engine.data.anomaly.system.topk2

Non-existent Settings​

The following names appear in old documents or external materials but do not exist in templates or code. Adding settings with these names will have no effect.

Item soughtActual location
storage.postgresql.*metastore.driver / metastore.url / metastore.user / metastore.password
storage.redis.*cache.host / cache.port / cache.password / cache.ssl.*
storage.cassandra.*storage.host / storage.port / storage.keyspace / storage.user / storage.password
storage.tse.*tse.protocol / tse.host / tse.port / tse.user / tse.password
storage.ttl.realtime etc.storage.tag.point.ttl / storage.asset.data.ttl etc. per table (TTL section)
storage.compression.enable / .algorithmstorage.compression.zstd.level / storage.compression.zstd.type (Template lines are typos — Typo Key Warning)
storage.compaction.enable / .schedulestorage.table.compaction.strategy series (Compaction section)
storage.metastore.* / storage.cache.*None
mq.type / mq.kafka.bootstrap.servers / mq.kafka.group.idmq.host + mq.kafka.port. Consumer groups are code constants (PP-KAFKA-POINT-GROUP etc., Messaging Architecture), not configuration
mail.* in fileOnly one place: pp.mm_config (Migrated 2026-09-17, file deleted)
websocket.* / plantpulse-websocket.propertiesNone. STOMP/WebSocket retired 2026-07, browser push is SSE (/push/sse) — Messaging Architecture
scheduler.enabled / scheduler.thread.count / scheduler.misfire.* / scheduler.history.*None. Quartz configuration is plantpulse-server-web/src/quartz.properties (WAR classpath) — Scheduler Architecture
engine.ntp.enable / engine.ntp.serverengine.ntpdate.sync / engine.ntpdate.server.ip
engine.cep.enable / engine.cep.host / engine.cep.portengine.cep.server.ip / engine.cep.server.port / engine.cep.server.protocol
engine.anomaly.*engine.data.anomaly.*
engine.dds.enable / engine.dds.topic.prefixengine.dds.enabled, Topic prefix is PP_TOPIC_PREFIX (mq template)
engine.async.queue.size / engine.async.timeout / engine.pipeline.batch.size / engine.timeout.* / engine.dataflow.threads / engine.dataflow.buffer.sizeNone
PP_STOMP_* / PP_WEBSOCKET_* env variablesNot in env.sh

Properties Containing Passwords​

Values that must be replaced before delivery. Dev plaintext defaults are placeholders in env.sh (or template); for production/customer delivery, replace with customer-specific values or overwrite via Docker -e VAR=... / export.

FileKey
plantpulse-storage.propertiesmetastore.password · cache.password · cache.ssl.truststore.password · storage.password · tse.password · data.gateway.api.key
plantpulse-engine.propertiesapi.key · flow.webhook.api.key · engine.cep.server.api.key
plantpulse-mq.propertiesmq.password · mq.ssl.truststore.password
pp.mm_config (Mail)mail.smtp.password
pp.mm_config (AI)ai.llm.api.key — No fallback for old name ai.openai.*
plantpulse-cep.propertiescache.password · storage.password · cep.api.key
plantpulse-batch.propertiesmetastore.password · cache.password · tse.password · mq.password · storage.db.password · analytics.password · external.db.password
plantpulse-jdbc.propertiescache.password · jdbc.postgres.password · jdbc.cassandra.password · jdbc.tse.password · jdbc.spark.password · data.gateway.api.key
plantpulse-data-gateway.propertiesdata.gateway.api.key
plantpulse-datalake-admin-api.propertiesdb_password · tse_password · redis_jmx_uri (password in URL) · redis_ssl_truststore_password · postgres_jmx_uri (password in URL)
plantpulse-mqtt.properties · plantpulse-mq-auth.propertiesmqtt.password
plantpulse-plugin-opcua.propertiespostgres.password · cassandra.password · redis.password · kafka.password · opc.ua.server.password
plantpulse-plugin-aas.propertiesaas.db.password · cassandra.password · kafka.password
kafka.propertiesssl.keystore.password · ssl.key.password · ssl.truststore.password
hive-auth.propertiesEntire value is password

API Key Policy: PP_API_KEY · PP_DATA_GATEWAY_API_KEY · PP_FLOW_WEBHOOK_API_KEY · PP_CEP_API_KEY use a dev plaintext default fallback (${VAR:-<dev-default>}) — this allows dev/test to boot and deploy without additional secret injection. Do not change to hard-fail (:?) — if restart-server.sh sources env.sh, it will crash immediately and deployment will fail.

Secrets are not written in configuration files. Collect them in a single sidecar file and use 0600.

ls -l /etc/kopens/plantpulse-platform.env # 비밀 — 0600, repo 밖
ls -l /etc/kopens/platform.node.env # 이 박스 고유 값 — 0600

# 값을 바꿀 때는 파일을 열지 말고 도구를 씁니다
cd /opt/kopens/plantpulse-platform-docker
bin/passwd.sh --list # 바꿀 수 있는 키
bin/passwd.sh PP_PG_PASSWORD # 서버 계정 변경 → 사이드카 → 재렌더 → 재시작

Since the rendered configuration files contain the substituted values, do not commit those files to the repository.