# Registry: Env Keys # SSOT: wiki/projects/ca-tmpl/registries/env-keys.yaml # Schema owner: feature-contract-registry-governance # Owner branch: feature-env-driven-runtime-configuration # Last updated: 2026-07-28 # # Conventions: # - Application-owned env uses `APP_` prefix, fully unified (D2, 2026-06-05): # datasource/server/etc. keys that map onto Spring properties are renamed APP_* # as well (e.g. SERVER_PORT -> APP_SERVER_PORT). # - Only env the Spring runtime reads natively stays native: SPRING_* and # SPRING_PROFILES_ACTIVE (D6 — profile selector is Spring-native, not APP_). # - `classification: secret` rows only reference secrets-classification.yaml; full row owned there. # - reload_policy default = `restart-only` (env-driven branch "config reload: no runtime reload"). # - boolean encoding = true/false only (env-driven branch 2026-05-22). # - Duration encoding = Spring shorthand (`30s`); ISO-8601 (`PT30S`) forbidden (env-driven branch 2026-05-22). # - DataSize encoding = `10MB` (env-driven branch 2026-05-22). env_keys: # === Profile / Identity (feature-env-driven-runtime-configuration) === - name: SPRING_PROFILES_ACTIVE # source: feature-env-driven-runtime-configuration D6 (2026-06-06), amended by # five-adapter-runtime-remediation §7.1. Profile selector is Spring-native and sole # (APP_PROFILE was dropped). Exactly one value, not a CSV list: two environments cannot both # have their safety rules apply, and whichever lost did so silently. type: enum # No default. A profile that is guessed is a deployment nobody chose: a jar started # with none used to become local, which before persistence was gated also meant an # in-memory database that loses every write on restart. allowed_values: [local, dev, prod] classification: public-config required: true reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: env-contract:profile-active # APP_PROFILE intentionally removed (D6, 2026-06-06): profile = SPRING_PROFILES_ACTIVE # alone. A duplicate APP_PROFILE would only add information doubling + mismatch-fail # cost. See branch note feature-env-driven-runtime-configuration Claims (wont-fix). - name: APP_NAME # source: feature-env-driven-runtime-configuration 2026-05-22 # "Required config: APP_NAME, APP_PROFILE..." type: string default: null allowed_values: null classification: public-config required: true reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: non_empty_string compatibility_impact: behavior-change required_test: env-contract:app-name-present # === HTTP server (APP_ unified per D2) === - name: APP_SERVER_PORT # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — full APP_ # unification; server.port maps from APP_SERVER_PORT. # + feature-management-actuator-security-contract 2026-05-22 "management port default = 9001 (separate from app 8080)" type: int default: 8080 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: port_range_1_65535 compatibility_impact: behavior-change required_test: env-contract:server-port-bound - name: MANAGEMENT_SERVER_PORT # source: feature-management-actuator-security-contract 2026-05-22 # "management port default = 9001 (separate from app 8080). single-port는 platform ingress 보호 + 문서화 시만 허용." type: int default: 9001 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-management-actuator-security-contract validation: port_range_1_65535 compatibility_impact: behavior-change required_test: actuator-contract:management-port-separated - name: APP_SERVER_SHUTDOWN # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (server.shutdown mode; graceful drains in-flight requests) type: enum default: graceful allowed_values: [graceful, immediate] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: env-contract:server-shutdown-mode - name: APP_SERVER_SHUTDOWN_TIMEOUT # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification. # Supersedes the old APP_SHUTDOWN_TIMEOUT row. Must stay <= k8s # terminationGracePeriod (cross-ref feature-container-runtime-contract). type: duration default: 30s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: spring_duration_shorthand_le_termination_grace compatibility_impact: behavior-change required_test: env-contract:server-shutdown-timeout-aligned - name: APP_SERVER_FORWARD_HEADERS_STRATEGY # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (trust X-Forwarded-* when behind LB/proxy) type: enum default: framework allowed_values: [none, native, framework] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: env-contract:server-forward-headers-strategy - name: APP_SERVER_TOMCAT_MAX_THREADS # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (ceiling on concurrent request workers) type: int default: 200 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: positive_int compatibility_impact: behavior-change required_test: env-contract:tomcat-max-threads-bounded - name: APP_SERVER_TOMCAT_MIN_SPARE_THREADS # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (idle worker pool floor) type: int default: 10 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: non_negative_int compatibility_impact: behavior-change required_test: env-contract:tomcat-min-spare-threads-valid - name: APP_SERVER_TOMCAT_ACCEPT_COUNT # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (OS-level backlog queue depth for incoming TCP connections) type: int default: 100 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: non_negative_int compatibility_impact: behavior-change required_test: env-contract:tomcat-accept-count-valid - name: APP_SERVER_TOMCAT_MAX_CONNECTIONS # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (hard cap on simultaneously open connections) type: int default: 8192 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: positive_int compatibility_impact: behavior-change required_test: env-contract:tomcat-max-connections-bounded - name: APP_SERVER_TOMCAT_CONNECTION_TIMEOUT # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (connection timeout for the Tomcat connector) type: duration default: 20s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: spring_duration_shorthand compatibility_impact: behavior-change required_test: env-contract:tomcat-connection-timeout-set - name: APP_SERVER_COMPRESSION_ENABLED # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (server.compression toggle) type: boolean default: true allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: boolean_strict compatibility_impact: behavior-change required_test: env-contract:server-compression-toggle - name: APP_SERVER_COMPRESSION_MIN_RESPONSE_SIZE # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (payloads below this threshold are not compressed) type: data_size default: 1KB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: spring_data_size compatibility_impact: behavior-change required_test: env-contract:server-compression-min-size - name: APP_SERVER_ERROR_INCLUDE_STACKTRACE # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (spring.web.error.include-stacktrace policy) type: enum default: never allowed_values: [always, never, on_param] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: env-contract:server-error-stacktrace-policy - name: APP_SERVER_ERROR_INCLUDE_MESSAGE # source: feature-env-driven-runtime-configuration D2 (2026-06-05) — APP_ unification # (spring.web.error.include-message policy) type: enum default: never allowed_values: [always, never, on_param] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: env-contract:server-error-message-policy # === Error exposure / body logging (env-driven branch "Required config: error exposure, log") === - name: APP_ERROR_DETAIL_EXPOSURE_ENABLED # source: feature-env-driven-runtime-configuration 2026-05-22 # "prod profile에서 body logging과 internal error detail exposure는 기본 금지" type: boolean default: false allowed_values: [true, false] classification: public-config required: true reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: prod_profile_must_be_false compatibility_impact: behavior-change required_test: env-contract:error-exposure-prod-safe - name: APP_LOG_BODY_CAPTURE_ENABLED # source: feature-env-driven-runtime-configuration 2026-05-22 "prod profile에서 body logging ... 기본 금지" # + feature-log-management-contract "request body capture filter — allowlist 없이는 capture 자체 금지" type: boolean default: false allowed_values: [true, false] classification: public-config required: true reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: prod_profile_must_be_false compatibility_impact: behavior-change required_test: env-contract:body-logging-prod-safe - name: APP_MULTI_INSTANCE_ENABLED # source: feature-env-driven-runtime-configuration D8 (2026-06-06) # When true, StartupSafetyValidator (SmartInitializingSingleton) requires the 5 # instance-coordination beans (distributed lock / cache-stampede / outbox leader # / rate-limiter / migration runner) to be present, else startup fails. Consumed # by feature-runtime-health-lifecycle-contract, feature-background-job-async-contract, # feature-cache-consistency-contract, feature-domain-event-outbox-contract, # feature-rate-limit-idempotency-contract, feature-migration-startup-contract. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: requires_coordination_beans_when_true compatibility_impact: behavior-change required_test: env-contract:multi-instance-beans-present - name: APP_MIGRATION_ON_STARTUP # source: feature-migration-startup-contract # When true, Flyway migrations are executed automatically during application startup. # When false, migrations are bypassed (delegated to out-of-app container/pipeline jobs). type: boolean default: true allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-migration-startup-contract validation: boolean_strict compatibility_impact: behavior-change required_test: env-contract:migration-on-startup-toggle # === Datasource / pool (env-driven branch "Required config: datasource") === - name: APP_DATASOURCE_URL # source: feature-env-driven-runtime-configuration "Required config: datasource" # + feature-persistence-failure-baseline "datasource/pool/timeout/connection exhaustion log field" type: url default: null allowed_values: null classification: public-config required: true reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: jdbc_url_pattern compatibility_impact: behavior-change required_test: env-contract:datasource-url-resolvable - name: APP_DATASOURCE_USERNAME # source: feature-env-driven-runtime-configuration "Required config: datasource" type: string default: null allowed_values: null classification: sensitive-config required: true reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: non_empty_string compatibility_impact: behavior-change required_test: env-contract:datasource-credential-present - name: APP_DATASOURCE_PASSWORD # source: feature-env-driven-runtime-configuration "Required config: datasource" # + feature-secrets-config-source-contract — secret 분류로 secrets-classification.yaml에서 owns type: string default: null allowed_values: null classification: secret required: true reload_policy: restart-only owner_branch: feature-secrets-config-source-contract validation: must_not_be_local_dev_sentinel_in_prod compatibility_impact: breaking required_test: secrets-contract:db-password-not-leaked - name: APP_DATASOURCE_POOL_MAX_SIZE # source: feature-env-driven-runtime-configuration "datasource/pool env" # + feature-persistence-failure-baseline "Hikari metric 노출 기준" type: int default: 10 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: positive_int compatibility_impact: behavior-change required_test: env-contract:pool-bounded - name: APP_DATASOURCE_POOL_MIN_IDLE # source: feature-env-driven-runtime-configuration "datasource/pool env" type: int default: 2 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: non_negative_int compatibility_impact: behavior-change required_test: env-contract:pool-min-idle-valid - name: APP_DATASOURCE_CONNECTION_TIMEOUT # source: feature-env-driven-runtime-configuration "datasource/pool env" # + feature-persistence-failure-baseline "Hikari Alert Threshold: pool wait p99 > 100ms" # unit: milliseconds. It feeds spring.datasource.hikari.connection-timeout, which binds onto # HikariConfig#setConnectionTimeout(long) — a duration shorthand such as "5s" does not bind and # fails the boot. This row said `duration` / `5s`, application.yml copied that default, and # every prod and dev deployment refused to start; five-adapter-runtime-remediation Wave 2 found # it in the prod-smoke lane. Corrected to what the property actually accepts. type: integer default: 5000 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: positive_integer_milliseconds compatibility_impact: behavior-change required_test: env-contract:connection-timeout-set - name: APP_DATASOURCE_DRIVER # source: feature-env-driven-runtime-configuration "Required config: datasource" # (JDBC driver class for the configured datasource URL) type: string default: org.postgresql.Driver allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: non_empty_string compatibility_impact: behavior-change required_test: env-contract:datasource-driver-set - name: APP_DATASOURCE_DDL_AUTO # source: feature-env-driven-runtime-configuration "Required config: datasource" # (Hibernate ddl-auto; prod must be validate|none, local update convenient) type: enum default: validate allowed_values: [none, validate, update, create, create-drop] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: env-contract:datasource-ddl-auto-safe - name: APP_DATASOURCE_SHOW_SQL # source: feature-env-driven-runtime-configuration "Required config: datasource" # (echo SQL to logs) type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: boolean_strict compatibility_impact: behavior-change required_test: env-contract:datasource-show-sql-toggle - name: APP_DATASOURCE_FORMAT_SQL # source: feature-env-driven-runtime-configuration "Required config: datasource" # (pretty-print SQL — only useful when SHOW_SQL=true) type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: boolean_strict compatibility_impact: behavior-change required_test: env-contract:datasource-format-sql-toggle - name: APP_DATASOURCE_OPEN_IN_VIEW # source: feature-env-driven-runtime-configuration "Required config: datasource" # (Hibernate OSIV — don't enable in prod) type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: boolean_strict compatibility_impact: behavior-change required_test: env-contract:datasource-open-in-view-toggle - name: APP_DATASOURCE_POOL_IDLE_TIMEOUT # source: feature-env-driven-runtime-configuration "datasource/pool env" # (Hikari milliseconds; idle connection eviction threshold) type: int default: 600000 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: non_negative_int compatibility_impact: behavior-change required_test: env-contract:pool-idle-timeout-valid - name: APP_DATASOURCE_POOL_MAX_LIFETIME # source: feature-env-driven-runtime-configuration "datasource/pool env" # (Hikari milliseconds; max lifetime — rotate before broker timeout) type: int default: 1800000 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-env-driven-runtime-configuration validation: positive_int compatibility_impact: behavior-change required_test: env-contract:pool-max-lifetime-valid # === Tracing / Observability (feature-distributed-tracing-contract) === - name: OTEL_EXPORTER_OTLP_ENDPOINT # source: feature-distributed-tracing-contract 2026-05-22 # "Micrometer Tracing + OpenTelemetry exporter를 기본 기준으로 둠" type: url default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-distributed-tracing-contract validation: url_or_empty compatibility_impact: additive required_test: tracing-contract:exporter-endpoint-resolvable - name: APP_TRACING_ENABLED # source: feature-distributed-tracing-contract 2026-05-22 # "tracing disabled profile에서도 envelope meta.traceId와 log traceId는 유지" type: boolean default: true allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-distributed-tracing-contract validation: boolean_strict compatibility_impact: behavior-change required_test: tracing-contract:meta-traceid-when-disabled - name: APP_TRACING_SAMPLE_RATE # source: feature-distributed-tracing-contract 2026-05-22 # "trace sampling rate default = prod 1%, staging 10%, dev/local 100%" # D-1 ISSUE-1 fix (2026-06-16): blank = per-profile resolver 기본값 사용. # TracingSampleRateResolver SSOT (prod=0.01/staging=0.10/dev·local=1.0). # TracingSamplingEnvironmentPostProcessor bridges resolved rate to # management.tracing.sampling.probability. type: string default: "" allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-distributed-tracing-contract validation: float_between_0_and_1_or_blank compatibility_impact: behavior-change required_test: tracing-contract:sample-rate-per-profile # === Log management (feature-log-management-contract) === # APP_LOG_LEVEL (single key) replaced by the 5 granular APP_LOG_LEVEL_* rows below # (root / app / spring / web / sql) — as built by feature-log-management-contract. - name: APP_LOG_LEVEL_ROOT # source: feature-log-management-contract — root logger level type: enum default: INFO allowed_values: [TRACE, DEBUG, INFO, WARN, ERROR, OFF] classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: log-contract:root-level - name: APP_LOG_LEVEL_APP # source: feature-log-management-contract — application package level type: enum default: INFO allowed_values: [TRACE, DEBUG, INFO, WARN, ERROR, OFF] classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: log-contract:app-level - name: APP_LOG_LEVEL_SPRING # source: feature-log-management-contract — Spring framework package level type: enum default: INFO allowed_values: [TRACE, DEBUG, INFO, WARN, ERROR, OFF] classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: log-contract:spring-level - name: APP_LOG_LEVEL_WEB # source: feature-log-management-contract — web/MVC package level type: enum default: INFO allowed_values: [TRACE, DEBUG, INFO, WARN, ERROR, OFF] classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: log-contract:web-level - name: APP_LOG_LEVEL_SQL # source: feature-log-management-contract — JPA/JDBC SQL package level (DEBUG prints SQL) type: enum default: WARN allowed_values: [TRACE, DEBUG, INFO, WARN, ERROR, OFF] classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: log-contract:sql-level - name: APP_LOG_FILE_ENABLED # source: feature-log-management-contract — rolling JSON file appender toggle type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: boolean_strict compatibility_impact: behavior-change required_test: log-contract:file-appender-toggle - name: APP_LOG_FILE_PATH # source: feature-log-management-contract — file path (relative to bootRun cwd or absolute) type: string default: logs/ca-skeleton.json allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: non_empty_string compatibility_impact: behavior-change required_test: log-contract:file-path-set - name: APP_LOG_FILE_MAX_SIZE # source: feature-log-management-contract — per-file rolling size cap type: data_size default: 100MB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: spring_data_size compatibility_impact: behavior-change required_test: log-contract:file-max-size - name: APP_LOG_FILE_MAX_HISTORY # source: feature-log-management-contract — number of rolled archives to retain type: int default: 14 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: positive_int compatibility_impact: behavior-change required_test: log-contract:file-max-history - name: APP_LOG_FILE_TOTAL_SIZE_CAP # source: feature-log-management-contract — total size cap across rolled files type: data_size default: 3GB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: spring_data_size compatibility_impact: behavior-change required_test: log-contract:file-total-size-cap - name: APP_LOG_ASYNC_ENABLED # source: feature-log-management-contract — AsyncAppender wrap for non-blocking I/O type: boolean default: true allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: boolean_strict compatibility_impact: behavior-change required_test: log-contract:async-appender-toggle - name: APP_LOG_ASYNC_QUEUE_SIZE # source: feature-log-management-contract — in-memory queue depth before back-pressure type: int default: 512 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: positive_int compatibility_impact: behavior-change required_test: log-contract:async-queue-size - name: APP_LOG_ASYNC_DISCARDING_THRESHOLD # source: feature-log-management-contract — remaining-capacity floor below which # TRACE/DEBUG/INFO events drop (WARN/ERROR always kept). 0 = never drop. type: int default: 20 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: non_negative_int compatibility_impact: behavior-change required_test: log-contract:async-discarding-threshold - name: APP_LOG_JSON_TIMEZONE # source: feature-log-management-contract — IANA timezone for JSON encoder timestamps type: string default: UTC allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: non_empty_string compatibility_impact: behavior-change required_test: log-contract:json-timezone - name: APP_LOG_JSON_TIMESTAMP_PATTERN # source: feature-log-management-contract — JSON encoder timestamp pattern (ISO 8601 default) type: string default: "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: non_empty_string compatibility_impact: behavior-change required_test: log-contract:json-timestamp-pattern - name: APP_LOG_JSON_INCLUDE_CALLER_DATA # source: feature-log-management-contract — include file/method/line (significant perf cost) type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: boolean_strict compatibility_impact: behavior-change required_test: log-contract:json-include-caller-data - name: APP_LOG_JSON_LOGGER_NAME_LENGTH # source: feature-log-management-contract — logger name abbreviation (0 = full name) type: int default: 0 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: non_negative_int compatibility_impact: behavior-change required_test: log-contract:json-logger-name-length - name: APP_LOG_SAMPLING_RATE # source: feature-log-management-contract 2026-05-22 # "log sampling(prod 10%) > trace sampling(prod 1%)" + Sampling Policy 표 (prod 10%, staging/dev/local 100%) type: string default: "1.0" allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-log-management-contract validation: float_between_0_and_1 compatibility_impact: behavior-change required_test: log-contract:sample-rate-per-profile # === Privacy: user_principal pseudonymization (feature-data-retention-privacy-contract) === - name: APP_PRIVACY_PSEUDONYMIZATION_SALT # source: feature-data-retention-privacy-contract — "pseudonymization key = HMAC-SHA-256 # with rotating salt (90d)". Consumed by feature-log-management-contract (DRIFT-6) # to record user_principal in pseudonymized form. secret 분류로 secrets-classification.yaml에서 owns. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: feature-data-retention-privacy-contract validation: must_not_be_local_dev_sentinel_in_prod compatibility_impact: breaking required_test: secrets-contract:pseudonymization-salt-rotation # === Security / CORS / JWT (feature-security-operational-baseline) === - name: APP_SECURITY_CORS_ORIGINS # source: feature-security-operational-baseline 2026-05-22 # "allowlist origin은 env-driven runtime configuration의 APP_SECURITY_CORS_ORIGINS로 주입" type: csv_list default: null allowed_values: null classification: public-config required: true reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: csv_of_origins_no_wildcard_with_credentials compatibility_impact: behavior-change required_test: security-contract:cors-allowlist - name: APP_SECURITY_CORS_ENABLED # source: feature-security-operational-baseline — CORS filter master toggle type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: boolean_strict compatibility_impact: behavior-change required_test: security-contract:cors-enabled-toggle - name: APP_SECURITY_CORS_ALLOWED_METHODS # source: feature-security-operational-baseline — allowed methods # (empty -> sensible method defaults in CorsSettings) type: csv_list default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: csv_of_http_methods_or_empty compatibility_impact: behavior-change required_test: security-contract:cors-allowed-methods - name: APP_SECURITY_CORS_ALLOWED_HEADERS # source: feature-security-operational-baseline — allowed request headers ("*" = any) type: csv_list default: "*" allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: csv_non_empty compatibility_impact: behavior-change required_test: security-contract:cors-allowed-headers - name: APP_SECURITY_CORS_ALLOW_CREDENTIALS # source: feature-security-operational-baseline 2026-05-22 # "CORS는 allowlist default, credentials false default" / "wildcard with credentials forbidden" type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: forbid_true_with_wildcard_origin compatibility_impact: behavior-change required_test: security-contract:cors-credentials-policy - name: APP_SECURITY_CORS_MAX_AGE # source: feature-security-operational-baseline 2026-05-22 # "preflight max-age 600s default" type: duration default: 600s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: spring_duration_shorthand compatibility_impact: behavior-change required_test: security-contract:cors-preflight-max-age - name: APP_SECURITY_AUTH_MODE type: enum default: jwt allowed_values: [jwt, redis-session] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: enum_in_allowed_values compatibility_impact: additive required_test: redis-session-contract:auth-mode-exclusive - name: APP_SESSION_COOKIE_NAME type: string default: CA_SESSION allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: bounded_cookie_name compatibility_impact: additive required_test: redis-session-contract:cookie-hardened - name: APP_SESSION_COOKIE_SECURE type: boolean default: true allowed_values: [true] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: must_be_true compatibility_impact: additive required_test: redis-session-contract:cookie-hardened - name: APP_SESSION_COOKIE_HTTP_ONLY type: boolean default: true allowed_values: [true] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: must_be_true compatibility_impact: additive required_test: redis-session-contract:cookie-hardened - name: APP_SESSION_COOKIE_SAME_SITE type: enum default: Lax allowed_values: [Lax, Strict, None] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: enum_in_allowed_values compatibility_impact: additive required_test: redis-session-contract:cookie-hardened - name: APP_SESSION_COOKIE_PATH type: string default: / allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: bounded_absolute_path compatibility_impact: additive required_test: redis-session-contract:cookie-hardened - name: APP_SESSION_CSRF_COOKIE_NAME type: string default: XSRF-TOKEN allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: bounded_cookie_name compatibility_impact: additive required_test: redis-session-contract:csrf-enabled - name: APP_SESSION_CSRF_HEADER_NAME type: string default: X-XSRF-TOKEN allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: bounded_header_name compatibility_impact: additive required_test: redis-session-contract:csrf-enabled - name: APP_SESSION_REDIS_NAMESPACE_ENVIRONMENT # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: local allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: lowercase_slug compatibility_impact: additive required_test: redis-session-contract:key-namespace - name: APP_SESSION_IDLE_TIMEOUT # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 30m allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: positive_duration_le_30d compatibility_impact: additive required_test: redis-session-contract:idle-expiry - name: APP_SESSION_ABSOLUTE_LIFETIME # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 8h allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: positive_duration_le_30d compatibility_impact: additive required_test: redis-session-contract:absolute-expiry - name: APP_SESSION_TOUCH_INTERVAL # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 1m allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: positive_duration_lt_idle compatibility_impact: additive required_test: redis-session-contract:bounded-touch - name: APP_SESSION_TOMBSTONE_TTL # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 5m allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: positive_duration_gt_route_drain compatibility_impact: additive required_test: redis-session-contract:logout-tombstone - name: APP_SESSION_MAXIMUM_ENVELOPE_BYTES # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 32768 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: int_range_64_1048576 compatibility_impact: additive required_test: redis-session-contract:serializer-bounded - name: APP_SESSION_MAXIMUM_ATTRIBUTES # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 64 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: int_range_1_256 compatibility_impact: additive required_test: redis-session-contract:serializer-bounded - name: APP_SESSION_MAXIMUM_SCALAR_BYTES # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 8192 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: positive_int_le_envelope compatibility_impact: additive required_test: redis-session-contract:serializer-bounded - name: APP_SECURITY_JWT_ISSUER # source: feature-security-operational-baseline 2026-05-22 # "issuer mismatch | 401 | AUTH_ISSUER_MISMATCH" type: url default: null allowed_values: null classification: public-config required: true reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: url_required compatibility_impact: behavior-change required_test: security-contract:jwt-issuer-set - name: APP_SECURITY_JWT_AUDIENCE # source: feature-security-operational-baseline 2026-05-22 # "audience mismatch | 401 | AUTH_AUDIENCE_MISMATCH" type: csv_list default: null allowed_values: null classification: public-config required: true reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: csv_non_empty compatibility_impact: behavior-change required_test: security-contract:jwt-audience-set - name: APP_SECURITY_JWT_JWKS_URI # source: feature-security-operational-baseline 2026-05-22 # "JWKS refresh interval = 10분, on-demand refresh on unknown kid" type: url default: null allowed_values: null classification: public-config required: true reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: url_required compatibility_impact: behavior-change required_test: security-contract:jwks-uri-resolvable - name: APP_SECURITY_JWT_CLOCK_SKEW # source: feature-security-operational-baseline 2026-05-22 # "JWT clock skew tolerance = 60s (Spring Security JwtTimestampValidator leeway)" type: duration default: 60s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-security-operational-baseline validation: spring_duration_shorthand compatibility_impact: behavior-change required_test: security-contract:jwt-clock-skew-applied - name: APP_SECURITY_JWT_SIGNING_KEY # source: feature-security-operational-baseline 2026-05-22 # "JWT signing key rotation의 운영 관측 (JWKS refresh, kid mismatch 분류)" # secret 분류 — owner: secrets-classification.yaml type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: feature-secrets-config-source-contract validation: must_not_be_local_dev_sentinel_in_prod compatibility_impact: breaking required_test: secrets-contract:jwt-signing-key-rotation-overlap # === Tenant context (feature-tenant-context-policy) === - name: APP_TENANT_ENABLED # source: feature-tenant-context-policy 2026-05-22 # "skeleton core는 multi-tenancy 미지원이 기본이며 tenant header는 기본 거부" type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-tenant-context-policy validation: boolean_strict compatibility_impact: behavior-change required_test: tenant-contract:disabled-rejects-header # === Rate limit / Idempotency (feature-rate-limit-idempotency-contract) === - name: APP_RATE_LIMIT_ENABLED # Inbound enforcement stays disabled until an exact provider is selected. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: boolean_strict compatibility_impact: additive required_test: redis-rate-limit-contract:transport-provider-default-pair - name: APP_RATE_LIMIT_CLIENT_IP_MODE # source: feature-rate-limit-idempotency-contract — rate-limit client IP source policy. # Use forwarded-headers-trusted only behind an ingress/LB that overwrites X-Forwarded-For. type: enum default: remote-addr-only allowed_values: [remote-addr-only, forwarded-headers-trusted] classification: public-config required: false reload_policy: restart-only owner_branch: feature-rate-limit-idempotency-contract validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: rate-limit-contract:client-ip-mode - name: APP_RATE_LIMIT_REDIS_ENABLED # DEPRECATED 2026-08-10: the rate limiter no longer owns a Redis client of its own. One client, built by RedisSdkAutoConfiguration, serves every capability, so a second endpoint and a second set of ceilings could only ever disagree with it. # Replaced by: app.redis.enabled (APP_REDIS_ENABLED). deprecated_orphaned: true removal_deadline: 2026-11-30 type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: boolean_strict compatibility_impact: additive required_test: rate-limit-contract:redis-disabled-zero-side-effect - name: APP_RATE_LIMIT_PROVIDER type: enum default: disabled allowed_values: [disabled, redis] classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: enum_strict compatibility_impact: additive required_test: rate-limit-contract:provider-explicit - name: APP_RATE_LIMIT_ROLE type: enum default: coordination allowed_values: [coordination] classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: enum_strict compatibility_impact: additive required_test: rate-limit-contract:coordination-role-only - name: APP_RATE_LIMIT_FAILURE_POLICY type: enum default: fail-closed allowed_values: [fail-closed] classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: enum_strict compatibility_impact: additive required_test: rate-limit-contract:fail-closed-only - name: APP_RATE_LIMIT_DEFAULT_POLICY_ID type: string default: api-default allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: lowercase_slug compatibility_impact: additive required_test: rate-limit-contract:default-policy-resolves - name: APP_RATE_LIMIT_FAILURE_RETRY_AFTER type: duration default: 100ms allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: spring_duration_shorthand_non_zero_le_30d compatibility_impact: additive required_test: rate-limit-contract:failure-retry-bounded - name: APP_RATE_LIMIT_HASH_KEY_VERSION type: int default: 1 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: int_1_to_9999 compatibility_impact: additive required_test: rate-limit-contract:hash-version-bounded - name: APP_RATE_LIMIT_KEY_VERSION type: int default: 1 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: int_1_to_9999 compatibility_impact: additive required_test: rate-limit-contract:key-version-bounded - name: APP_RATE_LIMIT_REDIS_HOST # DEPRECATED 2026-08-10: the rate limiter no longer owns a Redis client of its own. One client, built by RedisSdkAutoConfiguration, serves every capability, so a second endpoint and a second set of ceilings could only ever disagree with it. # Replaced by: app.redis.nodes (APP_REDIS_NODES). deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: non_empty_string_when_rate_limit_redis_enabled compatibility_impact: additive required_test: rate-limit-contract:redis-host-required - name: APP_RATE_LIMIT_REDIS_PORT # DEPRECATED 2026-08-10: the rate limiter no longer owns a Redis client of its own. One client, built by RedisSdkAutoConfiguration, serves every capability, so a second endpoint and a second set of ceilings could only ever disagree with it. # Replaced by: app.redis.nodes (APP_REDIS_NODES). deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 6379 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: port_range_1_65535 compatibility_impact: additive required_test: rate-limit-contract:redis-port-bounded - name: APP_RATE_LIMIT_REDIS_PASSWORD type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: must_not_be_local_dev_sentinel_in_prod compatibility_impact: additive required_test: rate-limit-contract:redis-password-no-leak - name: APP_RATE_LIMIT_REDIS_TRUST_PEM # DEPRECATED 2026-08-10: the rate limiter no longer owns a Redis client of its own. One client, built by RedisSdkAutoConfiguration, serves every capability, so a second endpoint and a second set of ceilings could only ever disagree with it. # Replaced by: app.redis.tls.trust-material-resource. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: null allowed_values: null classification: sensitive-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: non_blank_pem_when_coordination_role_is_bound compatibility_impact: additive required_test: redis-contract:coordination-trust-material-no-leak - name: APP_RATE_LIMIT_REDIS_KEY_HMAC_SECRET type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: base64_min_32_bytes_when_rate_limit_redis_enabled compatibility_impact: additive required_test: rate-limit-contract:redis-hmac-required - name: APP_SESSION_REDIS_PASSWORD type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: redis-production-capability validation: non_blank_when_session_role_is_bound compatibility_impact: additive required_test: redis-contract:session-password-no-leak - name: APP_SESSION_REDIS_TRUST_PEM # DEPRECATED 2026-08-10: the session generation that bound this was removed, and the replacement does not own a Redis client of its own either. # Replaced by: app.redis.tls.trust-material-resource. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: null allowed_values: null classification: sensitive-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: non_blank_pem_when_session_role_is_bound compatibility_impact: additive required_test: redis-contract:session-trust-material-no-leak - name: APP_SESSION_REDIS_KEY_HMAC_SECRET # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: redis-production-capability validation: base64_min_32_bytes_when_redis_session_enabled compatibility_impact: additive required_test: redis-session-contract:key-hmac-no-leak - name: APP_RATE_LIMIT_REDIS_COMMAND_TIMEOUT type: duration default: 1s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: spring_duration_shorthand_non_zero_le_30s compatibility_impact: additive required_test: rate-limit-contract:redis-timeout-bounded - name: APP_RATE_LIMIT_REDIS_MAXIMUM_COMMAND_BYTES # DEPRECATED 2026-08-10: the rate limiter no longer owns a Redis client of its own. One client, built by RedisSdkAutoConfiguration, serves every capability, so a second endpoint and a second set of ceilings could only ever disagree with it. # Replaced by: app.redis.limits.max-batch-request-bytes. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 16384 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: int_16384_to_65536 compatibility_impact: additive required_test: rate-limit-contract:redis-command-bytes-bounded - name: APP_RATE_LIMIT_REDIS_MAXIMUM_QUEUED_COMMANDS # DEPRECATED 2026-08-10: the rate limiter no longer owns a Redis client of its own. One client, built by RedisSdkAutoConfiguration, serves every capability, so a second endpoint and a second set of ceilings could only ever disagree with it. # Replaced by: app.redis.capacity.maximum-in-flight-commands. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 32 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: int_1_to_4096 compatibility_impact: additive required_test: rate-limit-contract:redis-queue-bounded - name: APP_RATE_LIMIT_REDIS_MAXIMUM_IN_FLIGHT_BYTES # DEPRECATED 2026-08-10: the rate limiter no longer owns a Redis client of its own. One client, built by RedisSdkAutoConfiguration, serves every capability, so a second endpoint and a second set of ceilings could only ever disagree with it. # Replaced by: app.redis.capacity.maximum-in-flight-bytes. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 1048576 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: covers_rate_limit_command_and_le_268435456 compatibility_impact: additive required_test: rate-limit-contract:redis-byte-admission-bounded - name: APP_RATE_LIMIT_REDIS_NAMESPACE_ENVIRONMENT # DEPRECATED 2026-08-10: the rate limiter no longer renders its own key prefix. Four capabilities each joining two free-form tokens produced four prefixes, and the ACL pattern matched none of them. # Replaced by: app.redis.namespace.environment (APP_REDIS_NAMESPACE_ENVIRONMENT), shared by every capability. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: local allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: lowercase_slug compatibility_impact: additive required_test: rate-limit-contract:redis-namespace-bounded - name: APP_RATE_LIMIT_POLICY_REVISION type: string default: v1 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: lowercase_slug compatibility_impact: additive required_test: rate-limit-contract:policy-revision-bounded - name: APP_RATE_LIMIT_ALGORITHM type: enum default: sliding-counter allowed_values: [fixed-window, sliding-counter, token-bucket] classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: enum_strict compatibility_impact: additive required_test: rate-limit-contract:algorithm-selectable - name: APP_RATE_LIMIT_LIMIT type: int default: 100 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: positive_lua_exact_integer compatibility_impact: additive required_test: rate-limit-contract:limit-bounded - name: APP_RATE_LIMIT_WINDOW type: duration default: 1s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: spring_duration_shorthand_non_zero_le_1d compatibility_impact: additive required_test: rate-limit-contract:window-bounded - name: APP_RATE_LIMIT_CAPACITY type: int default: 100 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: positive_lua_exact_integer compatibility_impact: additive required_test: rate-limit-contract:capacity-bounded - name: APP_RATE_LIMIT_REFILL_TOKENS type: int default: 100 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: positive_lua_exact_integer compatibility_impact: additive required_test: rate-limit-contract:refill-tokens-bounded - name: APP_RATE_LIMIT_REFILL_PERIOD type: duration default: 1s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: spring_duration_shorthand_non_zero_le_1d compatibility_impact: additive required_test: rate-limit-contract:refill-period-bounded - name: APP_RATE_LIMIT_MAXIMUM_COST type: int default: 10 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: positive_lua_exact_integer compatibility_impact: additive required_test: rate-limit-contract:maximum-cost-bounded - name: APP_RATE_LIMIT_CLEANUP_GRACE type: duration default: 5s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: spring_duration_shorthand_non_zero_le_1d compatibility_impact: additive required_test: rate-limit-contract:cleanup-grace-bounded - name: APP_RATE_LIMIT_MAXIMUM_CLOCK_REGRESSION type: duration default: 250ms allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-distributed-rate-limit validation: spring_duration_shorthand_non_negative_le_1h compatibility_impact: additive required_test: rate-limit-contract:clock-regression-bounded - name: APP_IDEMPOTENCY_TTL # source: feature-rate-limit-idempotency-contract 2026-05-22 # "idempotency TTL default = 24h. long-running use case는 use case 선언으로 72h까지 override 가능" type: duration default: 24h allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-rate-limit-idempotency-contract validation: spring_duration_shorthand_le_72h compatibility_impact: behavior-change required_test: idempotency-contract:ttl-applied - name: APP_IDEMPOTENCY_PROVIDER # postgresql selects the owner-safe V2 store on the primary data source. It had no value here # while the store, its schema stream and its integration suite all existed, so the capability # could only be reached by constructing it in a test. type: enum default: jdbc allowed_values: [disabled, jdbc, redis, postgresql] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: enum_strict compatibility_impact: additive required_test: redis-idempotency-contract:provider-exclusive - name: APP_IDEMPOTENCY_REDIS_KEY_HMAC_SECRET type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: base64_min_32_bytes_when_redis_idempotency_enabled compatibility_impact: additive required_test: redis-idempotency-contract:key-hmac-no-leak - name: APP_IDEMPOTENCY_REDIS_NAMESPACE_ENVIRONMENT # DEPRECATED 2026-08-10: the idempotency store no longer renders its own key prefix. Four capabilities each joining two free-form tokens produced four prefixes, and the ACL pattern matched none of them. # Replaced by: app.redis.namespace.environment (APP_REDIS_NAMESPACE_ENVIRONMENT), shared by every capability. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: local allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: lowercase_slug compatibility_impact: additive required_test: redis-idempotency-contract:key-namespace - name: APP_IDEMPOTENCY_PROCESSING_LEASE type: duration default: 30s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: positive_duration_le_1h compatibility_impact: additive required_test: redis-idempotency-contract:processing-lease-bounded - name: APP_IDEMPOTENCY_FAILURE_RETENTION type: duration default: 24h allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: positive_duration_le_30d compatibility_impact: additive required_test: redis-idempotency-contract:failure-retention-bounded - name: APP_LEASE_PROVIDER type: enum default: disabled allowed_values: [disabled, redis] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: enum_strict compatibility_impact: additive required_test: redis-lease-contract:provider-exclusive - name: APP_LEASE_REDIS_KEY_HMAC_SECRET type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: base64_min_32_bytes_when_redis_lease_enabled compatibility_impact: additive required_test: redis-lease-contract:key-hmac-no-leak - name: APP_LEASE_REDIS_NAMESPACE_ENVIRONMENT # DEPRECATED 2026-08-10: the lease no longer renders its own key prefix. Four capabilities each joining two free-form tokens produced four prefixes, and the ACL pattern matched none of them. # Replaced by: app.redis.namespace.environment (APP_REDIS_NAMESPACE_ENVIRONMENT), shared by every capability. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: local allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: lowercase_slug compatibility_impact: additive required_test: redis-lease-contract:key-namespace - name: APP_LEASE_REDIS_DRIFT_BUDGET type: duration default: 10ms allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: non_negative_duration_lt_minimum_lease compatibility_impact: additive required_test: redis-lease-contract:drift-budget-bounded # === Cache / Redis (feature-cache-consistency-contract + integration-adapter-templates) === - name: APP_CACHE_CANONICAL_DEFAULT_PROVIDER # Canonical default semantic region provider selection; legacy enable is a separate migration path. type: enum default: disabled allowed_values: [disabled, redis] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: enum_strict compatibility_impact: additive required_test: redis-cache:canonical-cache-role-composition - name: APP_REDIS_ENABLED # The single global Redis activation switch (property app.redis.enabled). # False loads no Redis settings, requires no Redis secret, and creates no client, connection, # thread or health contributor. Role selectors choose which capabilities compose once Redis is # on; none of them is a second master switch. property: app.redis.enabled owner_module: app-bootstrap type: boolean default: false allowed_values: [true, false] classification: public-config required: false required_when: always-optional reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: boolean_strict compatibility_impact: behavior-change required_test: redis-optionality:global-switch-off-creates-nothing - name: APP_CACHE_REDIS_POSITIVE_HARD_TTL # How long a cache entry stays usable. The physical Redis TTL equals this and nothing else, so # an entry can never outlive the deployment's own notion of usability or be discarded early. type: duration default: 5m allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: spring_duration_shorthand_ge_minimum_hard_ttl compatibility_impact: additive required_test: redis-capability:cache-region-composition - name: APP_CACHE_REDIS_NEGATIVE_TTL # How long an authoritative absence is cached. Separate from the positive TTL because "the # source says this does not exist" is a fact with a different shelf life from a value. type: duration default: 10s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: spring_duration_shorthand_non_zero compatibility_impact: additive required_test: redis-capability:cache-region-composition - name: APP_IDEMPOTENCY_REDIS_COMMAND_TIMEOUT # The ceiling on one owner-safe transition. type: duration default: 200ms allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: spring_duration_shorthand_non_zero compatibility_impact: additive required_test: redis-capability:idempotency-store-composition - name: APP_LEASE_REDIS_COMMAND_TIMEOUT # The ceiling on one lease operation. type: duration default: 200ms allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: spring_duration_shorthand_non_zero compatibility_impact: additive required_test: redis-capability:lease-composition - name: APP_LEASE_REDIS_CONTENTION_RETRY_AFTER # What a contended acquire tells the caller to wait. Distinct from the drift budget: one is # advice to a caller that lost, the other is how much of its own lease a winner does not trust. type: duration default: 50ms allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: spring_duration_shorthand_non_zero compatibility_impact: additive required_test: redis-capability:lease-composition # --- Redis SDK typed settings (app.redis.*) ------------------------------- # Bound only by RedisSdkAutoConfiguration, which exists only while APP_REDIS_ENABLED # is true. They are deliberately absent from application.yml and src/.env: putting # them there would make a Redis-free deployment carry Redis configuration, which is # the defect the conditional composition root removes. verifyEnvKeys checks them # against spring-configuration-metadata.json instead. - name: APP_REDIS_ACKNOWLEDGED_WRITE_LOSS_ACCEPTED # Declares that losing acknowledged writes is a deliberate trade. Leave false. property: app.redis.acknowledged-write-loss-accepted owner_module: adapter-outbound-cache-redis type: boolean default: false allowed_values: [true, false] classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: boolean_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_ADMIN_CREDENTIAL_REFERENCE property: app.redis.admin.credential-reference owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: sensitive-config required: false required_when: app.redis.admin.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_ADMIN_ENABLED property: app.redis.admin.enabled owner_module: adapter-outbound-cache-redis type: boolean default: false allowed_values: [true, false] classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: boolean_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_ADVANCED_ENABLED property: app.redis.advanced.enabled owner_module: adapter-outbound-cache-redis type: boolean default: false allowed_values: [true, false] classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: boolean_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_ADVANCED_POLICIES property: app.redis.advanced.policies owner_module: adapter-outbound-cache-redis type: csv default: "" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: csv_nonempty compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_BLOCKING_MAX_BLOCK # Hard ceiling on a server-side block; zero would be unbounded. property: app.redis.blocking.max-block owner_module: adapter-outbound-cache-redis type: duration default: "30s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_BLOCKING_MAX_CONNECTIONS property: app.redis.blocking.max-connections owner_module: adapter-outbound-cache-redis type: integer default: 32 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_DATABASE # Cluster supports database 0 only; a non-zero value fails startup there. property: app.redis.database owner_module: adapter-outbound-cache-redis type: integer default: 0 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_BATCH_COMMANDS property: app.redis.limits.max-batch-commands owner_module: adapter-outbound-cache-redis type: integer default: 500 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_BATCH_REPLY_BYTES property: app.redis.limits.max-batch-reply-bytes owner_module: adapter-outbound-cache-redis type: integer default: 16777216 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_BATCH_REQUEST_BYTES property: app.redis.limits.max-batch-request-bytes owner_module: adapter-outbound-cache-redis type: integer default: 4194304 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_BITMAP_OFFSET property: app.redis.limits.max-bitmap-offset owner_module: adapter-outbound-cache-redis type: integer default: 10000000 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_COLLECTION_ELEMENTS property: app.redis.limits.max-collection-elements owner_module: adapter-outbound-cache-redis type: integer default: 1000 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_HASH_FIELD_VALUE_BYTES property: app.redis.limits.max-hash-field-value-bytes owner_module: adapter-outbound-cache-redis type: integer default: 524288 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_KEY_BYTES property: app.redis.limits.max-key-bytes owner_module: adapter-outbound-cache-redis type: integer default: 512 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_SCAN_COUNT property: app.redis.limits.max-scan-count owner_module: adapter-outbound-cache-redis type: integer default: 500 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_STREAM_PAYLOAD_BYTES property: app.redis.limits.max-stream-payload-bytes owner_module: adapter-outbound-cache-redis type: integer default: 262144 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_MAX_VALUE_BYTES property: app.redis.limits.max-value-bytes owner_module: adapter-outbound-cache-redis type: integer default: 1048576 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_LIMITS_OFFLINE_QUEUE_COMMANDS property: app.redis.limits.offline-queue-commands owner_module: adapter-outbound-cache-redis type: integer default: 1000 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_MODE # standalone | sentinel | cluster. property: app.redis.mode owner_module: adapter-outbound-cache-redis type: enum default: "standalone" allowed_values: [standalone, sentinel, cluster] classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: enum_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_NAMESPACE_DOMAIN property: app.redis.namespace.domain owner_module: adapter-outbound-cache-redis type: string default: "shared" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_NAMESPACE_ENVIRONMENT property: app.redis.namespace.environment owner_module: adapter-outbound-cache-redis type: string default: "local" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_NAMESPACE_SERVICE property: app.redis.namespace.service owner_module: adapter-outbound-cache-redis type: string default: "sample-service" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_NODES # CSV of host:port. Cluster and Sentinel take every seed node. property: app.redis.nodes owner_module: adapter-outbound-cache-redis type: csv default: "localhost:6379" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: csv_nonempty compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_RAW_CREDENTIAL_REFERENCE property: app.redis.raw.credential-reference owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: sensitive-config required: false required_when: app.redis.raw.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_RAW_ENABLED property: app.redis.raw.enabled owner_module: adapter-outbound-cache-redis type: boolean default: false allowed_values: [true, false] classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: boolean_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_RAW_POLICY_RESOURCE # Classpath resource listing every approved raw command. Absent resource fails startup. property: app.redis.raw.policy-resource owner_module: adapter-outbound-cache-redis type: string default: "classpath:redis-sdk/raw-command-allowlist.yml" allowed_values: null classification: public-config required: false required_when: app.redis.raw.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_TIMEOUT_ADMIN property: app.redis.timeout.admin owner_module: adapter-outbound-cache-redis type: duration default: "3s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_TIMEOUT_BATCH property: app.redis.timeout.batch owner_module: adapter-outbound-cache-redis type: duration default: "2s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_TIMEOUT_COLLECTION property: app.redis.timeout.collection owner_module: adapter-outbound-cache-redis type: duration default: "2s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_TIMEOUT_FAST # Single-key command profile; above 5s produces a startup warning. property: app.redis.timeout.fast owner_module: adapter-outbound-cache-redis type: duration default: "500ms" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_TIMEOUT_SCRIPT property: app.redis.timeout.script owner_module: adapter-outbound-cache-redis type: duration default: "1s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated - name: APP_REDIS_TRANSACTION_MAX_CONNECTIONS property: app.redis.transaction.max-connections owner_module: adapter-outbound-cache-redis type: integer default: 16 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:typed-settings-bound-and-validated # --- Redis runtime composition settings (app.redis.*) ---------------------- # Authentication, Sentinel discovery, TLS, lifecycle, Cluster routing, capacity and # subscription delivery. Same rule as the rest of app.redis.*: bound only while # APP_REDIS_ENABLED is true, and deliberately absent from application.yml and .env. - name: APP_REDIS_AUTHENTICATION_ADVANCED_CREDENTIAL_REFERENCE property: app.redis.authentication.advanced-credential-reference owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: sensitive-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_AUTHENTICATION_ANONYMOUS_ACCESS_ACCEPTED property: app.redis.authentication.anonymous-access-accepted owner_module: adapter-outbound-cache-redis # Explicit acknowledgement that Redis runs with no credential. Startup fails without it when # no credential reference is set, because booting anyway builds an unauthenticated client that # cannot run a single command on any deployment which disabled the `default` ACL user — the # failure moves from startup to the first request, where it reads as an outage rather than a # missing setting. Setting this to true keeps the deployment running and logs the trade. type: boolean default: false allowed_values: [true, false] classification: public-config required: false required_when: app.redis.enabled=true and no credential reference is configured reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: boolean_strict compatibility_impact: additive required_test: redis-sdk:authentication-required-unless-anonymous-accepted - name: APP_REDIS_AUTHENTICATION_CREDENTIAL_REFERENCE # Pointer to the application ACL account credential. The value lives in the secret manager. property: app.redis.authentication.credential-reference owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: sensitive-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_AUTHENTICATION_PUBSUB_CREDENTIAL_REFERENCE property: app.redis.authentication.pubsub-credential-reference owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: sensitive-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_CAPACITY_MAXIMUM_IN_FLIGHT_BYTES property: app.redis.capacity.maximum-in-flight-bytes owner_module: adapter-outbound-cache-redis type: integer default: null allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_CAPACITY_MAXIMUM_IN_FLIGHT_COMMANDS property: app.redis.capacity.maximum-in-flight-commands owner_module: adapter-outbound-cache-redis type: integer default: 64 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_CAPACITY_MAXIMUM_REPLY_BYTES property: app.redis.capacity.maximum-reply-bytes owner_module: adapter-outbound-cache-redis type: integer default: null allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_CAPACITY_REJECT_WHEN_DISCONNECTED # True refuses commands while disconnected. False restores the driver offline queue, which replays a burst of writes on reconnect in arbitrary order relative to the outage. property: app.redis.capacity.reject-when-disconnected owner_module: adapter-outbound-cache-redis type: boolean default: true allowed_values: [true, false] classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: boolean_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_CLUSTER_MAXIMUM_REDIRECTS property: app.redis.cluster.maximum-redirects owner_module: adapter-outbound-cache-redis type: integer default: 5 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_CLUSTER_TOPOLOGY_REFRESH_PERIOD property: app.redis.cluster.topology-refresh-period owner_module: adapter-outbound-cache-redis type: duration default: "30s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_LIFECYCLE_ACQUIRE_TIMEOUT property: app.redis.lifecycle.acquire-timeout owner_module: adapter-outbound-cache-redis type: duration default: "2s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_LIFECYCLE_CLIENT_NAME property: app.redis.lifecycle.client-name owner_module: adapter-outbound-cache-redis type: string default: "ca-skeleton" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_LIFECYCLE_CONNECT_TIMEOUT property: app.redis.lifecycle.connect-timeout owner_module: adapter-outbound-cache-redis type: duration default: "2s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_LIFECYCLE_DRAIN_TIMEOUT # How long shutdown waits for in-flight commands before closing connections. property: app.redis.lifecycle.drain-timeout owner_module: adapter-outbound-cache-redis type: duration default: "6s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_LIFECYCLE_SHUTDOWN_QUIET_PERIOD property: app.redis.lifecycle.shutdown-quiet-period owner_module: adapter-outbound-cache-redis type: duration default: "100ms" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_LIFECYCLE_SHUTDOWN_TIMEOUT property: app.redis.lifecycle.shutdown-timeout owner_module: adapter-outbound-cache-redis type: duration default: "3s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_LIFECYCLE_TLS_HANDSHAKE_TIMEOUT property: app.redis.lifecycle.tls-handshake-timeout owner_module: adapter-outbound-cache-redis type: duration default: "3s" allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: duration_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_PUBSUB_BUFFER_CAPACITY property: app.redis.pubsub.buffer-capacity owner_module: adapter-outbound-cache-redis type: integer default: 1024 allowed_values: null classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: positive_integer compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_PUBSUB_OVERFLOW_POLICY # error | drop-oldest | drop-latest. property: app.redis.pubsub.overflow-policy owner_module: adapter-outbound-cache-redis type: string default: "error" allowed_values: [error, drop-oldest, drop-latest] classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_SENTINEL_CREDENTIAL_REFERENCE property: app.redis.sentinel.credential-reference owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: sensitive-config required: false # Applied only when present: RedisTopologyClientFactory sets the sentinel credentials provider # through ifPresent, so a Sentinel deployment whose sentinels accept unauthenticated discovery # starts without it. The unconditional "app.redis.mode=sentinel" this used to declare was a # requirement the runtime never enforced. required_when: app.redis.mode=sentinel and the sentinels require authentication reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_SENTINEL_MASTER_NAME property: app.redis.sentinel.master-name owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: public-config required: false required_when: app.redis.mode=sentinel reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_SENTINEL_NODES property: app.redis.sentinel.nodes owner_module: adapter-outbound-cache-redis type: csv default: app.redis.nodes allowed_values: null classification: public-config required: false # Falls back to app.redis.nodes by design, so a deployment that points nodes at its sentinels # and says nothing else is the common case rather than a misconfiguration. required_when: app.redis.mode=sentinel and app.redis.nodes does not list the sentinels reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: csv_nonempty compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_TLS_CLIENT_CERTIFICATE_RESOURCE property: app.redis.tls.client-certificate-resource owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: public-config required: false # A key manager is configured only when this is present. Ordinary one-way TLS needs no client # certificate, so requiring one whenever TLS is on was a claim the runtime never made. required_when: app.redis.tls.enabled=true and the server requires mutual TLS reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_TLS_CLIENT_KEY_REFERENCE property: app.redis.tls.client-key-reference owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: sensitive-config required: false # A relationship between two settings rather than a switch: a client certificate without its # key cannot build a key manager. Enforced in RedisSdkSettings.validate and covered by # RedisSdkSettingsTest, which is where the registry's prose conditions are proven. required_when: app.redis.tls.client-certificate-resource is configured reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_TLS_ENABLED property: app.redis.tls.enabled owner_module: adapter-outbound-cache-redis type: boolean default: false allowed_values: [true, false] classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: boolean_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_TLS_HOSTNAME_VERIFICATION # Disabling this accepts any certificate the trust material signs, for any host. property: app.redis.tls.hostname-verification owner_module: adapter-outbound-cache-redis type: boolean default: true allowed_values: [true, false] classification: public-config required: false required_when: app.redis.enabled=true reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: boolean_strict compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_REDIS_TLS_TRUST_MATERIAL_RESOURCE property: app.redis.tls.trust-material-resource owner_module: adapter-outbound-cache-redis type: string default: null allowed_values: null classification: public-config required: false # A trust manager is installed only when this is present; otherwise the JDK default trust # anchors apply, which is enough for a server certificate from a public CA. required_when: app.redis.tls.enabled=true and the server certificate is not publicly trusted reload_policy: restart-only owner_branch: redis-optionality-and-composition validation: nonblank_when_required compatibility_impact: additive required_test: redis-sdk:runtime-composition-binds-and-validates - name: APP_CACHE_REDIS_ENABLED # source: feature-integration-adapter-templates 2026-05-22 # "Redis | disabled optional module | cache consistency" + Adapter Template Defaults 표 # DEPRECATED 2026-08-10: this was a second Redis master switch, and the settings class that # bound it was removed with the previous Redis generation, so the key reached nothing. # APP_REDIS_ENABLED is the sole global activation authority; the cache role is selected by # ca-skeleton.capabilities.cache.bindings.default. The row is kept rather than deleted so a # deployment still setting this key can be told what replaced it. deprecated_orphaned: true deprecated_alias_for: APP_REDIS_ENABLED removal_deadline: 2026-11-30 type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: feature-integration-adapter-templates validation: boolean_strict compatibility_impact: behavior-change required_test: adapter-contract:redis-disabled-default - name: APP_CACHE_REDIS_CLIENT_MODE # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: enum default: managed allowed_values: [managed, external] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: enum_strict compatibility_impact: additive required_test: adapter-contract:redis-client-mode-explicit - name: APP_CACHE_REDIS_HOST # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 # source: feature-cache-consistency-contract — Redis adapter (활성화 시 endpoint 필요) type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-cache-consistency-contract validation: non_empty_string_when_redis_enabled compatibility_impact: behavior-change required_test: cache-contract:redis-host-when-enabled - name: APP_CACHE_REDIS_PORT # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 # source: feature-cache-consistency-contract — Redis adapter endpoint type: int default: 6379 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-cache-consistency-contract validation: port_range_1_65535 compatibility_impact: behavior-change required_test: cache-contract:redis-port-bound - name: APP_CACHE_REDIS_PASSWORD # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: codex-phase-a-ci-recovery validation: must_not_be_local_dev_sentinel_in_prod compatibility_impact: additive required_test: secrets-contract:redis-password-no-leak - name: APP_CACHE_REDIS_TRUST_PEM # DEPRECATED 2026-08-10: the cache no longer owns a Redis client of its own, so no code reads this. # Replaced by: app.redis.tls.trust-material-resource (APP_REDIS_TLS_TRUST_MATERIAL_RESOURCE), which the one Redis client uses for every capability. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: null allowed_values: null classification: sensitive-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: non_blank_pem_when_cache_role_is_bound compatibility_impact: additive required_test: redis-contract:cache-trust-material-no-leak - name: APP_REDIS_SEMANTIC_PROBE_MINIMUM_INTERVAL # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 5s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: spring_duration_1s_to_60s compatibility_impact: additive required_test: redis-contract:semantic-probe-cadence-bounded - name: APP_REDIS_SENTINEL_DISCOVERY_REFRESH_PERIOD # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 30s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: spring_duration_5s_to_5m_inclusive compatibility_impact: additive required_test: redis-contract:sentinel-discovery-refresh-period-bounded - name: APP_REDIS_SEMANTIC_PROBE_MAXIMUM_STALENESS # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 15s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability-completion validation: spring_duration_gte_probe_minimum_and_lte_5m compatibility_impact: additive required_test: redis-contract:semantic-probe-staleness-bounded - name: APP_CACHE_REDIS_KEY_HMAC_SECRET # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: codex-phase-a-ci-recovery validation: base64_min_32_bytes_when_redis_enabled compatibility_impact: additive required_test: cache-contract:redis-hmac-secret-bounded - name: APP_CACHE_REDIS_COMMAND_TIMEOUT # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 2s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: codex-phase-a-ci-recovery validation: spring_duration_shorthand_non_zero_le_30s compatibility_impact: additive required_test: cache-contract:redis-command-timeout-bounded - name: APP_CACHE_REDIS_MAXIMUM_QUEUED_COMMANDS # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 8 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: codex-phase-a-ci-recovery validation: int_1_to_4096 compatibility_impact: additive required_test: cache-contract:redis-command-queue-bounded - name: APP_CACHE_REDIS_MAXIMUM_IN_FLIGHT_BYTES # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 16777216 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: codex-phase-a-ci-recovery validation: covers_maximum_value_and_le_268435456 compatibility_impact: additive required_test: cache-contract:redis-command-byte-admission-bounded - name: APP_CACHE_REDIS_POSITIVE_SOFT_TTL type: duration default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-cache-resilience validation: optional_spring_duration_non_zero_le_positive_hard_ttl compatibility_impact: additive required_test: cache-contract:redis-soft-hard-ttl-order - name: APP_CACHE_REDIS_TTL_JITTER type: float default: 0.10 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-cache-resilience validation: decimal_0_to_0_5 compatibility_impact: additive required_test: cache-contract:redis-ttl-jitter-bounded - name: APP_CACHE_REDIS_MINIMUM_HARD_TTL type: duration default: 1s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-cache-resilience validation: spring_duration_shorthand_non_zero_le_configured_hard_ttls compatibility_impact: additive required_test: cache-contract:redis-hard-ttl-minimum - name: APP_CACHE_REDIS_NAMESPACE_ENVIRONMENT # DEPRECATED 2026-08-10: the cache no longer renders its own key prefix. Four capabilities # each joining two free-form tokens produced four prefixes, and the ACL pattern that was meant # to fence the deployment in matched none of them. The row is kept (not deleted) so a # deployment still setting it can be told what replaced it. # Replaced by: app.redis.namespace.environment (APP_REDIS_NAMESPACE_ENVIRONMENT), shared by # every capability. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: local allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: codex-phase-a-ci-recovery validation: lowercase_slug compatibility_impact: behavior-change required_test: cache-contract:redis-namespace-environment-bound - name: APP_CACHE_REDIS_SEMANTIC_REGION # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: string default: default allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: codex-phase-a-ci-recovery validation: lowercase_slug compatibility_impact: behavior-change required_test: cache-contract:redis-semantic-region-bound - name: APP_CACHE_REDIS_MAXIMUM_VALUE_BYTES # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 1048576 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: codex-phase-a-ci-recovery validation: int_1_to_16777216 compatibility_impact: additive required_test: cache-contract:redis-value-size-bounded - name: APP_CACHE_REDIS_L1_ENABLED # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: boolean_strict_cache_only compatibility_impact: additive required_test: cache-contract:redis-l1-disabled-default - name: APP_CACHE_REDIS_L1_MAXIMUM_ENTRIES # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 10000 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: int_1_to_1000000 compatibility_impact: additive required_test: cache-contract:redis-l1-cardinality-bounded - name: APP_CACHE_REDIS_L1_MAXIMUM_WEIGHT_BYTES # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 67108864 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: int_1_to_1073741824_accounting_proxy compatibility_impact: additive required_test: cache-contract:redis-l1-weight-bounded - name: APP_CACHE_REDIS_L1_MAXIMUM_ENTRY_WEIGHT_BYTES # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 1048576 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: positive_not_above_l1_maximum_weight compatibility_impact: additive required_test: cache-contract:redis-l1-entry-weight-bounded - name: APP_CACHE_REDIS_L1_TTL # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 30s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: spring_duration_shorthand_non_zero_le_1h compatibility_impact: additive required_test: cache-contract:redis-l1-ttl-bounded - name: APP_CACHE_REDIS_L1_GENERATION_RECHECK_INTERVAL # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: duration default: 5s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: spring_duration_shorthand_non_zero_le_l1_ttl compatibility_impact: additive required_test: cache-contract:redis-l1-generation-recheck-bounded - name: APP_CACHE_REDIS_L1_INVALIDATION_QUEUE_CAPACITY # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 type: int default: 1024 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: redis-production-capability validation: int_1_to_65536 compatibility_impact: additive required_test: cache-contract:redis-l1-invalidation-queue-bounded - name: APP_CACHE_DEFAULT_TTL # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 # source: feature-cache-consistency-contract 2026-05-22 # "TTL | explicit per key family | no-cache for sensitive data | immortal cache forbidden" type: duration default: 300s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-cache-consistency-contract validation: spring_duration_shorthand_non_zero compatibility_impact: behavior-change required_test: cache-contract:default-ttl-bounded - name: APP_CACHE_NEGATIVE_TTL # DEPRECATED 2026-08-10: the settings class that bound this property was removed # with the previous Redis generation, so the key reached nothing. The row is kept # (not deleted) so a deployment still setting it can be told what replaced it. deprecated_orphaned: true removal_deadline: 2026-11-30 # source: feature-cache-consistency-contract 2026-05-22 # "negative cache 정책 = 존재하지 않는 row는 짧은 TTL(60s) 캐싱 허용" type: duration default: 60s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-cache-consistency-contract validation: spring_duration_shorthand compatibility_impact: additive required_test: cache-contract:negative-ttl-bounded # === Messaging / Kafka (feature-domain-event-outbox-contract + integration-adapter-templates) === - name: APP_MESSAGING_BROKER # source: messaging multi-broker redesign 2026-06-16 — single active broker selection # (app.messaging.broker=); blank = messaging disabled. Replaces the former # Kafka-binary APP_MESSAGING_KAFKA_ENABLED. Adding a broker is new files only. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-integration-adapter-templates validation: none compatibility_impact: behavior-change required_test: adapter-contract:messaging-broker-selection - name: APP_MESSAGING_KAFKA_BROKERS # source: feature-domain-event-outbox-contract — "Kafka는 optional integration adapter" # (broker 활성화 시 endpoint 필요) type: csv_list default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-integration-adapter-templates validation: csv_of_host_port_when_kafka_enabled compatibility_impact: behavior-change required_test: adapter-contract:kafka-brokers-when-enabled # === Notification adapters (feature-integration-adapter-templates) === - name: APP_NOTIFICATION_SLACK_PROVIDER # source: notification provider-SPI redesign 2026-06-16 — single active Slack provider # selection (app.notification.slack.provider=, e.g. webhook); blank = Slack disabled. # Replaces the former provider-binary APP_NOTIFICATION_SLACK_ENABLED. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-integration-adapter-templates validation: none compatibility_impact: behavior-change required_test: adapter-contract:notification-slack-provider-selection - name: APP_NOTIFICATION_EMAIL_PROVIDER # source: notification provider-SPI redesign 2026-06-16 — single active email provider # selection (app.notification.email.provider=, e.g. google-email); blank = email disabled. # Replaces the former provider-binary APP_NOTIFICATION_GOOGLE_EMAIL_ENABLED. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-integration-adapter-templates validation: none compatibility_impact: behavior-change required_test: adapter-contract:notification-email-provider-selection # === Fileserver R2 local-persistent provider === - name: APP_FILESERVER_ENABLED # source: Fileserver R2 control-plane/provider-selection design 2026-07-28. # Disabled is the shipped safe default. Enabling requires every local attestation # value below and an exact app.fileserver destination/provider graph. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-r2-control-plane-provider-selection validation: boolean_strict compatibility_impact: additive required_test: fileserver-r2:disabled-default-and-enabled-attestation - name: APP_FILESERVER_LOCAL_ROOT # Pre-provisioned local-persistent root. The runtime additionally attests real # path, ancestor/root symlinks, owner/mode, FileStore, sentinel, and capabilities. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-r2-control-plane-provider-selection validation: absolute_existing_directory_when_app_fileserver_enabled compatibility_impact: additive required_test: fileserver-r2:disabled-default-and-enabled-attestation - name: APP_FILESERVER_LOCAL_EXPECTED_FILE_STORE_NAME # Exact FileStore.name() expected for the pre-provisioned root. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-r2-control-plane-provider-selection validation: non_empty_string_when_app_fileserver_enabled compatibility_impact: additive required_test: fileserver-r2:disabled-default-and-enabled-attestation - name: APP_FILESERVER_LOCAL_EXPECTED_FILE_STORE_TYPE # Exact FileStore.type() expected for the pre-provisioned root. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-r2-control-plane-provider-selection validation: non_empty_string_when_app_fileserver_enabled compatibility_impact: additive required_test: fileserver-r2:disabled-default-and-enabled-attestation - name: APP_FILESERVER_LOCAL_MOUNT_SENTINEL_SHA256 # Lowercase SHA-256 of the operator-created .ca-fileserver-volume sentinel. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-r2-control-plane-provider-selection validation: lowercase_sha256_when_app_fileserver_enabled compatibility_impact: additive required_test: fileserver-r2:disabled-default-and-enabled-attestation - name: APP_FILESERVER_LOCAL_EXPECTED_OWNER # Exact filesystem owner expected for the attested root and private namespace. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-r2-control-plane-provider-selection validation: non_empty_string_when_app_fileserver_enabled compatibility_impact: additive required_test: fileserver-r2:disabled-default-and-enabled-attestation # === HTTP Client platform (app.httpclient.*) === # # Only the master switch is registered here. The per-client surface is an indexed list whose # element cannot be templated in application.yml without materialising a nameless client in every # deployment, so it has no deployment-independent value for this registry to hold and is # registered in docs/httpclient/env-fields.yaml instead. That manifest is derived from # HttpClientPlatformSettings and enforced in both directions: a field with no entry fails # HttpClientPlatformEnvManifestTest, and an APP_HTTPCLIENT_ variable with no field fails startup. - name: APP_HTTPCLIENT_ENABLED # Master switch. While false the platform block is not bound at all: the auto-configuration that # binds it is not processed, so no bean, connection pool, TLS context, credential, thread or # gateway exists, and a malformed HTTP client setting cannot fail this deployment's startup. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: httpclient-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: httpclient-platform:off-state-zero-side-effects-and-env-manifest-parity # === Fileserver HTTP platform (app.fileserver-platform.*) === # # A different capability from the app.fileserver R2 publication block above. Separate # namespaces so the two cannot be switched on together by accident, and so a change to one # cannot silently re-shape the other. - name: APP_FILESERVER_PLATFORM_ENABLED # Master switch. While false the platform block is not bound at all: the auto-configuration that # binds it is not processed, so no bean, route, thread, schema check or filesystem call exists. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_INSTANCE_ID # Writer-lease owner; must be unique per instance. The startup gate treats the default as # single-instance and refuses a shared-metadata claim it cannot support. type: string default: local-node allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: non_empty_string compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_DEFAULT_NAMESPACE # Namespace applied to a request that does not name one. type: string default: default allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: non_empty_string compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_STORAGE_ROOT # Absolute path on its own volume. A relative root resolves against the process working # directory, which differs between a container and a test, so it is refused. type: string default: /var/lib/backend/files allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: absolute_path_outside_forbidden_ancestors compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_STORAGE_PUBLISH_MODE # atomic-move-required fails startup when the probe cannot prove an atomic rename. type: string default: atomic-move-preferred allowed_values: [atomic-move-required, atomic-move-preferred, metadata-pointer] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: enum_in_allowed_values compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_STORAGE_BUFFER_SIZE # Bounds every transfer allocation, so resident bytes never scale with file size. type: data_size default: 128KB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: between_4kb_and_8mb compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_STORAGE_FORBIDDEN_ROOT_ANCESTORS # A storage root under a web root turns every upload into a published file; under a config # root, into a configuration change. Both are refused at binding time. type: csv_list default: /app,/etc,/usr/share/nginx/html allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: absolute_path_list compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_UPLOAD_MAX_FILE_SIZE # Also drives spring.servlet.multipart.max-file-size. One placeholder for both: a smaller # servlet ceiling rejects the upload before any Fileserver code, including its error mapping. type: data_size default: 100MB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_data_size compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_UPLOAD_MAX_REQUEST_SIZE # Also drives spring.servlet.multipart.max-request-size. type: data_size default: 110MB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: at_least_max_file_size compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_UPLOAD_INITIAL_RESERVATION # Quota reserved for an upload that does not declare its length. type: data_size default: 8MB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: at_most_max_file_size compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_UPLOAD_MAX_PARTS # Ceiling on parts in one multipart/batch request. type: integer default: 16 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_integer compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_UPLOAD_TTL # Lifetime of an upload resource before it is reclaimable. type: duration default: 1h allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_duration compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_UPLOAD_RESERVATION_TTL # Lifetime of a quota reservation whose upload never completed. type: duration default: 24h allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_duration compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_UPLOAD_LEASE_DURATION # Writer lease. Renewed at one third of this while a transfer runs; a transfer that cannot # renew is fenced out before its next physical write. type: duration default: 30s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_duration compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_UPLOAD_REQUIRE_CONTENT_LENGTH # When true a raw upload without Content-Length is refused with 411. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_DOWNLOAD_CACHE_CONTROL # Cache-Control emitted on every download response. type: string default: private, no-store allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: non_empty_string compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_DOWNLOAD_INLINE_ALLOWED # Inline rendering is off by default; scriptable content is forced to attachment regardless. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_DOWNLOAD_MAX_RANGES # Multi-range is opt-in; above one the response is multipart/byteranges. type: integer default: 1 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: between_1_and_8 compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_DOWNLOAD_MAX_RANGE_BYTES # Applies to the single-range profile too, so the ceiling is not inert in the default # configuration that almost every deployment runs. type: data_size default: 100MB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_data_size compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_DOWNLOAD_ZERO_COPY_ENABLED # Changes only where bytes are copied, never a header or a status. type: boolean default: true allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_DOWNLOAD_ZERO_COPY_MINIMUM_BYTES # Below this the syscall setup costs more than it saves. type: data_size default: 16MB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_data_size compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_TRANSFER_CORE_SIZE # Bounded transfer pool; rejection becomes a retryable 429, never caller-runs. type: integer default: 8 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_integer_at_most_max_size compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_TRANSFER_MAX_SIZE # Upper bound of the transfer pool. type: integer default: 32 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_integer compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_TRANSFER_QUEUE_CAPACITY # Bounded queue; an unbounded one trades a fast 429 for eventual heap exhaustion. type: integer default: 64 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_integer compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_TRANSFER_AWAIT_SECONDS # Shutdown drain and per-transfer caller wait. type: integer default: 300 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_integer compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_SECURITY_ACCESS_POLICY # No permissive default. `required` fails startup unless the deployment supplies a # FileAccessPolicy bean; `unenforced` is refused under a production profile. type: string default: required allowed_values: [required, role-based, unenforced] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: enum_in_allowed_values compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_SECURITY_READ_ROLES # Roles accepted for read operations under the role-based policy. type: csv_list default: ROLE_FILE_READ allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: non_empty_role_list compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_SECURITY_WRITE_ROLES # Roles accepted for write operations under the role-based policy. type: csv_list default: ROLE_FILE_WRITE allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: non_empty_role_list compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_SECURITY_ADMIN_ROLES # Roles accepted for the management plane. Admin routes additionally require this role at the # servlet chain, not only in application policy. type: csv_list default: ROLE_FILE_ADMIN allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: non_empty_role_list compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_VERIFICATION_TIMEOUT # Whole-chain verification budget for one upload. type: duration default: 5s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_duration compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_VERIFICATION_REQUIRE_MEDIA_TYPE_VERDICT # When true a file whose type could not be determined is refused rather than published. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_VERIFICATION_INLINE_SAFE_PROFILE # When true scriptable content is accepted instead of quarantined; only safe when downloads # are never served inline from a trusted origin. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_QUOTA_INSTANCE_UPLOAD_PERMITS # Concurrent uploads admitted per instance. type: integer default: 16 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_integer compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_QUOTA_SCOPE_UPLOAD_PERMITS # Concurrent uploads admitted per namespace. type: integer default: 4 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_integer_at_most_instance_permits compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_QUOTA_DIRECT_DOWNLOAD_PERMITS # Concurrent direct downloads admitted per instance. type: integer default: 64 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_integer compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_QUOTA_SOFT_HIGH_WATER # Storage fraction at which new uploads start being shed. type: string default: 0.70 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: fraction_below_hard_high_water compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_QUOTA_HARD_HIGH_WATER # Storage fraction at which every upload is refused. type: string default: 0.85 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: fraction_within_zero_and_one compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_ADMIN_ENABLED # Management plane, a separate decision from the data plane. Requires the master switch too: # enabling it alone now does nothing instead of half-building a bean graph. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_ADMIN_ORPHAN_MINIMUM_AGE # How long an unreferenced object must exist before a scan may name it; anything younger is # assumed mid-commit rather than abandoned. type: duration default: 1h allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_duration compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_CLEANUP_ENABLED # Background reclamation. Off by default because the worker deletes physical objects. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_CLEANUP_INTERVAL # Fixed delay between batches; sole owner of the schedule, with no @Scheduled placeholder # carrying a second default. type: duration default: 60s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_duration compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_CLEANUP_MAX_ITEMS # Item ceiling for one batch, so a backlog cannot monopolise the scheduler. type: integer default: 100 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_integer compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_CLEANUP_MAX_BYTES # Byte ceiling for one batch. type: data_size default: 1GB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_data_size compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_CLEANUP_RETRY_BACKOFF # Delay before a failed cleanup item is retried. type: duration default: 5m allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_duration compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_TUS_ENABLED # tus 1.0. Requires the master switch too. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_HTTPBIS_DRAFT12_ENABLED # Unratified draft whose contract can change without notice. Requires the master switch too. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_NGINX_ENABLED # Front-proxy delegation. Startup attests the internal mapping by exercising it; a mapping the # proxy cannot resolve answers 200 with an empty body, so it fails closed instead. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_NGINX_INTERNAL_PREFIX # Internal location the proxy resolves to the storage root. type: string default: /__files/ allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: internal_uri_prefix compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_NGINX_OBJECT_SUFFIX # Suffix appended to the sharded object key in the internal URI. type: string default: .bin allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: non_empty_string compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_NGINX_MINIMUM_SIZE # Below this the request is served by the application rather than delegated. type: data_size default: 16MB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: positive_data_size compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_OBSERVABILITY_METRICS_ENABLED # When false neither the metrics port nor the fingerprint is created, and no key is required. type: boolean default: true allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: boolean_strict compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip - name: APP_FILESERVER_PLATFORM_OBSERVABILITY_FINGERPRINT_KEY # Keyed HMAC over file identifiers. An unkeyed digest of an enumerable identifier is # reversible, so startup fails while metrics are on and this is blank. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: fileserver-http-platform-activation-boundary validation: non_empty_when_metrics_enabled compatibility_impact: additive required_test: fileserver-platform:off-state-zero-side-effects-and-env-round-trip # === File / Upload (feature-file-resource-handling-contract) === - name: APP_FILE_UPLOAD_MAX_SIZE # source: feature-file-resource-handling-contract 2026-05-22 # "Spring spring.servlet.multipart.max-file-size 10MB" type: data_size default: 10MB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-file-resource-handling-contract validation: spring_data_size_le_10MB_by_default compatibility_impact: behavior-change required_test: file-contract:upload-size-enforced - name: APP_FILE_UPLOAD_GLOBAL_REQUEST_MAX_SIZE # source: feature-file-resource-handling-contract 2026-05-22 # "global request size 12MB" type: data_size default: 12MB allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-file-resource-handling-contract validation: spring_data_size compatibility_impact: behavior-change required_test: file-contract:global-request-size-enforced # === Runtime / Lifecycle (feature-runtime-health-lifecycle-contract + container-runtime) === # APP_SHUTDOWN_TIMEOUT superseded by APP_SERVER_SHUTDOWN_TIMEOUT (HTTP server section, # owner feature-env-driven-runtime-configuration). The k8s terminationGracePeriod # alignment requirement (feature-container-runtime-contract) now applies to # APP_SERVER_SHUTDOWN_TIMEOUT. # === Async executor (feature-background-job-async-contract) === - name: APP_ASYNC_EXECUTOR_CORE_SIZE # source: feature-background-job-async-contract 2026-05-22 # "executor pool sizing default = core=10, max=50, queue=200" type: int default: 10 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-background-job-async-contract validation: positive_int compatibility_impact: behavior-change required_test: async-contract:executor-core-size - name: APP_ASYNC_EXECUTOR_MAX_SIZE # source: feature-background-job-async-contract 2026-05-22 # "core=10, max=50, queue=200" type: int default: 50 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-background-job-async-contract validation: positive_int_ge_core compatibility_impact: behavior-change required_test: async-contract:executor-max-size - name: APP_ASYNC_EXECUTOR_QUEUE_CAPACITY # source: feature-background-job-async-contract 2026-05-22 # "queue=200" + "unbounded queue forbidden" type: int default: 200 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: feature-background-job-async-contract validation: positive_int_bounded compatibility_impact: behavior-change required_test: async-contract:executor-queue-bounded # === Notification delivery platform (NTF-025 — configuration surface) === # The tree exists in application.yml as ca-skeleton.notification.platform, disabled by # default. Every key carries an inline default so a deployment that leaves the platform off # supplies nothing. Reference: docs/notification/configuration.md. - name: APP_PERSISTENCE_JPA_ENABLED # source: five-adapter-runtime-remediation §5.1 — master switch for relational persistence. # false means no DataSource, no entity scan, no repositories, no Hibernate, no Flyway and no DB # health contributor; the old app.jpa-platform.enabled gated three add-on beans while reading # like this one and defaulting to on. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-five-adapter-activation validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:persistence-jpa-disabled-safe - name: APP_PERSISTENCE_MONGO_ENABLED # source: five-adapter-runtime-remediation §5.1 — master switch for MongoDB persistence. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-five-adapter-activation validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:persistence-mongo-disabled-safe - name: APP_PERSISTENCE_MONGO_ACTIVE_PROFILE # source: five-adapter-runtime-remediation §5.1 — selects exactly one Mongo profile. The runtime # builds one sync client and one pool; a profile present in the map but not selected has neither # its secret resolved nor a client created. type: string default: "" classification: public-config required: false required_when: APP_PERSISTENCE_MONGO_ENABLED=true reload_policy: restart-only owner_branch: worktree-five-adapter-activation validation: nonblank-when-required compatibility_impact: behavior-change required_test: adapter-contract:persistence-mongo-active-profile - name: APP_MESSAGING_ENABLED # source: five-adapter-runtime-remediation §5.1 — master switch for broker publication. # APP_MESSAGING_BROKER selects which transport and is no longer the de-facto switch. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-five-adapter-activation validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:messaging-disabled-safe - name: APP_GRAPHQL_ENABLED # source: five-adapter-runtime-remediation §5.1 — master switch for the GraphQL transport. # false publishes no /graphql route, including the one Spring GraphQL would publish by itself. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-five-adapter-activation validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:graphql-disabled-safe - name: APP_GRAPHQL_DEPLOYMENT_MODE # source: five-adapter-runtime-remediation §5.1 / GQL-INT-002 — replaces backend.graphql.production # and backend.graphql.environment, which defaulted to production=false with # environment=PRODUCTION_PUBLIC and let anonymous-principal and allow-by-default authorization # read one axis while the other claimed production. type: enum default: "" allowed_values: [LOCAL, DEV, PRODUCTION_INTERNAL, PRODUCTION_PUBLIC] classification: public-config required: false required_when: APP_GRAPHQL_ENABLED=true reload_policy: restart-only owner_branch: worktree-five-adapter-activation validation: enum compatibility_impact: behavior-change required_test: adapter-contract:graphql-deployment-mode - name: APP_OUTBOX_ENABLED # source: five-adapter-runtime-remediation §6.1 JPA-INT-004 — the outbox capability switch. # relay-enabled below only starts the scheduler; conflating the two meant a relay-off deployment # still assembled outbox metrics over a store port a database-less runtime does not have. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-five-adapter-activation validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:outbox-capability-disabled-safe - name: APP_OUTBOX_RELAY_ENABLED # source: five-adapter-runtime-remediation §6.3 MSG-INT-001 — starts the relay scheduler. # Requires APP_OUTBOX_ENABLED, APP_PERSISTENCE_JPA_ENABLED and APP_MESSAGING_ENABLED with a # broker; the shipped default was true beside a blank broker, which refused every startup. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-five-adapter-activation validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:outbox-relay-dependency - name: APP_NOTIFICATION_PLATFORM_ENABLED # source: NTF-025 — master switch for the notification delivery platform; false binds nothing at all type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:notification-platform-disabled-safe - name: APP_NOTIFICATION_PLATFORM_CONTACT_ENCRYPTION_KEY # source: NTF-INT-007 — Encrypts recipient contact points at rest — addresses and phone numbers. # Full row owned by secrets-classification.yaml. Bound by # ca-skeleton.notification.platform.secrets.contact-encryption-key; the platform decodes it at startup and # refuses to boot if it is blank, shorter than 32 bytes, or equal to another purpose's key. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: base64_at_least_32_bytes_and_distinct_per_purpose compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_CONTACT_LOOKUP_HMAC_KEY # source: NTF-INT-007 — Blind index over contact points, so a lookup never needs the plaintext. # Full row owned by secrets-classification.yaml. Bound by # ca-skeleton.notification.platform.secrets.contact-lookup-hmac-key; the platform decodes it at startup and # refuses to boot if it is blank, shorter than 32 bytes, or equal to another purpose's key. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: base64_at_least_32_bytes_and_distinct_per_purpose compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_CALLBACK_SIGNING_KEY # source: NTF-INT-007 — Signs the callback URLs a provider posts delivery outcomes back to. # Full row owned by secrets-classification.yaml. Bound by # ca-skeleton.notification.platform.secrets.callback-signing-key; the platform decodes it at startup and # refuses to boot if it is blank, shorter than 32 bytes, or equal to another purpose's key. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: base64_at_least_32_bytes_and_distinct_per_purpose compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_PROVIDER_CREDENTIAL_KEY # source: NTF-INT-007 — Encrypts stored provider credentials, which are themselves secrets. # Full row owned by secrets-classification.yaml. Bound by # ca-skeleton.notification.platform.secrets.provider-credential-key; the platform decodes it at startup and # refuses to boot if it is blank, shorter than 32 bytes, or equal to another purpose's key. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: base64_at_least_32_bytes_and_distinct_per_purpose compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_PAYLOAD_ENCRYPTION_KEY # source: NTF-INT-007 — Encrypts notification variables and retained callback bodies at rest. # Full row owned by secrets-classification.yaml. Bound by # ca-skeleton.notification.platform.secrets.payload-encryption-key; the platform decodes it at startup and # refuses to boot if it is blank, shorter than 32 bytes, or equal to another purpose's key. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: base64_at_least_32_bytes_and_distinct_per_purpose compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_VAPID_SIGNING_KEY # source: NTF-INT-007 — Signs Web Push requests; the browser push service rejects anything else. # Full row owned by secrets-classification.yaml. Bound by # ca-skeleton.notification.platform.secrets.vapid-signing-key; the platform decodes it at startup and # refuses to boot if it is blank, shorter than 32 bytes, or equal to another purpose's key. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: base64_at_least_32_bytes_and_distinct_per_purpose compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_PROVIDER_REQUEST_LOOKUP_HMAC_KEY # source: NTF-INT-007 — Keyed hash of provider request ids, which are provider-side identifiers. # Full row owned by secrets-classification.yaml. Bound by # ca-skeleton.notification.platform.secrets.provider-request-lookup-hmac-key; the platform decodes it at startup and # refuses to boot if it is blank, shorter than 32 bytes, or equal to another purpose's key. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: base64_at_least_32_bytes_and_distinct_per_purpose compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_CALLBACK_FINGERPRINT_HMAC_KEY # source: NTF-INT-007 — Keyed fingerprint of callback bodies, used to detect replays. # Full row owned by secrets-classification.yaml. Bound by # ca-skeleton.notification.platform.secrets.callback-fingerprint-hmac-key; the platform decodes it at startup and # refuses to boot if it is blank, shorter than 32 bytes, or equal to another purpose's key. type: string default: null allowed_values: null classification: secret required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: base64_at_least_32_bytes_and_distinct_per_purpose compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_CONTACT_ENCRYPTION_KEY_ID # source: NTF-INT-007 — the id written into every envelope the CONTACT_ENCRYPTION key produces. # An identifier, not key material, so it is public-config; the material itself is the # APP_NOTIFICATION_PLATFORM_CONTACT_ENCRYPTION_KEY row above. Bound into # ca-skeleton.notification.platform.secrets.active-key-ids.CONTACT_ENCRYPTION. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank_when_platform_enabled compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_CONTACT_LOOKUP_HMAC_KEY_ID # source: NTF-INT-007 — the id written into every envelope the CONTACT_LOOKUP_HMAC key produces. # An identifier, not key material, so it is public-config; the material itself is the # APP_NOTIFICATION_PLATFORM_CONTACT_LOOKUP_HMAC_KEY row above. Bound into # ca-skeleton.notification.platform.secrets.active-key-ids.CONTACT_LOOKUP_HMAC. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank_when_platform_enabled compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_CALLBACK_SIGNING_KEY_ID # source: NTF-INT-007 — the id written into every envelope the CALLBACK_SIGNING key produces. # An identifier, not key material, so it is public-config; the material itself is the # APP_NOTIFICATION_PLATFORM_CALLBACK_SIGNING_KEY row above. Bound into # ca-skeleton.notification.platform.secrets.active-key-ids.CALLBACK_SIGNING. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank_when_platform_enabled compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_PROVIDER_CREDENTIAL_KEY_ID # source: NTF-INT-007 — the id written into every envelope the PROVIDER_CREDENTIAL key produces. # An identifier, not key material, so it is public-config; the material itself is the # APP_NOTIFICATION_PLATFORM_PROVIDER_CREDENTIAL_KEY row above. Bound into # ca-skeleton.notification.platform.secrets.active-key-ids.PROVIDER_CREDENTIAL. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank_when_platform_enabled compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_PAYLOAD_ENCRYPTION_KEY_ID # source: NTF-INT-007 — the id written into every envelope the PAYLOAD_ENCRYPTION key produces. # An identifier, not key material, so it is public-config; the material itself is the # APP_NOTIFICATION_PLATFORM_PAYLOAD_ENCRYPTION_KEY row above. Bound into # ca-skeleton.notification.platform.secrets.active-key-ids.PAYLOAD_ENCRYPTION. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank_when_platform_enabled compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_VAPID_SIGNING_KEY_ID # source: NTF-INT-007 — the id written into every envelope the VAPID_SIGNING key produces. # An identifier, not key material, so it is public-config; the material itself is the # APP_NOTIFICATION_PLATFORM_VAPID_SIGNING_KEY row above. Bound into # ca-skeleton.notification.platform.secrets.active-key-ids.VAPID_SIGNING. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank_when_platform_enabled compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_PROVIDER_REQUEST_LOOKUP_HMAC_KEY_ID # source: NTF-INT-007 — the id written into every envelope the PROVIDER_REQUEST_LOOKUP_HMAC key produces. # An identifier, not key material, so it is public-config; the material itself is the # APP_NOTIFICATION_PLATFORM_PROVIDER_REQUEST_LOOKUP_HMAC_KEY row above. Bound into # ca-skeleton.notification.platform.secrets.active-key-ids.PROVIDER_REQUEST_LOOKUP_HMAC. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank_when_platform_enabled compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_CALLBACK_FINGERPRINT_HMAC_KEY_ID # source: NTF-INT-007 — the id written into every envelope the CALLBACK_FINGERPRINT_HMAC key produces. # An identifier, not key material, so it is public-config; the material itself is the # APP_NOTIFICATION_PLATFORM_CALLBACK_FINGERPRINT_HMAC_KEY row above. Bound into # ca-skeleton.notification.platform.secrets.active-key-ids.CALLBACK_FINGERPRINT_HMAC. type: string default: null allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank_when_platform_enabled compatibility_impact: behavior-change required_test: adapter-contract:notification-secret-material-required - name: APP_NOTIFICATION_PLATFORM_SMTP_ENABLED # source: NTF-INT-001 — master switch of the shipped SMTP provider profile; false means assembly skips it entirely. type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_PRIMARY # source: NTF-INT-001 — whether this profile is the primary route for EMAIL; exactly one primary per channel. type: boolean default: true allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_ENVIRONMENT # source: NTF-INT-001 — the profile's declared environment, carried on every dispatch record. type: string default: local allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_CREDENTIAL_PROFILE # source: NTF-INT-001 — the credential profile the relay's credentials are resolved through. type: string default: default allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_blank compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_TIMEOUT # source: NTF-INT-001 — per-attempt provider timeout for this profile. type: duration default: 10s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: duration_spring_shorthand compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_MAX_CONCURRENCY # source: NTF-INT-001 — how many attempts this profile may have in flight. type: int default: 4 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: positive_int compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_RATE_PER_SECOND # source: NTF-INT-001 — the profile's attempt rate limit. type: int default: 10 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: positive_int compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_TLS_MODE # source: NTF-INT-001 — transport security of the SMTP session; the type has no plaintext member. type: enum default: STARTTLS_REQUIRED allowed_values: [STARTTLS_REQUIRED, IMPLICIT_TLS] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: enum_in_allowed_values compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_SENDER_IDENTITY # source: NTF-INT-001 — the envelope sender every message is sent as. type: string default: no-reply@example.invalid allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: email_address compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_CONNECT_TIMEOUT # source: NTF-INT-001 — how long a connection attempt to the relay may take. type: duration default: 5s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: duration_spring_shorthand compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_READ_TIMEOUT # source: NTF-INT-001 — how long a relay reply may take. type: duration default: 10s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: duration_spring_shorthand compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_WRITE_TIMEOUT # source: NTF-INT-001 — how long a write to the relay may take. type: duration default: 10s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: duration_spring_shorthand compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_NOTIFICATION_PLATFORM_SMTP_DISPATCH_CONCURRENCY # source: NTF-INT-001 — size of the bounded executor SMTP sends run on. type: int default: 4 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: positive_int compatibility_impact: behavior-change required_test: adapter-contract:notification-smtp-provider-assembled - name: APP_OPENAPI_DOCS_ENABLED # source: five-adapter-runtime-remediation §9 — whether /v3/api-docs is served; application-prod.yml pins it false. Stated rather than defaulted because # SpringDoc warns on every startup until a deployment decides, and a warning on every start is # one nobody reads. type: boolean default: true allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: main validation: boolean compatibility_impact: behavior-change required_test: env-contract:openapi-exposure-decided - name: APP_OPENAPI_UI_ENABLED # source: five-adapter-runtime-remediation §9 — whether the Swagger UI is served; application-prod.yml pins it false. Stated rather than defaulted because # SpringDoc warns on every startup until a deployment decides, and a warning on every start is # one nobody reads. type: boolean default: true allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: main validation: boolean compatibility_impact: behavior-change required_test: env-contract:openapi-exposure-decided - name: APP_NOTIFICATION_PLATFORM_MODE # source: NTF-025 — SERVING refuses to start without a working provider; INGEST_ONLY stores and does not dispatch. # The constant is INGEST_ONLY. This row said ACCEPT_ONLY, a name NotificationPlatformMode has # never had, so an operator following the registry got a binding failure naming a value the # documentation does not mention. NotificationModeSsotTest derives the list below from the enum. type: enum default: SERVING allowed_values: [SERVING, INGEST_ONLY] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: enum_of_notification_platform_mode compatibility_impact: behavior-change required_test: adapter-contract:notification-platform-mode - name: APP_NOTIFICATION_PLATFORM_CLAIM_BATCH_SIZE # source: NTF-025 — how many recipient deliveries one scheduler pass claims; 1..1000, refused outside that at binding type: integer default: 50 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: integer_1_to_1000 compatibility_impact: behavior-change required_test: adapter-contract:notification-dispatch-bounds - name: APP_NOTIFICATION_PLATFORM_LEASE_DURATION # source: NTF-025 — must outlast a provider call plus its timeout, or a live worker's delivery is claimed by a second one type: duration default: 2m allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: positive_duration compatibility_impact: behavior-change required_test: adapter-contract:notification-lease-fencing - name: APP_NOTIFICATION_PLATFORM_POLL_INTERVAL # source: NTF-025 — how often the scheduler asks for work when the last pass claimed nothing type: duration default: 1s allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: positive_duration compatibility_impact: behavior-change required_test: adapter-contract:notification-dispatch-bounds - name: APP_NOTIFICATION_PLATFORM_MAX_CONCURRENCY # source: NTF-025 — ceiling on in-flight provider calls across the whole process type: integer default: 64 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: positive_integer compatibility_impact: behavior-change required_test: adapter-contract:notification-dispatch-bounds - name: APP_NOTIFICATION_PLATFORM_MAX_ADDITIONAL_ATTEMPTS # source: NTF-025 — retries after the first attempt; 0 means one attempt and no retry type: integer default: 4 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: non_negative_integer compatibility_impact: behavior-change required_test: adapter-contract:notification-retry-policy - name: APP_NOTIFICATION_PLATFORM_MAX_QUEUE_AGE # source: NTF-025 — after this, a queued delivery expires rather than being sent late type: duration default: 24h allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: positive_duration compatibility_impact: behavior-change required_test: adapter-contract:notification-expiry - name: APP_NOTIFICATION_PLATFORM_ALLOW_AMBIGUOUS_FALLBACK # source: NTF-025 — an ambiguous attempt reached the provider with an unread outcome; falling back risks a duplicate send type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:notification-ambiguity - name: APP_NOTIFICATION_PLATFORM_CALLBACKS_ENABLED # source: NTF-025 — whether the platform exposes provider callback endpoints type: boolean default: false allowed_values: [true, false] classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: boolean compatibility_impact: behavior-change required_test: adapter-contract:notification-callback-ingestion - name: APP_NOTIFICATION_PLATFORM_CALLBACK_MAX_BODY_BYTES # source: NTF-025 — ceiling is 65508 = ciphertext column minus AES-GCM nonce and tag; larger is refused at binding type: integer default: 65508 allowed_values: null classification: public-config required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: integer_1_to_65508 compatibility_impact: behavior-change required_test: adapter-contract:notification-callback-body-bound - name: APP_NOTIFICATION_PLATFORM_CALLBACK_TRUSTED_PROXIES # source: NTF-001 — peers whose forwarded headers may be believed when reconstructing the URL a # provider signed. Empty means the resolver uses what the container observed; honouring # forwarded headers unconditionally would let any caller pick the URL its signature is checked # against, which defeats the signature. type: csv default: "" allowed_values: null classification: security-relevant required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: none compatibility_impact: behavior-change required_test: adapter-contract:notification-callback-url-resolution - name: APP_NOTIFICATION_PLATFORM_CALLBACK_REPLAY_SKEW # source: NTF-025 — how far a callback timestamp may differ from local time before it is treated as a replay type: duration default: 5m allowed_values: null classification: security-relevant required: false reload_policy: restart-only owner_branch: worktree-notification-platform validation: positive_duration compatibility_impact: behavior-change required_test: adapter-contract:notification-callback-replay