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
Recommended order:
- Start PostgreSQL, Redis, and Kafka and wait until the services can connect to them.
- Start the discovery service and wait until it is healthy.
- Start the client service. It updates its database with Flyway and registers with discovery.
- Start the router. It also updates its database and registers with discovery.
- Start the aggregator after the router tables have been created. The aggregator uses selected tables in the
sms_routerschema. - 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_servicesms_routersms_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.