Skip to main content

Property Reference

This document is regenerated from the actual deployed configuration template (*.properties) (2026-07-28) — the template's current location is plantpulse-datalake-cli/config/templates, and the host's /etc/kopens/conf is bind-mounted to that location. The single source of truth for the deployment path mapping is plantpulse-startup/src/plantpulse/startup/config/ConfigTemplates.java, and the single source of truth for loading priority is plantpulse-core/src/plantpulse/core/engine/utils/PropertiesUtils.java.

If you add/remove/rename a key, the template is the source of truth, not this document. Don't hand-fill the document — regenerate it from the template. The "Default" column in each table is exactly as written in the template, and ${PP_XXX} is where configure.sh substitutes the env.sh value.

Three-Stage Configuration Model

StageLocationHow to change
Global configplantpulse-startup/env.shEdit directly, then ./configure.sh → restart the corresponding module
Site overrideplantpulse-startup/env.local.shenv.sh is entirely in ${PP_VAR:-default} form, so an already-exported value wins
Module configeach module's config/Can be edited directly, but will be overwritten the next time configure.sh runs

Recommendation: In production, edit only env.sh (or env.local.sh) and let configure.sh generate all module configurations.

Standard procedure for changing env.sh

cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin

vi env.sh # 1. 편집
./env-validate.sh # 2. 검증 (선택)
./configure.sh # 3. 템플릿 치환 + 각 모듈 config/ 로 배포
./restart.sh # 4. 재시작 (또는 ./restart-<module>.sh)
./status.sh # 5. 확인

configure.sh only re-renders the configuration files; it does not restart the services. Until a restart, the new configuration exists only on disk while the old process is still alive.

Configuration File Loading Priority

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

  1. The directory specified via the -Dpp.conf.dir system property (constant PropertiesUtils.CONF_DIR_SYSTEM_PROPERTY = "pp.conf.dir")
  2. ${catalina.base}/../config — the module's config/ directory
  3. The web app classpath (default bundled in the WAR) — fallback

External files are read as UTF-8. When an external configuration loads successfully, the following is printed in the startup log:

Properties loaded from external conf: <absolute-path>

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

Logging configuration (log4j2.xml) is also externalized through the same chain (self-seeding — if no external file exists, the WAR default is copied once to the module's config/log4j2.xml before use). When applied, Logging reconfigured from external conf: <absolute-path> is printed in the startup log. Log level changes are applied by editing the module's config/log4j2.xml and restarting, and this persists across WAR redeployments. See the configuration and deployment guide for details.

Note: Do not edit internal web app files (e.g. server/webapps/ROOT/WEB-INF/classes/) directly — they disappear on WAR redeployment.

${ENV:기본값} Substitution Happens Twice

The ${PP_XXX} / ${PP_XXX:기본값} notation in the template is resolved at two points in time.

Point in timeActorBehavior
At deploymentconfigure.shTemplateProcessor.resolvePlaceholdersSubstituted with env.sh. Order is replacements map → environment variables → :기본값 → keep original. Nested placeholders not supported
At runtimePropertiesUtils.resolveEnvPlaceholdersRe-resolves ${ENV_VAR[:default]} against every value in the loaded Properties

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

PP_* Variables Not in env.sh (the template default applies as-is)

The variables below are referenced by the template as ${PP_XXX:기본값}, but env.sh does not export them. So unless injected separately, the template default is always used.

PP_STORAGE_PASSWORD · PP_METASTORE_PASSWORD · 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_OPENAI_CHAT_PATH · PP_AI_OPENAI_RESPONSES_PATH · PP_AI_MCP_ENABLED · PP_AI_MCP_ALLOWED_ORIGINS · PP_AI_CHAT_ENABLED

PP_MAIL_SMTP_* is intentionally not exported. As the env.sh comment notes, there was an incident where an exported environment variable silently overrode the template default (the Brevo relay SSOT), breaking the SMTP login combination (2026-07-22, a stale 25/no-auth value masked the Brevo 587/auth value). Site-specific overrides belong in env.local.sh.

The 5 Server-Managed Configurations

There are exactly 5 configuration files defined by the ConfigTemplates.SERVER_CONFIGS array and deployed via 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
4plantpulse-mail.properties/plantpulse-server/config/plantpulse-mail.properties
5plantpulse-ai.properties/plantpulse-server/config/plantpulse-ai.properties

Of these, 1–4 are read together by PropertiesLoader.load() (engine/mail/mq/storage) and reconstructed into the typed configuration beans EngineConfig · StorageConfig · MqConfig. Item 5 (plantpulse-ai.properties) is read separately by AIConfig through the same external chain.

plantpulse-startup/sh/server-managed-webapp-files.list is currently empty (comments only). This is because, after the 2026-06 configuration externalization was completed, no server-managed configuration remains inside the WAR.

application.properties (Removed)

application.properties was removed in 2026.06. No code reads this file (zero usages across the entire repo), and its existing entries were migrated as follows.

  • Theme / homepage and other console behavior settings → console System > Settings Management (PostgreSQL mm_config table)
  • alarm.duplicate.check.minutes → the plantpulse-engine.properties family (read by EngineConfig)

plantpulse-engine.properties

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

Controls the core behavior of the data processing engine.

Async / Pipeline

PropertyDefaultSubstitutionDescription (template comment)
engine.async.parallelism256Async worker pool parallelism (total cores ~= 256)
engine.pipeline.threads36Number of pipeline threads
engine.pipeline.ratelimit40000Pipeline per-second processing cap (rate limit)
engine.pipeline.queue.size1200000Pipeline queue size (backpressure limit)
engine.pipeline.queue.o3.delay50Allowed delay for out-of-order data (ms)
engine.pipeline.task.modeSINGLETask execution mode (SINGLE / PARALLEL)

NTP

PropertyDefaultSubstitutionDescription
engine.ntpdate.server.ip127.0.0.1NTP server IP
engine.ntpdate.syncfalseWhether to perform NTP sync at boot

Stream / CEP

PropertyDefaultSubstitutionDescription
engine.stream.processorDIRECTStream 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-aligned to protocol: http→7400, https→7401)
engine.cep.server.protocolhttp${PP_CEP_PROTOCOL:http}CEP protocol. Default http for internal communication; https for distributed/containerized
engine.cep.server.api.key(none)${PP_CEP_API_KEY}For the CEPClient X-API-Key header. Must match the CEP server's cep.api.key

Streaming Message Delivery

PropertyDefaultSubstitutionDescription
engine.streaming.messaging.warning.ms5000Message delivery delay warning (ms)
engine.streaming.messaging.timeout.ms10000Message delivery timeout (ms)
engine.streaming.messaging.timeout.store.typeFILE_QUEUEStorage method for timed-out messages (FILE_QUEUE/MEMORY)
engine.streaming.messaging.timeout.recovery.typeDBRecovery source for timed-out messages (DB/FILE)

Job Worker Threads

PropertyDefaultSubstitutionDescription
engine.job.thread.asset8Number of asset job threads
engine.job.thread.point8Number of point job threads

DDS

PropertyDefaultSubstitutionDescription
engine.dds.enabledtrueGlobal DDS enable
engine.dds.data.tag.enabledtruePublish tag data to DDS
engine.dds.data.asset.enabledtruePublish asset data to DDS

Anomaly Detection / Dataflow

PropertyDefaultSubstitutionDescription
engine.data.anomaly.enabledfalseEnable anomaly detection (external service integration)
engine.data.anomaly.urlhttps://127.0.0.1:8970Anomaly detection service URL
engine.dataflow.classplantpulse.core.engine.pipeline.dataflow.BaseDataFlowDataflow implementation class
engine.dataflow.server-timestamp.overridefalseWhether to force server timestamp (true: collection time, false: original)
engine.dataflow.negative-timestamp.overridetrueWhether to correct negative timestamps
engine.factory.model.updater.classplantpulse.core.engine.model.impl.DefaultFactoryMetaModelUpdaterFactory metamodel updater
engine.event.handler.classplantpulse.core.engine.event.DefaultEventHanlderEvent handler implementation (the class name typo Hanlder is kept exactly as the actual class name)
engine.javagc.enabledfalseWhether to allow explicit System.gc() calls

Flow Engine

PropertyDefaultSubstitutionDescription
flow.debug.execution.logfalseNode execution INFO logging. Set true only for debugging sessions
flow.stats.prune.interval.ms86400000Counter cleanup interval (ms, 24 hours). Cassandra counter tables can't use default_time_to_live, so cleanup happens at the application level
flow.stats.prune.hourly.days30Retention days for hour_bucket of tm_flow_stats_hourly
flow.stats.prune.daily.days90Retention days for day_bucket of tm_flow_stats_daily
flow.health.check.interval.ms600000Flow health check interval (ms, 10 min). ERROR if errors > 0 in the current time bucket, otherwise NORMAL (KST-based)
flow.webhook.api.keydev-webhook-19ba7a54-1132-49f2-967e-3c6f5cd989a0${PP_FLOW_WEBHOOK_API_KEY:...}Flow engine external webhook authentication

Cassandra tables used by the 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.ms600000Edge health check interval (ms, 10 min)

The determination source is the _ON / _NORMAL flags in the Cassandra tm_edge_status payload. There is no RT REST call, so load is 0 and it finishes within a 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.enabledtrueV5 API auth brute-force defense
engine.api.v5.auth.bruteforce.ip_limit30Attempt limit per IP
engine.api.v5.auth.bruteforce.user_limit10Attempt limit per user
engine.api.v5.auth.bruteforce.window.seconds60Counting window (seconds)
engine.api.v5.trusted_proxies(empty)Trusted proxy IP allowlist. Only when set, if remoteAddr is in this list, the first IP in X-Forwarded-For is used as the 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_limit30Attempt limit per IP
engine.session.bruteforce.user_limit10Attempt limit per user
engine.session.bruteforce.window.seconds300Counting 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.enabledtrueCleanup of expired (expires_at < now) / revoked (revoked_at IS NOT NULL) tokens
engine.api.token.cleanup.retention_days30Hard delete from mm_token after this period elapses. Runs once every 24 hours (first run 60 seconds after boot)
engine.api.token.default_ttl_days90Default expiration (days) for newly issued tokens. 0 = permanent token. If the issuance request supplies ttl_days, that value takes priority → API Token Issuance

Existing tokens whose expires_at is NULL remain permanently active (backward compatibility).


plantpulse-storage.properties

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

Manages connections to the metastore (PostgreSQL) · cache (Valkey) · time series (Cassandra) · TSE · Data Gateway, along with storage policy.

⚠️ This file actually contains typo'd keys. 3 keys are spelled differently from what the code reads — be sure to read the Typo Key Warning section.

PostgreSQL Metastore

PropertyDefaultSubstitutionDescription
metastore.driverorg.postgresql.DriverJDBC driver class
metastore.urljdbc:postgresql://...${PP_POSTGRES_HOST} · ${PP_POSTGRES_PORT} · ${PP_DB_NAME}Metastore JDBC URL. Includes the ?characterEncoding=UTF-8&reWriteBatchedInserts=true query string
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.enabledfalseCache TLS. Default redis:// for internal clients
cache.ssl.truststore.location/var/security/plantpulse/master/master.truststore.p12Truststore path
cache.ssl.truststore.passwordkopens123!${PP_TLS_TRUSTSTORE_PASSWORD:kopens123!}Truststore password
cache.ssl.truststore.typePKCS12Truststore type
cache.ssl.endpoint.identification.enabledfalseEndpoint identification validation

The single source of truth for key constants is InMemoryConfigKeys in plantpulse-inmemory.

TSE (TimeSeries Engine)

PropertyDefaultSubstitutionDescription
tse.protocolhttp${PP_TSE_PROTOCOL:http}TSE protocol. Defaults to plaintext http since it's internal communication (2026-08)
tse.host${PP_TSE_HOST}TSE host
tse.port7800${PP_TSE_CONNECT_PORT:7800}TSE port. Defaults to plaintext listener 7800
tse.usertse${PP_TSE_USER:tse}TSE account
tse.passwordtse123!${PP_TSE_PASSWORD:tse123!}TSE password

Cassandra Time Series Storage

PropertyDefaultSubstitutionDescription
storage.db_typeCASSANDRADB kind (template comment still says CASSANDRA/DSE/SCYLLADB, but currently Cassandra-5.0-only)
storage.db_version5.0DB version (determines driver/feature compatibility)
storage.host${PP_CASSANDRA_HOST}Contact point host
storage.port9042${PP_STORAGE_PORT:9042}Native protocol port
storage.keyspace${PP_KEYSPACE}Keyspace to use
storage.user${PP_CASSANDRA_USER}Connection account
storage.passwordcassandra${PP_STORAGE_PASSWORD:cassandra}Password. PP_STORAGE_PASSWORD is not exported by env.sh → default applies
storage.durable_writestrueWhether to use the commit log (⚠️ no code reads this — 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 Interval

PropertyDefaultDescription
storage.asset.data.snapshot.interval10 SECONDSRecords every asset's tag map (data_map) into the asset_data series (data/second/timestamp + minute/hour/day boundaries) before each cycle

The template comment states the rationale: at 1 SECONDS, with 121 assets, it was about 22K writes/min (roughly 4% of all Cassandra writes) — too dense. Since the tag original (per second) is fully preserved in tm_tag_point/TSE, the asset-view snapshot interval was lowered to 10s (matching the code default) — writes −90%, while retaining recording completeness.

This value becomes the ASSET_DATA_JOB interval for the scheduler. It must be in "<n> <unit>" two-token format — see the scheduler architecture for the rules.

Internal Metastore Sync (Experimental)

PropertyDefaultDescription
storage.internal.metastore.enabledfalseEnable internal metastore sync
storage.internal.metastore.thread.count4Number of sync worker threads
storage.internal.metastore.queue.size12000000Sync queue size
storage.internal.metastore.point.retation.days10Point retention days (⚠️ typo'd key — see below)

Row Cache

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

Compaction

PropertyDefaultDescription
storage.table.compaction.strategyUCSDefault strategy (TWCS: TimeWindow, UCS: Unified). Read by CassandraCreateDAO (code fallback is TWCS)
storage.table.compaction.strategy.twcs.window_size1TWCS window size — ⚠️ no code reads this
storage.table.compaction.strategy.twcs.window_unitDAYSTWCS window unit — ⚠️ no code reads this
storage.table.compaction.strategy.ucs.scailing_parameterT8UCS scaling parameter (T8 = tiered 8 levels). Key spelling scailing matches the 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 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.level3zstd compression level (1~22) — ⚠️ typo'd key, see below
storage.tag.point.select.limit.size1000000Max rows for a single tag point select
storage.doamin.model.changed.to.metastore.backuptrueMetastore backup on domain model change — ⚠️ typo'd key + no code reads this
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'd Keys — Editing Them Has No Effect

The 3 keys below actually exist in the template but are spelled differently from what the code reads. If an administrator changes the value on these lines, it is silently ignored and the code default applies.

Key in template (typo)Key code actually readsCode defaultRead location
storage.compresion.zstd.levelstorage.compression.zstd.level3StorageConfigCassandraCreateDAO
storage.internal.metastore.point.retation.daysstorage.internal.metastore.point.retention.days10StorageConfigPointDAO
storage.doamin.model.changed.to.metastore.backupnone (no code reads it even with correct spelling)

To actually change the value, add the correctly-spelled key to the same file. For example, to raise the zstd level to 6, you must add storage.compression.zstd.level=6 (this means adding a new correctly-spelled line, not fixing the typo'd one). Leaving the typo'd line in place is harmless, but the real fix is to correct the template itself.

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

Storage Keys Not in the Template but Read by Code

PropertyCode DefaultDescription
storage.compression.zstd.typeZstdCompressorCompressor class name

Storage Template Keys with No Reading Code (editing has no effect)

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'd keys above)

Even changing the two TWCS-related keys to storage.table.compaction.strategy=TWCS will not 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 publish topics. The code-side SSOT is MqConfig (connection) 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_PLAINTEXTKafka security protocol
mq.ssl.truststore.location/var/security/plantpulse/master/master.truststore.p12Messaging TLS truststore (MQTT + optional Kafka TLS)
mq.ssl.truststore.passwordkopens123!${PP_TLS_TRUSTSTORE_PASSWORD:kopens123!}Truststore password
mq.ssl.truststore.typePKCS12Truststore 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.enabledtrueUse MQTT TLS

Beyond 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 present in the template; mq.ssl.* is used 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 full set of keys and defaults is documented under Messaging Architecture → DDS Publish Topics. Topic values are part of the Kafka/MQTT wire contract and UNSTopicDefaultsContractTest freezes the literals, so arbitrary changes are prohibited.

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


plantpulse-mail.properties

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

SMTP/SMS settings for sending alarms/reports.

PropertyDefaultSubstitutionDescription
mail.send.enabledfalse${PP_MAIL_SEND_ENABLED:false}Master send gate. Unless true, all mail sending logs a WARN only and is skipped (no SMTP attempt is made at all). Site-specific opt-in
mail.smtp.hostsmtp-relay.brevo.com${PP_MAIL_SMTP_HOST:...}SMTP host
mail.smtp.port587${PP_MAIL_SMTP_PORT:587}SMTP port (25:plain, 465:SSL, 587:STARTTLS)
mail.smtp.authtrue${PP_MAIL_SMTP_AUTH:true}Whether SMTP auth is used
mail.smtp.userb2df89001@smtp-brevo.com${PP_MAIL_SMTP_USER:...}SMTP sender account
mail.smtp.passwordbskHIVJqcFQaFtb${PP_MAIL_SMTP_PASSWORD:...}SMTP password (dev default — replace before delivery)
mail.smtp.starttls.enabletrue${PP_MAIL_SMTP_STARTTLS:true}Whether to use STARTTLS
sms.sender.classplantpulse.cep.listener.alarm.sms.DefaultSMSSenderSMS send implementation class (CEP listener)
diagnostic.log.emaildiag@kopens.com${PP_DIAGNOSTIC_EMAIL:diag@kopens.com}Diagnostic notification recipient email — ⚠️ no code reads this

PP_MAIL_SMTP_* is not exported by env.sh. This template (the Brevo relay) is the SSOT, and overriding via environment variable silently breaks the login combination. Site overrides belong in env.local.sh. See the substitution section for background.


plantpulse-ai.properties

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

Manages the OpenAI-compatible AI gateway and AI feature flags. On the code side, plantpulse.core.service.ai.AIConfig reads it via the same external configuration chain.

Gateway

PropertyDefaultSubstitutionDescription
ai.openai.enabledfalse${PP_AI_OPENAI_ENABLED:false}Master feature flag. If false, the AI UI/endpoints are hidden and disabled
ai.openai.base.urlhttps://api.openai.com${PP_AI_OPENAI_BASE_URL:...}OpenAI-compatible gateway. No trailing slash
ai.openai.chat.path/v1/chat/completions${PP_AI_OPENAI_CHAT_PATH:...}chat completions path
ai.openai.responses.path/v1/responses${PP_AI_OPENAI_RESPONSES_PATH:...}responses path
ai.openai.api.key(empty)${PP_AI_OPENAI_API_KEY:}LiteLLM virtual key / proxy key. No repository default
ai.openai.modelgpt-5-mini${PP_AI_OPENAI_MODEL:gpt-5-mini}Model name exposed by LiteLLM config.yaml
ai.openai.timeout.ms15000Request timeout (ms)
ai.openai.max.output.tokens1200Max output tokens
ai.openai.temperature-1Sampling temperature. If negative, the parameter is omitted from the request body entirely

⚠️ ai.openai.temperature pitfall. The gpt-5 family (gpt-5-mini, gpt-5.5, etc.) doesn't support temperature, and sending anything other than the default of 1 causes a 400 Unsupported value. So it must be left negative (an omission sentinel). The template comment's mention of "default 0.1" refers to the LiteLLM/vLLM gateway (gpt-4o, etc.); the current template's actual value is -1.

Operations Assistant

PropertyDefaultDescription
ai.alarm.rca.enabledtrueAlarm root cause analysis
ai.alarm.eql.enabledtrueAlarm EQL assistance
ai.uns.topic.enabledtrueUNS topic assist
ai.result.audit.enabledtrueAI result audit
ai.similar.incident.enabledtrueSimilar-incident recommendation
ai.similar.incident.max.items5Max recommendation count
ai.similar.incident.min.score40Minimum recommendation score
6 Keys Removed in 2026-08

The 3 ai.diagnostic.summary.* keys (diagnostic log AI summary) and the 3 ai.operations.report.* keys (AI operations report) were removed from the product on 2026-08-25. Since the screens, JS, and controllers were removed together, restoring the values will not bring the feature back.

It's harmless if these keys remain in the configuration file after an upgrade — no code reads them, so they're simply ignored. Feel free to delete them if you want to tidy up.

MCP / Chat

PropertyDefaultSubstitutionDescription
ai.mcp.enabledtrue${PP_AI_MCP_ENABLED:true}MCP (AI chat-ops endpoint)
ai.mcp.allowed.origins(empty)${PP_AI_MCP_ALLOWED_ORIGINS:}List of allowed MCP Origins
ai.chat.enabledfalse${PP_AI_CHAT_ENABLED:false}server-web console AI chat drawer. Only works when the ai.openai.* gateway is on

Other Templates

Beyond the 5 above, template/ contains application/infrastructure configuration templates. The single source of truth for the 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/ and /plantpulse-sql/config/JDBC integration configuration (both modules share the same template)
plantpulse-data-gateway.properties/plantpulse-data-gateway/config/Data Gateway behavior
plantpulse-warehouse.properties/plantpulse-warehouse/config/Cassandra → Iceberg(S3) archive
plantpulse-monitor.properties/plantpulse-monitor/config/Monitor (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/analytics 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/...Analytics
workflow.yaml · application.yaml/plantpulse-workflow/...Temporal / Kestra
plantpulse-startup.properties(used by startup itself)Data lake health-check connection info at boot

plantpulse-sql.properties does not exist. The SQL module receives plantpulse-jdbc.properties. plantpulse-websocket.properties also does not exist. There is no WebSocket/STOMP-family configuration file. template/cluster/ is a worker-node-only override — if you edit the master template, this must be synced too.

plantpulse-batch.properties

Composed of connection blocks (platform/metastore/cache/TSE/Kafka/Cassandra/Spark) plus batch behavior settings. Note that connection key names differ from storage/jdbc — e.g., Cassandra is 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 ingestion topic
kafka.group.idPP-BATCH-GROUPBatch consumer group
batch.timer_schedule_delay5000Batch timer interval (ms)
batch.thread_pool_batch_thread_size4Number of batch worker threads
batch.buffer_drain_limit_size10000Max items flushed at once
batch.sync.inmemory.enabledfalseIn-memory sync
batch.sync.inmemory.ttl.minute10In-memory sync TTL (minutes)
batch.sync.tse.enabledtrueDistribute to TSE
batch.sync.external.db.enabledfalseSync to external DB
external.db.nameTIMESCALEDBExternal DB type. The INFLUXDB/QUESTDB blocks are commented out in the template
analytics.urljdbc:spark://${PP_SPARK_HOST}:${PP_KYUUBI_PORT}/defaultSpark Thrift JDBC

plantpulse-cep.properties

PropertyDefaultDescription
cep.ha.enabledtrueRedis-based HA kill switch (preserves deployment/named window/single-key table state across restarts)
cep.ha.snapshot.interval_ms1000Snapshot interval (non-blocking background off the event thread)
cep.ha.snapshot.named_windowstrueNamed window snapshot
cep.ha.snapshot.tablestrueTable snapshot
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 threads
cep.stream.shard_count16Number of stream shards
cep.stream.drain_limit_size1000Drain limit
cep.stream.drain_warn_ms1000Drain warning (ms)
cep.monitor.initial_delay_seconds5Monitor initial delay
cep.monitor.interval_seconds1Monitor interval
cep.monitor.store_interval_seconds60Cassandra storage interval for per-EQL-statement metrics
cep.monitor.statement_metrics_enabledtrueCollect per-statement metrics
cep.performance.cpu_warn_threshold_ns1000000000CPU warning threshold (ns)
cep.performance.wall_warn_threshold_ns1000000000Wall warning threshold (ns)
cep.api.key${PP_CEP_API_KEY}EQL management endpoint authentication (X-API-Key)
cep.api.max_eql_text_length100000EQL text max length (DOS defense)
cep.storage.request_timeout_seconds10Cassandra request timeout
cep.storage.max_inflight_writes256In-flight write cap
cep.storage.connect_max_retries3Connection retry
cep.storage.ttl_seconds864000Metrics 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 interval
cep.stream.max_clean_duration_ms30000Clean max duration
cep.stream.cleaner_max_claim_count5000Claim max count
cep.stream.ack_chunk_size500ACK chunk size

There is a rationale behind 60 of cep.monitor.store_interval_seconds — writes scale with the number of statements (asset × EMS/alarm rules, dev measured at 1,263), which produced 7.6K rows/min at 10s. Since this is used only for on-demand queries, it was relaxed to 60s (−83%).

The HA-dedicated Redis connection (cep.ha.redis.host/port/password) is commented out in the template — only enable it when using a Redis instance different from the cache.

plantpulse-jdbc.properties

Unified connection configuration for external JDBC clients (SQL module · Data Gateway). Prefixes are 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 config consistency (functionally unused)
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 analytics
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 pinned to tss/7801, the JDBC connection fails → data-gateway fails to boot → all /api/v1/* return 404 → this cascades into 404s for the analytics catalog. That's why it's pinned to ts/PP_TSE_PORT.

jdbc.spark.username is an analytics-only account, ${PP_ANALYTICS_USER}. It is separate from the Kyuubi internal metastore account (PP_HIVE_*). The optional keys jdbc.<tech>.pool.initial|min|max (postgres/spark/tse) and jdbc.<tech>.query.timeout|fetch-size can also be used (see plantpulse-jdbc/docs/configuration.md for the full reference). jdbc.cassandra.local-datacenter is commented out in the template and defaults to datacenter1 if not set.

plantpulse-data-gateway.properties

PropertyDefaultDescription
data.gateway.api.key${PP_DATA_GATEWAY_API_KEY:ADFA-URDV-QWED-1234}API auth key (required). Replace the dev default before 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-monitor.properties

A 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 (.) in keys.

PropertyDefaultDescription
typeMASTERSingle node or cluster master
db_typeCASSANDRADB type being monitored
master / host${PP_MASTER_IP} / ${PP_HOST_IP}Master / own host
db_host · db_port · db_keyspace · db_username · db_password · db_replication_factor${PP_CASSANDRA_*} · 9042 · ${PP_SCHEME} · 1Cassandra connection
tse_host · tse_port · tse_protocol · tse_username · tse_password${PP_TSE_*} · 7801 · https · tse · tse123!TSE connection (metric ingestion)
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/jmxrmiCassandra 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, Cassandra 7199, Spark 10010.

plantpulse-warehouse.properties

Cassandra → Iceberg(S3) archive batch. This is the only file where keys are UPPER_SNAKE_CASE (UPPER_SNAKE).

GroupKey KeysDefault
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-ARCHIVE-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)
ScriptsS3_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_MINIO_BUCKET:-plantpulse}/spark-checkpoint/
Source/TargetCASSANDRA_CATALOG · CASSANDRA_DATABASE · S3_BUCKET · ICEBERG_CATALOG · ICEBERG_DATABASEcassandra · ${PP_SCHEME:pp} · ${PP_MINIO_BUCKET:-plantpulse} · spark_catalog · ${PP_SCHEME:pp}
OptimizationSNAPSHOT_RETENTION_DAYS · OPTIMIZER_MIN_INPUT_FILES · OPTIMIZER_TARGET_FILE_SIZE_BYTES3 · 10 · 134217728 (128MB)
TimeoutsARCHIVER_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 Templates

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 — the auth source that the HiveMQ security extension (FileAuthAuthenticator) points to via the HIVEMQ_AUTH_FILE environment variable. There are only two keys: mqtt.user / mqtt.password.

hive-auth.properties — read by plantpulse-hive-auth (PasswordAuthenticator). Uses the HIVE_AUTH_FILE environment variable or $PP_HOME/plantpulse-analytics/spark/conf/hive-auth.properties. What's unusual is that the key name itself is a placeholder.

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

kafka.properties — Kafka broker in KRaft mode. Key values: process.roles=broker,controller, node.id=1, num.partitions=4, 3 listener types (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. The premise is that Kafka acts as a buffer, while persistence is handled by Cassandra/TSE. If a consumer is stalled for more than 1 hour, data will be lost.

Plugin Templates

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

PropertyDefaultDescription
kafka.topicpp-tag-point⚠️ literal — not a ${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 configuration.

PropertyDefaultDescription
aas.v3.port${PP_AAS_V3_PORT:8090}V3 HTTP port
kafka.topic${PP_TOPIC_PREFIX}-tag-pointReal-time tag point ingestion
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's registry/AAS ports are hardcoded in the code, not configurableREGISTRY_PORT=4800, AAS_PORT=4801 in AASServer.java.

plantpulse-startup.properties

Connection info used by Checker for the data lake/health check at boot. Composed of platform.host · metastore.* · cache.* · tse.* · storage.db.* · analytics.* · object.* (MinIO) blocks. All values are env.sh substitutions and use the same key-naming convention (storage.db.*) as the batch template.


Engine Keys Not in the Template But Read by Code

EngineConfig also reads the keys below. Since they are not in the template (plantpulse-engine.properties), the code default applies as usual; to change a value, you must add a line directly 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 the scheduler job interval — see 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. Because the template explicitly sets them to true, they are only enabled in the deployed build — deleting these three lines silently turns DDS off.

Job Threads (not listed in the 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 sets 8 (engine.job.thread.asset matches 8 on both sides). Deleting the template line halves the value.

Flow Engine (not listed in the 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 Metrics / 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

Settings That Do Not Exist

The names below appear in past documentation/external material but exist neither in the template nor in the code. Adding a setting under these names has no effect whatsoever.

What Was 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.Per-table storage.tag.point.ttl / storage.asset.data.ttl etc. (TTL Section)
storage.compression.enable / .algorithmstorage.compression.zstd.level / storage.compression.zstd.type (the template line is a typo — Typo Key Warning)
storage.compaction.enable / .scheduleThe storage.table.compaction.strategy family (Compaction Section)
storage.metastore.* / storage.cache.*None
mq.type / mq.kafka.bootstrap.servers / mq.kafka.group.idmq.host + mq.kafka.port. The consumer group is not a setting but a code constant (PP-KAFKA-POINT-GROUP etc., Messaging Architecture)
mail.* outside of plantpulse-server/config/Only in plantpulse-mail.properties
websocket.* / plantpulse-websocket.propertiesNone. STOMP/WebSocket was retired in 2026-07; browser push is SSE (/push/sse) — Messaging Architecture
scheduler.enabled / scheduler.thread.count / scheduler.misfire.* / scheduler.history.*None. Quartz configuration is at 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, the topic prefix is in 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 present in env.sh

Properties Containing Passwords

These values must be replaced before delivery. The dev plaintext defaults are placeholders in env.sh (or the template), and for production/customer delivery, either replace them with customer-specific values or override via Docker -e VAR=... / export.

FileKeys
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
plantpulse-mail.propertiesmail.smtp.password
plantpulse-ai.propertiesai.openai.api.key
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-monitor.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.propertiesThe entire value is the password

API key policy: PP_API_KEY · PP_DATA_GATEWAY_API_KEY · PP_FLOW_WEBHOOK_API_KEY · PP_CEP_API_KEY are left with a dev plaintext default fallback (${VAR:-<dev-default>}) — so dev/test can boot and deploy without injecting additional secrets. Do not change this to hard-fail (:?)restart-server.sh would die instantly while sourcing env.sh, causing deployment to fail.

# 설정 파일 권한 제한
chmod 600 /opt/kopens/plantpulse-platform/plantpulse-*/config/*.properties

# 사이트별 비밀값은 env.local.sh 로 분리 (env.sh 는 SSOT 유지)
vi /opt/kopens/plantpulse-platform/plantpulse-startup/env.local.sh

Do not commit secrets to the repository.