Client Service Installation and Configuration (client-service)¶
The client-service manages organizational identity, user sessions, account balances, admin onboarding, and reporting rollups.
The deployed process needs PostgreSQL, Redis, and Kafka. When using the development settings, Eureka must also be running. Use port 9014 for development.
Runtime and Service Metadata¶
These settings control how the process starts, how it identifies itself in logs/service discovery, and how it shuts down during deployments.
| Property | Value / Default | Env Variable | Description |
|---|---|---|---|
server.port |
0 base, 9014 dev |
SERVER_PORT |
HTTP port. Base uses random port; dev pins 9014. |
server.shutdown |
graceful |
SERVER_SHUTDOWN |
Shutdown mode. Allowed: graceful waits for in-flight requests to finish; immediate stops without waiting. |
log.dir |
client-service |
LOG_DIR |
Log directory identifier. |
spring.profiles.active |
dev |
SPRING_PROFILES_ACTIVE |
Active Spring profile. Common values: dev for local development, k8s when a Kubernetes profile exists, or any custom profile with a matching application-<profile>.yml. |
spring.application.name |
client-service |
SPRING_APPLICATION_NAME |
Service name used by Spring and discovery. |
spring.lifecycle.timeout-per-shutdown-phase |
90s |
SPRING_LIFECYCLE_TIMEOUT_PER_SHUTDOWN_PHASE |
Maximum graceful shutdown phase duration. |
spring.main.allow-bean-definition-overriding |
true |
SPRING_MAIN_ALLOW_BEAN_DEFINITION_OVERRIDING |
Allows duplicate bean names to be replaced at startup. Allowed: true permits overrides; false fails startup on duplicate bean definitions. |
info.app.name |
Customer Service |
— | Human-readable service name shown by the actuator info endpoint. |
info.app.description |
This service is responsible for Customer. |
— | Human-readable service purpose shown by the actuator info endpoint. |
info.app.version |
1.0 |
— | Application version shown by the actuator info endpoint. |
Actuator, Tracing, and Logging¶
Actuator is Spring Boot's operational endpoint layer. It exposes health, metrics, environment, and diagnostic endpoints. Tracing adds request correlation identifiers so operators can follow one request across logs and services.
| Property | Value / Default | Env Variable | Description |
|---|---|---|---|
management.endpoints.web.exposure.include |
* |
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE |
Actuator endpoints exposed over HTTP. Allowed examples: * exposes all; health,info exposes only health and info. Restrict this in production if actuator is reachable outside the private network. |
management.info.env.enabled |
true |
MANAGEMENT_INFO_ENV_ENABLED |
Environment-backed actuator info. Allowed: true includes configured info values; false hides environment-backed info. |
management.endpoint.health.probes.enabled |
true |
MANAGEMENT_ENDPOINT_HEALTH_PROBES_ENABLED |
Enables Kubernetes-style health probes. Allowed: true creates liveness/readiness health groups; false exposes only standard health behavior. |
management.tracing.sampling.probability |
1.0 |
MANAGEMENT_TRACING_SAMPLING_PROBABILITY |
Fraction of requests sampled for tracing. Allowed range: 0.0 samples none, 1.0 samples all, values between sample a percentage. |
logging.pattern.level |
%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-},%X{correlationId:-}] |
LOGGING_PATTERN_LEVEL |
Log level pattern with trace and correlation IDs. |
logging.config |
classpath:log/logback-dev.xml dev |
LOGGING_CONFIG |
Logback configuration used in dev. |
spring.sleuth.sampler.probability |
1.0 dev |
SPRING_SLEUTH_SAMPLER_PROBABILITY |
Sleuth tracing sample rate in dev. Allowed range: 0.0 to 1.0. |
Eureka Discovery¶
Eureka is the service registry. This service registers itself there so gateway and other services can discover its network location without hard-coding hostnames.
| Property | Value / Default | Env Variable | Description |
|---|---|---|---|
eureka.client.service-url.defaultZone |
http://localhost:8761/eureka/ |
EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE |
Eureka registry endpoint. |
eureka.instance.prefer-ip-address |
true |
EUREKA_INSTANCE_PREFER_IP_ADDRESS |
Registration address type. Allowed: true registers the instance IP address; false registers hostname. |
JPA, SQL Init, and Flyway¶
JPA/Hibernate maps Java entities to database tables. SQL init runs startup SQL scripts. Flyway runs versioned database migrations before the application uses the schema.
| Property | Value / Default | Env Variable | Description |
|---|---|---|---|
spring.jpa.database-platform |
postgres base |
— | Base JPA database platform. |
spring.jpa.show-sql |
false |
— | SQL statement logging. Allowed: true prints SQL to logs; false keeps logs quieter. |
spring.jpa.open-in-view |
false |
— | Keeps database session open during web response rendering. Allowed: true permits lazy loading during response rendering; false closes sessions at transaction boundaries. Services should normally keep this false. |
spring.jpa.properties.hibernate.dialect |
org.hibernate.dialect.PostgreSQLDialect |
— | Hibernate dialect. |
spring.jpa.hibernate.ddl-auto |
validate dev |
— | Hibernate schema action. Allowed: validate checks schema only; none does nothing; update changes schema automatically; create recreates schema; create-drop recreates then drops on shutdown. Use validate with Flyway-managed schemas. |
spring.sql.init.mode |
always |
SPRING_SQL_INIT_MODE |
SQL script execution mode. Allowed: always runs scripts for any database; embedded runs only for embedded databases; never disables SQL init. |
spring.sql.init.continue-on-error |
true |
SPRING_SQL_INIT_CONTINUE_ON_ERROR |
SQL init error handling. Allowed: true continues after script errors; false fails startup on script errors. |
spring.flyway.enabled |
true |
— | Flyway migration runner. Allowed: true runs migrations at startup; false skips migrations. |
spring.flyway.baseline-on-migrate |
true |
— | Baselines a non-empty schema without Flyway history. Allowed: true creates a baseline; false fails if the schema is non-empty and unmanaged. |
spring.flyway.baseline-version |
0 |
— | Baseline version. |
spring.flyway.schemas |
client_service |
— | Flyway migration schema. |
spring.flyway.default-schema |
client_service |
— | Flyway default schema. |
spring.flyway.url |
jdbc:postgresql://localhost:5432/sms_gateway?currentSchema=client_service |
DB_URL |
Flyway JDBC URL. |
spring.flyway.user |
appadmin |
DB_USERNAME |
Flyway database user. |
spring.flyway.password |
Required | DB_PASSWORD |
Flyway database password. |
Master Datasource¶
The master datasource is the read/write PostgreSQL connection pool used for commands that change client, user, balance, and reporting state.
| Property | Value / Default | Env Variable | Description |
|---|---|---|---|
datasource.master.url |
jdbc:postgresql://localhost:5432/sms_gateway?currentSchema=client_service |
DB_URL |
Master JDBC URL. |
datasource.master.username |
appadmin |
DB_USERNAME |
Master database username. |
datasource.master.password |
Required | DB_PASSWORD |
Master database password. |
datasource.master.maximum-pool-size |
10 |
— | Maximum master pool size. |
datasource.master.minimum-idle |
2 |
— | Minimum idle master connections. |
datasource.master.connection-timeout |
30000 |
— | Connection timeout in milliseconds. |
datasource.master.idle-timeout |
600000 |
— | Idle timeout in milliseconds. |
datasource.master.max-lifetime |
1800000 |
— | Maximum connection lifetime in milliseconds. |
datasource.master.pool-name |
ClientMasterHikariCP |
— | Master Hikari pool name. |
datasource.master.validation-timeout |
5000 |
— | Validation timeout in milliseconds. |
datasource.master.leak-detection-threshold |
60000 |
— | Leak detection threshold in milliseconds. |
Slave Datasource¶
The slave datasource is intended for read-heavy operations. If DB_SLAVE_URL is not set, it falls back to the master database URL.
| Property | Value / Default | Env Variable | Description |
|---|---|---|---|
datasource.slave.url |
Falls back to DB_URL / local client schema URL |
DB_SLAVE_URL |
Slave JDBC URL. |
datasource.slave.username |
appadmin |
DB_USERNAME |
Slave database username. |
datasource.slave.password |
Required | DB_PASSWORD |
Slave database password. |
datasource.slave.maximum-pool-size |
2 |
— | Maximum slave pool size. |
datasource.slave.minimum-idle |
1 |
— | Minimum idle slave connections. |
datasource.slave.connection-timeout |
30000 |
— | Connection timeout in milliseconds. |
datasource.slave.idle-timeout |
600000 |
— | Idle timeout in milliseconds. |
datasource.slave.max-lifetime |
1800000 |
— | Maximum connection lifetime in milliseconds. |
datasource.slave.pool-name |
ClientSlaveHikariCP |
— | Slave Hikari pool name. |
datasource.slave.validation-timeout |
5000 |
— | Validation timeout in milliseconds. |
datasource.slave.leak-detection-threshold |
60000 |
— | Leak detection threshold in milliseconds. |
Redis¶
Redis stores token/session data and fast lookup keys. Pool settings limit how many Redis connections the service keeps open.
| Property | Value / Default | Env Variable | Description |
|---|---|---|---|
redis.host |
localhost |
REDIS_HOST |
Redis host. |
redis.port |
6379 |
REDIS_PORT |
Redis port. |
redis.password |
Empty | REDIS_PASSWORD |
Redis password. |
redis.database.index |
5 |
REDIS_DATABASE_INDEX |
Redis logical database. |
redis.pool.max.connection |
30 |
— | Maximum Redis pool size. |
redis.pool.max.idle.connection |
10 |
— | Maximum idle Redis connections. |
redis.pool.min.idle.connection |
0 |
— | Minimum idle Redis connections. |
redis.key.prefix.accesstoken |
client:accesstoken: |
— | Redis access token key prefix. |
redis.key.prefix.idtoken |
client:idtoken: |
— | Redis identity token key prefix. |
Token keys used by the service
The service does not currently use the two token prefix settings above. It stores access tokens as sms:token:{rawJwt} and refresh tokens as sms:refresh:{sha256(refreshToken)}. Changing the prefix settings does not rename existing Redis keys or move active sessions.
JWT and Admin Security¶
JWT settings control user access-token and refresh-token lifetimes. admin.api.key protects privileged internal/admin endpoints.
| Property | Value / Default | Env Variable | Description |
|---|---|---|---|
jwt.secret.key |
Required | JWT_SECRET_KEY |
JWT signing key. Must match gateway validation key. |
jwt.expiry-ms |
3600000 base, 86400000 dev |
JWT_EXPIRY_MS |
Access token lifetime in milliseconds. Dev overrides the base value. |
jwt.refresh-expiry-ms |
604800000 |
JWT_REFRESH_EXPIRY_MS |
Refresh token lifetime in milliseconds. |
admin.api.key |
Required | ADMIN_API_KEY |
Shared admin key for admin/internal endpoints. |
JWT_SECRET_KEY must decode from Base64 to suitable HS512 key material and must match gateway-service. A mismatch allows login but causes the gateway to reject the returned access token. Startup fails when ADMIN_API_KEY is blank, shorter than 32 characters, or equals CHANGE_ME_IN_PRODUCTION.
Kafka and Reporting¶
Kafka carries asynchronous reporting events. The reporting consumer reads events and updates client-service reporting tables.
| Property | Value / Default | Env Variable | Description |
|---|---|---|---|
spring.kafka.bootstrap-servers |
localhost:9092 |
KAFKA_BOOTSTRAP_SERVERS |
Kafka bootstrap servers. |
spring.kafka.consumer.group-id |
client-service-reporting |
REPORTING_CONSUMER_GROUP |
Reporting consumer group ID. |
spring.kafka.consumer.auto-offset-reset |
earliest |
— | Offset reset policy when no committed offset exists. Allowed: earliest starts from the oldest retained message; latest starts from new messages only; none fails if no offset exists. |
spring.kafka.consumer.key-deserializer |
org.apache.kafka.common.serialization.StringDeserializer |
— | Consumer key deserializer. |
spring.kafka.consumer.value-deserializer |
org.apache.kafka.common.serialization.StringDeserializer |
— | Consumer value deserializer. |
spring.kafka.producer.key-serializer |
org.apache.kafka.common.serialization.StringSerializer |
— | Producer key serializer. |
spring.kafka.producer.value-serializer |
org.apache.kafka.common.serialization.StringSerializer |
— | Producer value serializer. |
reporting.topic |
sms.reporting |
REPORTING_TOPIC |
Reporting Kafka topic. |
reporting.consumer.enabled |
true |
REPORTING_CONSUMER_ENABLED |
Reporting event consumption. Allowed: true consumes reporting events in this service; false disables this consumer on this node. |
Malformed reporting events and known events that cannot be deserialized are routed to sms.reporting.dlt. Transient database failures retry with exponential backoff before the same destination. The service has no DLT replay consumer, so retain and monitor this topic.
Channel Failure Alerts¶
The reporting consumer counts unique terminal-failure recipient IDs in a Redis rolling window. Reaching the threshold creates an alert plus transactional outbox row. Configure either a webhook or Kafka delivery.
| Property | Default | Env Variable | Description |
|---|---|---|---|
channel-alert.enabled |
true |
CHANNEL_ALERT_ENABLED |
Enables rolling-window evaluation. Redis failures are logged and do not fail reporting ingestion. |
channel-alert.threshold |
100 |
CHANNEL_ALERT_THRESHOLD |
Unique failed recipients required for an alert. Use a positive integer. |
channel-alert.window-seconds |
300 |
CHANNEL_ALERT_WINDOW_SECONDS |
Rolling Redis window. |
channel-alert.cooldown-seconds |
900 |
CHANNEL_ALERT_COOLDOWN_SECONDS |
Minimum time between alerts for one client/channel. |
channel-alert.key-prefix |
channel-failure:v1: |
CHANNEL_ALERT_KEY_PREFIX |
Redis key namespace. |
channel-alert.ttl-grace-seconds |
60 |
CHANNEL_ALERT_TTL_GRACE_SECONDS |
Extra TTL after the window. |
channel-alert.topic |
client.channel-alerts |
CHANNEL_ALERT_TOPIC |
Kafka delivery destination when webhook URL is empty. |
channel-alert.webhook-url |
Empty | CHANNEL_ALERT_WEBHOOK_URL |
Alert receiver. Any nonblank URL selects webhook instead of Kafka. |
channel-alert.webhook-api-key |
Empty | CHANNEL_ALERT_WEBHOOK_API_KEY |
Optional value sent as X-Api-Key; store as a secret. |
channel-alert.webhook-timeout-seconds |
5 |
CHANNEL_ALERT_WEBHOOK_TIMEOUT_SECONDS |
HTTP connect and read timeout. |
channel-alert.advisory-lock-timeout-seconds |
2 |
CHANNEL_ALERT_LOCK_TIMEOUT_SECONDS |
Intended alert-lock timeout setting. |
Terminal failures counted are FAILED, REJECTED, EXPIRED, UNDELIVERED, INVALID_MSISDN, DND, and NOT_AVAILABLE.
Alert Outbox Publisher and Recovery¶
| Property | Default | Env Variable | Description |
|---|---|---|---|
client.outbox.publisher.enabled |
true |
CLIENT_OUTBOX_PUBLISHER_ENABLED |
Creates the publisher bean. Disable on nodes that must only ingest reports. |
client.outbox.publisher.poll-ms |
1000 |
CLIENT_OUTBOX_POLL_MS |
Fixed delay after a publisher run completes. |
client.outbox.publisher.batch-size |
50 |
CLIENT_OUTBOX_BATCH_SIZE |
Rows claimed per run using SKIP LOCKED. |
client.outbox.publisher.send-timeout-ms |
5000 |
CLIENT_OUTBOX_SEND_TIMEOUT_MS |
Common deadline for the batch's Kafka sends. Webhook calls use the channel-alert timeout. |
client.outbox.recovery.enabled |
true |
CLIENT_OUTBOX_RECOVERY_ENABLED |
Reopens eligible failed rows. |
client.outbox.recovery.poll-ms |
60000 |
CLIENT_OUTBOX_RECOVERY_POLL_MS |
Recovery scan interval (code default; not explicitly present in base YAML). |
client.outbox.recovery.cooldown-minutes |
5 |
CLIENT_OUTBOX_RECOVERY_COOLDOWN_MINUTES |
Delay after failure before reopening (code default). |
client.outbox.recovery.max-rounds |
3 |
CLIENT_OUTBOX_RECOVERY_MAX_ROUNDS |
Maximum reopen cycles before manual intervention (code default). |
client.outbox.recovery.batch-size |
100 |
CLIENT_OUTBOX_RECOVERY_BATCH_SIZE |
Failed rows considered per scan (code default). |
If multiple instances run, database row claiming prevents duplicate publisher work. Alert threshold coordination uses PostgreSQL advisory transaction locks. Five failed delivery attempts is currently hard-coded before an event is parked; it is not a configuration property.