Skip to content

Installation and Deployment

You can run this project in several ways: as a complete Docker Compose setup on one host, as application containers connected to existing infrastructure, as separate containers, or directly from JAR files. Choose the option that fits your environment. In every setup, keep internal services private and protect secrets.

Choose a deployment mode

Mode Guide/file Best suited for
Full local Compose Docker deployment, docker-compose.yml Development, integration testing, or a complete setup on one host
Production Compose docker-compose.yml + docker-compose.prod.yml A safer starting point for production on one host, with private infrastructure ports and resource and log limits
Infrastructure on the host Base + docker-compose.host-infra.yml Application containers that connect to PostgreSQL, Redis, and Kafka running on the same host
External infrastructure Base + docker-compose.external.yml Application containers that connect to infrastructure outside the Compose setup
End-to-end tests Base + docker-compose.e2e.yml Integration tests with a mock provider and Newman; do not use this setup in production
Direct JARs Bare-metal deployment Local debugging, deployments on a VM or with systemd, or another process manager

The external infrastructure file contains an IP address for a specific environment. Review and replace it before use. For a new environment, use a configurable value or a standard DNS name instead.

Requirements

Requirement Version used by this project Notes
Java 17 Required to compile and run Spring Boot services
Maven Wrapper downloads 3.8.6 Run sh mvnw, or run chmod +x mvnw once and then use ./mvnw; Docker builds currently use Maven 3.8.4 images
Docker Current Engine with Compose plugin The production file uses Compose tags such as !reset and !override; run docker compose config --quiet before deployment to check that your version supports them
PostgreSQL Base Compose uses 16 Alpine One sms_gateway database with client_service, sms_router, sms_aggregator schemas
Redis Base Compose uses 7 Alpine The client and gateway use logical database 5; channel alerts also use Redis
Kafka Base Compose uses Confluent cp-kafka:7.5.0 in KRaft mode In production, use multiple brokers with persistent storage instead of the local single-broker defaults
Memory At least 8 GiB for the full local setup The production file limits service memory; the amount you need depends on campaign, report, and provider traffic

These are the versions used or tested by this repository. Newer versions are not guaranteed to work.

Ports

Component Port in a container or direct run Available from the host in base Compose Production Compose
Gateway 8000 8000 Remains available from the host; put a TLS reverse proxy or load balancer in front of it
Discovery/Eureka 8761 8761 Not available from the host
Client service 9014 Available only inside the Docker network Internal only
SMS router 9015 Available only inside the Docker network Internal only
Aggregator integration 9016 Available only inside the Docker network Internal only
PostgreSQL 5432 POSTGRES_PORT, default 5432 Not available from the host
Redis 6379 REDIS_PORT, default 6379 Not available from the host
Kafka broker/controller 9092/9093 Both available from the host Not available from the host

The gateway development profile uses port 8081, but Compose and the documented external URL use port 8000. When you run the gateway directly, set SERVER_PORT=8000 to use the same URL.

Built JAR files

After running sh mvnw clean package, or ./mvnw clean package if you made the wrapper executable, the JAR files are located at:

Service JAR path
Discovery services/discovery-service/service-jars/discovery-service.jar
Gateway services/gateway-service/service-jars/gateway-service.jar
Client services/all-service-jars/client-service.jar
SMS router services/all-service-jars/sms-router-service.jar
Aggregator integration services/all-service-jars/aggregator-integration-service.jar

Startup order

flowchart TD
    Infra[PostgreSQL + Redis + Kafka] --> Discovery[discovery-service]
    Infra --> Client[client-service]
    Discovery --> Client
    Infra --> Router[sms-router-service]
    Discovery --> Router
    Client --> Router
    Infra --> Aggregator[aggregator-integration-service]
    Discovery --> Aggregator
    Router --> Aggregator
    Redis[(Redis)] --> Gateway[gateway-service]
    Discovery --> Gateway
    Client --> Gateway
    Router --> Gateway
Hold "Ctrl" to enable pan & zoom

Recommended order:

  1. Start PostgreSQL, Redis, and Kafka and wait until the services can connect to them.
  2. Start the discovery service and wait until it is healthy.
  3. Start the client service. It updates its database with Flyway and registers with discovery.
  4. Start the router. It also updates its database and registers with discovery.
  5. Start the aggregator after the router tables have been created. The aggregator uses selected tables in the sms_router schema.
  6. Start the gateway after discovery can find the services it routes requests to.

Services retry failed connections, so they may not stop immediately when a dependency is unavailable. Even so, do not send traffic to a service until it is ready and registered. The base Compose file waits for its required services to become healthy.

Required secrets and shared settings

Value Consumers Requirement
POSTGRES_PASSWORD / DB_PASSWORD PostgreSQL and database services Replace the example values and keep the passwords in a secret store
JWT_SECRET_KEY Client issuer and gateway validator Same Base64-encoded value; openssl rand -base64 64 is the provided generation pattern
ADMIN_API_KEY Internal Operator, router, and aggregator service Same value; at least 32 characters; openssl rand -hex 32 is suitable
JASYPT_ENCRYPTOR_PASSWORD Router and aggregator Both services must use the same master password so they can encrypt and decrypt stored carrier credentials. Generate a strong value with openssl rand -base64 32
MNPSP_AGGREGATOR_API_KEY Aggregator API key for the Infozillion deployment

Do not commit .env.prod, copies of service secrets, provider credentials, JWTs, or generated database passwords. Use .env.example only as a template. The root .env is intended for development and is not safe for production as-is.

Database preparation

Base Compose mounts scripts/init-db.sql on first PostgreSQL initialization. It creates:

  • client_service
  • sms_router
  • sms_aggregator

Each service then uses Flyway to update its own schema. The aggregator also needs read and write access to specific router tables used for routing, completing message batches and recipients, and adding reporting events. A single local database user already has this access when it owns every schema. In production, give each database user only the permissions listed in the aggregator architecture.

PostgreSQL runs initialization scripts only when its data directory is new and empty. Changing scripts/init-db.sql does not run it again for an existing volume.

Check that services are ready

From the trusted network, check:

curl --fail http://localhost:8761/actuator/health
curl --fail http://localhost:9014/actuator/health/readiness
curl --fail http://localhost:9015/actuator/health/readiness
curl --fail http://localhost:9016/actuator/health/readiness
curl --fail http://localhost:8000/actuator/health/liveness

In the production Compose setup, only the gateway is available from the host. Check the internal services with docker compose exec, monitoring inside the container network, or an approved monitoring agent.

A successful liveness check only shows that the process is running. It does not confirm that Kafka messages are being processed, campaigns are being scheduled, providers are delivering messages, delivery reports are current, reports are updated, or refunds are complete. Monitor the business signals described in Platform Reliability.

Service configuration guides