5.2 KiB
Configuration reference
The notification delivery platform binds under ca-skeleton.notification.platform. The tree lives in
src/app-bootstrap/src/main/resources/application.yml, disabled by default, and every value carries
an inline default so a deployment that leaves the platform off supplies nothing.
Until 2026-08-15 this page named properties the binding did not have — max-retry-concurrency,
scheduler-poll-interval, callback-worker-concurrency — and omitted three it did. There was no
tree in application.yml at all, so the only way to configure the platform was to guess environment
variable names from Boot's relaxed binding. ./gradlew verifyNotificationConfiguration now fails
when this page, the YAML tree and docs/registries/env-keys.yaml disagree.
Master switch
| Property | Environment variable | Default | Meaning |
|---|---|---|---|
enabled |
APP_NOTIFICATION_PLATFORM_ENABLED |
false |
Binds nothing at all while false: no runtime, no schema check, no scheduler thread, no secret required |
mode |
APP_NOTIFICATION_PLATFORM_MODE |
SERVING |
SERVING refuses to start without a working provider; INGEST_ONLY stores requests and does not dispatch |
Dispatch
| Property | Environment variable | Default | Bound |
|---|---|---|---|
dispatch.claim-batch-size |
APP_NOTIFICATION_PLATFORM_CLAIM_BATCH_SIZE |
50 |
1..1000 |
dispatch.lease-duration |
APP_NOTIFICATION_PLATFORM_LEASE_DURATION |
2m |
positive, finite |
dispatch.poll-interval |
APP_NOTIFICATION_PLATFORM_POLL_INTERVAL |
1s |
positive, finite |
dispatch.max-global-concurrency |
APP_NOTIFICATION_PLATFORM_MAX_CONCURRENCY |
64 |
positive |
dispatch.max-additional-attempts |
APP_NOTIFICATION_PLATFORM_MAX_ADDITIONAL_ATTEMPTS |
4 |
non-negative |
dispatch.max-queue-age |
APP_NOTIFICATION_PLATFORM_MAX_QUEUE_AGE |
24h |
positive |
dispatch.allow-ambiguous-fallback |
APP_NOTIFICATION_PLATFORM_ALLOW_AMBIGUOUS_FALLBACK |
false |
boolean |
Every value is bounded. "Unlimited" is not an accepted configuration.
The lease must outlast a provider call plus its timeout. Below that, a delivery a live worker is still waiting on gets claimed by a second worker, and the recipient receives the notification twice.
Callbacks
| Property | Environment variable | Default | Bound |
|---|---|---|---|
callbacks.enabled |
APP_NOTIFICATION_PLATFORM_CALLBACKS_ENABLED |
false |
boolean |
callbacks.max-body-bytes |
APP_NOTIFICATION_PLATFORM_CALLBACK_MAX_BODY_BYTES |
65508 |
1..65508 |
callbacks.replay-skew |
APP_NOTIFICATION_PLATFORM_CALLBACK_REPLAY_SKEW |
5m |
positive |
65508 is not a round number by accident: it is the ciphertext column's 65536 bytes minus the AES-GCM
nonce and tag. A larger configured value would pass every check above the database and fail the
CHECK constraint after the callback had already been acknowledged to the provider.
Provider profiles
Profiles are a map under providers, keyed by profile id. There are no environment variables for
them, because the keys are deployment-chosen; supply them as YAML or as
CA_SKELETON_NOTIFICATION_PLATFORM_PROVIDERS_<ID>_<FIELD>.
| Field | Meaning |
|---|---|
type |
APNS, FCM, SES, SMTP, TWILIO, WEB_PUSH, WEBHOOK — a closed enum, so an unknown value fails binding rather than assembling into nothing |
enabled |
A disabled profile is bound and validated but contributes no runtime |
primary-for-channel |
Exactly one primary per channel |
environment |
Required when enabled |
credential-profile |
Resolved through SecretMaterialProvider; never an inline secret |
topic |
APNs bundle id |
vapid-public-key |
Web Push application server key |
callback-signing-secret-ref |
Reference, not material |
timeout |
Positive and finite |
max-concurrency |
Positive |
rate-per-second |
Positive |
A profile pins provider type, environment, credential profile, timeouts, concurrency and rate limit. Sender identity and credential profile are separate concerns.
Startup failures
Startup fails rather than degrading when:
- a payload or queue setting is unbounded
- a timeout is negative
- a TTL-required profile has no expiry source
- a callback signing secret is missing
- a production profile enables trust-all
- an APNs profile is missing its environment or topic
- a Web Push profile is missing its VAPID key
- two provider profiles share an id
- a route points only at disabled providers
modeisSERVINGand no provider profile is enabled- the notification schema stream is not applied and promoted
Secrets
All key material arrives through SecretMaterialProvider. Nothing is read from source, from a
committed file, or from a plaintext log. Contact point encryption and lookup HMAC keys must be
distinct, and the encryption key must be exactly 256 bits.
Readiness
The platform contributes a notifications actuator endpoint and a health indicator. It reports DOWN
when a provider's credentials were rejected, when a configured provider has no channel route, and
when the measured backlog, stuck-lease count, projection lag or reconciliation lag passes the
thresholds in NotificationServingThresholds. See operations.md.