Configuration

Profiles

Profiles are defined via Spring application-*.yml:

  • local: local developer settings (src/main/resources/application-local.yml)

  • mysql: MySQL settings with env overrides (src/main/resources/application-mysql.yml)

  • oracle: Oracle settings with env overrides (src/main/resources/application-oracle.yml)

Select the active profile with SPRING_PROFILES_ACTIVE (for example local, mysql, oracle).

Core HTTP settings

  • Context path: server.servlet.context-path=/configs-service (src/main/resources/application.yml)

  • Swagger UI: springdoc.swagger-ui.doc-expansion=none

Hazelcast client settings

The Hazelcast client is configured by ft-cache:

  • cache-config.path – defaults to classpath:; the effective resource is ${cache-config.path}hazelcast-client.yaml.

    • In container environments, CACHE_CONFIG_PATH is the typical env var name used to provide this value (Spring relaxed binding maps it to cache-config.path).

  • HZ_MEMBERS – overrides members list (comma/space separated).

    • If a member entry does not contain a port, :5701 is appended by the ft-cache resolver.

  • cache.is-server – when true, starts an embedded Hazelcast member from ${cache-config.path}hazelcast.yaml (not used for this service in production).

    • In container environments, CACHE_IS_SERVER is the typical env var name.

Production note: cluster-name is configured as dev.

Database settings

Database configuration is profile-specific:

  • mysql profile reads DB settings from application-mysql.yml (env overrides supported).

  • oracle profile reads DB settings from application-oracle.yml (env overrides supported).

See Environment variables for the full env var matrix with verified defaults and examples.

JWT and cookies

JWT and cookie settings come from the active profile YAML and can be overridden via environment variables.

See Environment variables for JWT_* and COOKIE_* inputs, defaults, and usage notes.

Mail

Spring Mail is configured in profile YAMLs (host, port, username/password, TLS flags) and used for:

  • user onboarding emails (mail/registration.html)

  • user deletion flows (auth/deletion/*)

Delivery modes (online / offline)

Email delivery is controlled by MAIL_MODE (property mail.mode), evaluated in MailDeliveryStatus from mail.mode plus Spring MailProperties. Values are case-insensitive; a blank or unknown value falls back to AUTO with a warning log. The supported values are AUTO and OFFLINE.

  • AUTO (default) — infers the mode from SMTP config: treated as OFFLINE when MAIL_HOST, MAIL_USERNAME, or MAIL_PASSWORD are not all set (non-blank); when they are all set it attempts email, but degrades to offline behaviour at runtime if the SMTP server is unreachable (see Runtime fallback below).

  • OFFLINE — never send email.

At startup the service logs the resolved mode, for example:

Mail delivery: mode=AUTO, smtpConfigured=false, effectiveOffline=true

Offline behavior

When offline (chosen explicitly via OFFLINE, inferred by AUTO, or reached at runtime when a configured SMTP server is unreachable):

  • Create user (POST /api/admin/users) and reset password (POST /api/admin/users/{id}/reset-password): the temporary password is not emailed. It is returned in the API response (passwordDelivery=RETURNED) so an admin can deliver it out-of-band.

  • User deletion request (POST /api/admin/users/{id}/deletion/request): OTP email confirmation is disabled. No OTP/token is issued and the response carries otpRequired=false, signalling the UI to show a plain confirmation. The account is still deleted in the /deletion/confirm step, called without a token/OTP (allowed only while OTP delivery is unavailable — configured offline or SMTP unreachable).

Online behavior

When online (AUTO with SMTP configured and reachable):

  • Temporary passwords are emailed; create/reset responses carry passwordDelivery=EMAIL and temporaryPassword=null.

  • Deletion issues an OTP intent and emails the OTP to the initiating admin’s address, returning otpRequired=true with token/expiry/otpLength/attemptLimit; the admin then calls /deletion/confirm with the OTP.

Because the OTP is sent to the initiating admin, that admin must have an email in online mode. Otherwise the deletion request fails with error code USER_DELETION_EMAIL_REQUIRED ("User email is required to request account deletion"). This email check applies only in online mode.

Runtime fallback on send failure

Under AUTO with SMTP configured, if the server is unreachable or a send throws, delivery degrades to the offline behaviour instead of erroring:

  • Create/reset password delivery degrades to passwordDelivery=RETURNED.

  • User deletion degrades to the no-OTP path: the request returns otpRequired=false and the account is deleted in the tokenless confirm step. The deletion confirm probes SMTP reachability (MailDeliveryStatus.isOtpConfirmationAvailable()) so it accepts a tokenless confirm when the server is down, since it has no OTP to send.

To keep this prompt, the JavaMail connect/read/write timeouts are fixed at 5000 ms (previously infinite, which could hang the request thread). They are configurable via spring.mail.properties.mail.smtp.connectiontimeout, .timeout, and .writetimeout.

See Security — User secret delivery for the rationale behind returning secrets in API responses.

Email template system

Email templates use table-based HTML for maximum email client compatibility:

  • Mobile-responsive — fluid width adapts to device screens

  • Dark-mode — includes color-scheme: light dark meta for clients that support it

  • MSO conditional comments — Microsoft Outlook rendering fixes

  • Multipart/alternative — every email includes a plain-text alternative for better deliverability and accessibility

Internationalization (i18n)

Email subjects, body text, and the brand name are localized via Spring MessageSource:

  • mail_messages.properties (English, default)

  • mail_messages_ru.properties (Russian)

The user’s locale is resolved from user.locale. If unset, English is used as fallback.

The brand name is controlled by the mail.brand message key:

  • English: "Configuration Center"

  • Russian: "Центр Конфигураций"

The MAIL_FROM_NAME environment variable has been removed. The sender display name now comes from the mail.brand message key.

Call-to-action button

The "Sign In" CTA button in emails is optional and controlled by MAIL_LOGIN_URL:

  • When set to a valid http:// or https:// URL, a styled button links to that URL.

  • When blank or non-HTTP, the button is replaced by a generic text hint ("Please sign in via your organization’s portal").

Security

  • All user inputs and MessageSource values are HTML-escaped before insertion into templates.

  • MAIL_LOGIN_URL is validated at startup; non-HTTP/HTTPS values are ignored with a warning log.

See Environment variables for MAIL_* inputs and profile-specific defaults.

Audit retention

Audit events are automatically cleaned up by AuditRetentionService, which runs daily at 03:00.

  • Default retention: 30 days

  • Configurable via AUDIT_RETENTION_DAYS (min 3, max 90, or 0 to disable)

See Auditing — Audit retention for full details.

See Environment variables for AUDIT_RETENTION_DAYS and AUDIT_REDACTION_FIELDS.

Actuator exposure (security note)

src/main/resources/application.yml exposes health, info, metrics, and prometheus actuator endpoints (management.endpoints.web.exposure.include=health,info,metrics,prometheus) and permits them without auth (SecurityConfig). In production, restrict actuator exposure further if needed via:

  • network policy / ingress rules, and/or

  • tightening management.endpoints.web.exposure.include and security rules.

Bootstrap admin provisioning

Configured via:

  • ft-configs.bootstrap.admin.username

  • ft-configs.bootstrap.admin.password

  • ft-configs.bootstrap.admin.email (optional)

  • ft-configs.bootstrap.admin.locale (optional)

See Environment variables for FT_CONFIGS_BOOTSTRAP_ADMIN_* defaults and examples.

Environment variables

Do not commit secrets (*_PASSWORD, JWT_SECRET) into Git. Use .env locally, and use Secret managers (Kubernetes Secrets, Vault, etc.) in shared environments.

HZ_MEMBERS must be reachable from inside the container/pod (Docker and Kubernetes networking apply).

A) Quick start (most common knobs)

Variable Required Default Description

SPRING_PROFILES_ACTIVE

Yes

local

Active Spring profile: local, mysql, or oracle. Controls which application-*.yml is loaded. Must be set explicitly in Docker and Kubernetes.

SERVER_PORT

No

8080

Primary server port. When SERVER_SSL_ENABLED=true, this becomes the HTTPS port.

SERVER_HTTP_PORT

No

8080

Plain HTTP port. In dual-mode (HTTP + HTTPS), set this to a different value than SERVER_PORT (e.g., 8080 for HTTP, 8443 for HTTPS).

HZ_MEMBERS

No

from Hazelcast client config

Comma-separated Hazelcast members (host:port). Required in Docker/Kubernetes. Default port 5701 is added automatically if missing.

CORS_ALLOWED_ORIGINS

No

http://localhost:9002

Comma-separated list of allowed CORS origins. Must match the URL the user sees in the browser address bar (where the frontend is loaded from), never the internal Docker service name. Scheme-sensitive: http:// and https:// are different origins — the UI is served on both HTTP (default port 3001) and HTTPS (default port 3443, both published by Docker), so list both. Examples: http://localhost:9002 (dev), http://<ui-host>:3001,https://<ui-host>:3443 (Docker, HTTP + HTTPS UI), https://management.example.com (production).

LOGGING_LEVEL_COM_FRIENDLY_FTCONFIGSSERVICE

No

INFO

Log level for the application package. Values: ERROR, WARN, INFO, DEBUG. Can also be changed at runtime via Actuator.

B) Database (MySQL profile: SPRING_PROFILES_ACTIVE=mysql)

Provide either MYSQL_JDBC_URL or the decomposed MYSQL_HOST/MYSQL_PORT/MYSQL_SCHEMA inputs.

Variable Required Default Description

MYSQL_JDBC_URL

No

derived if unset

Full MySQL JDBC URL. Recommended for Docker/Kubernetes to avoid host, port, and schema drift.

DB_HOST

No

localhost

Shared DB host fallback used by MySQL and Oracle when profile-specific host is not set.

MYSQL_HOST

No

${DB_HOST:localhost}

MySQL host used if MYSQL_JDBC_URL is not set.

MYSQL_PORT

No

3306

MySQL port used if MYSQL_JDBC_URL is not set.

MYSQL_SCHEMA

No

configs

MySQL schema used if MYSQL_JDBC_URL is not set.

MYSQL_USER

No

ftacs (template: ftacs_configs)

MySQL username for the service. The env templates in docker/ ship with ftacs_configs.

MYSQL_PASSWORD

No

ftacs (template: ftacs_configs)

MySQL password for the service. The env templates in docker/ ship with ftacs_configs. Treat as a secret.

MYSQL_DRIVER_CLASS_NAME

No

com.mysql.cj.jdbc.Driver

Override JDBC driver class if needed.

DB_MAX_POOL_SIZE

No

10

HikariCP max pool size.

DB_MIN_IDLE

No

5

HikariCP minimum idle connections.

DB_CONNECTION_TIMEOUT_MS

No

30000

HikariCP connection timeout in milliseconds.

When both *_JDBC_URL and decomposed variables are set, the explicit JDBC URL always takes precedence.

C) Database (Oracle profile: SPRING_PROFILES_ACTIVE=oracle)

Provide either ORACLE_JDBC_URL or the decomposed ORACLE_HOST/ORACLE_PORT/ORACLE_SERVICE (plus optional ORACLE_SCHEMA) inputs.

Variable Required Default Description

ORACLE_JDBC_URL

No

derived if unset

Full Oracle JDBC URL. Recommended for Docker/Kubernetes to avoid host, port, and service drift.

ORACLE_HOST

No

${DB_HOST:localhost}

Oracle host used if ORACLE_JDBC_URL is not set.

ORACLE_PORT

No

1521

Oracle port used if ORACLE_JDBC_URL is not set.

ORACLE_SERVICE

No

XEPDB1

Oracle service name used if ORACLE_JDBC_URL is not set.

ORACLE_SCHEMA

No

empty

Optional schema mapped to hibernate.default_schema.

ORACLE_USER

No

ftacs

Oracle username for the service.

ORACLE_PASSWORD

No

ftacs

Oracle password for the service. Treat as a secret.

ORACLE_DRIVER_CLASS_NAME

No

oracle.jdbc.OracleDriver

Override Oracle JDBC driver class if needed.

D) Hazelcast / cache

Variable Required Default Description

CACHE_CONFIG_PATH

No

classpath:

Base path for Hazelcast config files. hazelcast-client.yaml is resolved relative to this path.

CACHE_IS_SERVER

No

false

When true, starts an embedded Hazelcast member from ${cache-config.path}hazelcast.yaml. Not used in production.

FT_CONFIGS_ACS_EXCLUSION_MODELS_CACHE_NAME

No

qoeProductClassGroupCache

Name of the Hazelcast cache from which ACS publishes product-class groups, consumed by the dataStoreExclusionModels dropdown. Must match the name ACS publishes to; the default matches the standard ACS deployment.

E) Auth / JWT & cookies

Variable Required Default Description

JWT_SECRET

No

defined in profile

Base64-encoded HMAC-SHA256 signing key. Must decode to at least 32 bytes (256-bit) or startup fails. Generate with openssl rand -base64 32. Must be unique per environment. Never commit to Git.

JWT_EXPIRATION

No

86400000

Access token expiration in milliseconds.

JWT_REFRESH_TOKEN_EXPIRATION

No

604800000

Refresh token expiration in milliseconds.

COOKIE_SECURE

No

true (template: false)

Set true when HTTPS is used end-to-end or via a trusted TLS-terminating proxy. The env templates ship with false for local development.

COOKIE_DOMAIN

No

empty

Optional domain for cross-subdomain cookie sharing.

Mail

Variable Required Default Description

MAIL_MODE

No

AUTO

Email delivery mode (case-insensitive; blank or unknown falls back to AUTO with a warning log). The supported values are AUTO and OFFLINE. AUTO infers the mode from SMTP config: it is treated as OFFLINE when MAIL_HOST, MAIL_USERNAME, or MAIL_PASSWORD are not all set (non-blank); when they are all set it attempts email, but if the SMTP server is unreachable at runtime it degrades to offline behaviour. OFFLINE never sends email. In offline mode (configured or degraded at runtime), create-user and reset-password return the temporary password in the API response (passwordDelivery=RETURNED) instead of emailing it, and user-deletion requests skip OTP (returning otpRequired=false); the account is deleted in the confirm step, called without an OTP.

MAIL_HOST

No

smtp.gmail.com

SMTP host used for registration and deletion flows. Under MAIL_MODE=AUTO, leaving this blank (together with the credentials) selects offline mode.

MAIL_PORT

No

587

SMTP port.

MAIL_USERNAME

No

SMTP username. Under MAIL_MODE=AUTO, leaving this blank selects offline mode (no email is sent; secrets are returned in API responses). The local profile uses an empty default (${MAIL_USERNAME:}).

MAIL_PASSWORD

No

SMTP password. Treat as a secret. Under MAIL_MODE=AUTO, leaving this blank selects offline mode. The local profile uses an empty default (${MAIL_PASSWORD:}).

MAIL_PROTOCOL

No

smtp

Usually smtp.

MAIL_SMTP_AUTH

No

true

SMTP authentication toggle.

MAIL_SMTP_STARTTLS

No

true

STARTTLS toggle.

MAIL_FROM

No

no-reply@friendly.local

From address used in sent emails.

MAIL_LOGIN_URL

No

empty

URL for the "Sign In" call-to-action button in emails. Must start with http:// or https://. If blank or non-HTTP, the CTA button is replaced by a generic text hint. Example: https://management.example.com/configs-service.

The MAIL_FROM_NAME variable has been removed. The sender display name is now localized via the mail.brand message key (mail_messages*.properties), returning "Configuration Center" (EN) or the localized equivalent for other locales.

Audit

Variable Required Default Description

AUDIT_RETENTION_DAYS

No

30

Number of days to retain audit events. Minimum 3, maximum 90. Set to 0 to disable retention. Values outside range are clamped with a warning.

AUDIT_REDACTION_FIELDS

No

empty

Comma-separated list of additional sensitive field names to redact in audit snapshots and change records. Added on top of the 18 built-in defaults (password, token, secret, apiKey, etc.).

Bootstrap admin (first install)

Variable Required Default Description

FT_CONFIGS_BOOTSTRAP_ADMIN_USERNAME

No

admin

Username for first startup when no admin exists.

FT_CONFIGS_BOOTSTRAP_ADMIN_PASSWORD

Yes (first startup)

empty

Password for bootstrap admin. Must be set on first startup or the admin account will not be created. Rotate immediately after bootstrap via /auth/first-login. Treat as a secret.

FT_CONFIGS_BOOTSTRAP_ADMIN_EMAIL

No

empty

Optional email assigned to bootstrap admin.

FT_CONFIGS_BOOTSTRAP_ADMIN_LOCALE

No

empty

Optional locale for bootstrap admin.

JVM / container runtime

Variable Required Default Description

JAVA_OPTS

No

set in Docker image

JVM options passed by docker-entrypoint.sh. Add only needed flags.

TZ

No

UTC

Container timezone.