This architecture has been fully implemented in the SalvationArmyBackendMicroservice repository. All 14 business services, infrastructure, and deployment configurations are built and ready for containerised deployment.
228+ source files across 14 services (Java, Python, Node.js)
25 Docker containers orchestrated via Docker Compose on a single salt-network bridge
Shared database — all Spring Boot services connect to PostgreSQL 17 (salvation)
Kafka event-driven messaging across 17 topics for asynchronous communication
All containers configured with East Africa Time (Africa/Nairobi, UTC+3)
The monolithic application (Phases 1–10) remains the production system. The Strangler Fig pattern in the API Gateway routes traffic to the monolith as a fallback while services are gradually activated.
This document defines the architecture for decomposing the E-Learning monolithic Spring Boot application into a microservice ecosystem. The decomposition preserves all existing functionality while enabling independent scaling, deployment, and technology diversity.
Key Architectural Decisions
Decision
Choice
Rationale
Database Strategy
Shared PostgreSQL 17
Existing production data in salvation DB; avoids complex data migration. Services share the database with schema-level isolation.
Message Broker
Apache Kafka + Zookeeper
Event-driven decoupling between services; supports async notifications, audit trails, and eventual consistency.
Authentication
Keycloak
Replaces custom JWT implementation; provides SSO, role management, OAuth2/OIDC, and admin console out-of-the-box.
Service Discovery
Netflix Eureka
Spring Cloud native; automatic registration/deregistration with health checks.
API Gateway
Spring Cloud Gateway
Route management, rate limiting, circuit breaking, JWT validation — all Spring ecosystem native.
WebSocket-native runtime; MongoDB for flexible chat document storage.
Containerization
Docker + Docker Compose
Every component runs in its own container; reproducible across dev, staging, and production.
Constraint: The production database salvation (PostgreSQL 17) MUST remain intact. All services connect to the same database. No table dropping, renaming, or schema-breaking changes.
2. Architecture Overview
2.1 High-Level Architecture Diagram
Figure 1: Microservice Architecture — 14 business services + 3 infrastructure services, event-driven via Kafka
2.2 Infrastructure Components
Component
Technology
Port
Container Name
Purpose
GATEWAY API Gateway
Spring Cloud Gateway
8080
salt-gateway
Single entry point, routing, rate limiting, JWT validation
AUTH Keycloak
Keycloak 24+
8180
salt-keycloak
OAuth2/OIDC identity provider, SSO, role management
DISCOVERY Eureka
Spring Cloud Netflix Eureka
8761
salt-eureka
Service registration & discovery
BROKER Kafka
Apache Kafka 3.7+
9092
salt-kafka
Event-driven messaging between services
ZK Zookeeper
Apache Zookeeper
2181
salt-zookeeper
Kafka cluster coordination
DB PostgreSQL
PostgreSQL 17
5432
salt-postgres
Shared database (salvation)
CACHE Redis
Redis 7 Alpine
6379
salt-redis
Caching, sessions, Keycloak sessions
STORE MinIO
MinIO Latest
9000/9001
salt-minio
S3-compatible file storage
CHAT-DB MongoDB
MongoDB 7
27017
salt-mongodb
Chat message storage (document DB)
AUTH-DB Keycloak DB
PostgreSQL 17
5433
salt-keycloak-db
Keycloak-specific database (separate from salvation)
2.3 Communication Patterns
Pattern
Use Case
Technology
Synchronous (REST)
Client → Gateway → Service (CRUD operations)
HTTP/JSON via Spring Cloud Gateway
Asynchronous (Events)
Service → Kafka → Service (notifications, audit, sync)
Apache Kafka topics
WebSocket
Real-time chat between users
Socket.IO (Node.js Chat Service)
Service Discovery
Services locating each other dynamically
Netflix Eureka (heartbeat-based)
Token-Based Auth
JWT bearer tokens on all requests
Keycloak-issued OIDC tokens
3. Service Catalog
3.1 API Gateway INFRASTRUCTURE
Technology
Spring Cloud Gateway (Java 17)
Container
salt-gateway
Port
8080 (internal), exposed via Nginx on 443
Responsibilities
Route requests to services, validate JWT tokens against Keycloak, rate limiting, circuit breaking, CORS
Existing users in tbl_sys_users will be migrated to Keycloak via a custom User Federation SPI or batch import script. BCrypt password hashes are compatible with Keycloak's hash provider.
Backward Compatibility: During the transition period, the Gateway supports both legacy JWT tokens (from tbl_sys_settings signing key) and Keycloak-issued OIDC tokens.
3.3 Service Discovery (Eureka) INFRASTRUCTURE
Technology
Spring Cloud Netflix Eureka Server
Container
salt-eureka
Port
8761
Dashboard
http://localhost:8761
All Spring Boot services register with Eureka on startup. The API Gateway uses lb://service-name URIs for load-balanced routing. Health checks run every 30 seconds.
total = (AVG(assignments) * assignment_weight_pct / 100)
+ (exam_score * exam_weight_pct / 100)
grade = lookup(tbl_grading_config WHERE total BETWEEN min AND max)
Admin Control: The notification_channel column in tbl_sys_settings determines active channels. Values: EMAIL (default), SMS, PUSH, SMS_EMAIL, ALL. Admin can enable/disable channels via the Settings page. When multiple channels are active, the service dispatches to ALL active channels for each notification.
Endpoints
Method
Path
Description
POST
/api/v2/notifications/send
Send notification (internal, from other services)
GET
/api/v2/notifications/channels
Get active notification channels
PUT
/api/v2/notifications/channels
Admin updates active channels
GET
/api/v2/notifications/log
SMS/email send history
Kafka Consumer Topics
# Subscribes to all notification-triggering events
student.registered → Welcome email
enrollment.approved → "Your enrollment has been approved" (email + SMS if enabled)
enrollment.rejected → Rejection notification
exam.created → Exam availability alert
exam.submitted → Submission confirmation
exam.failed-3x → Suspension warning
assignment.marked → Grade notification
grading.level-completed → Level completion congratulations
Existing chat data in tbl_chat, tbl_chat_room, tbl_chat_counter will be migrated to MongoDB via a one-time migration script. After migration, the PostgreSQL chat tables become read-only archives.
Other services fetch settings from this service's REST API (cached in Redis, TTL: 30 min). This replaces the direct settingService.isRequestValid() call pattern.
Rule-based FAQ lookup with keyword matching. Supports 4 languages (en/fr/sw/pt). Escalation creates a chat room with an admin via the Chat Service.
4. Shared Database Strategy
All Spring Boot services connect to the same PostgreSQL 17 database (salvation). This is a pragmatic decision to avoid complex distributed transactions and data migration during the initial decomposition.
Convention: Each service ONLY writes to its owned tables. Cross-service data is accessed read-only or through Kafka events. This prevents hidden coupling.
Connection Pooling
Each service gets its own HikariCP connection pool (max 20 per service vs. 80 in the monolith). Total: ~240 connections across all services. PostgreSQL max_connections should be set to 300+.
5. Event-Driven Communication (Kafka)
Topic Catalog
Topic
Producer
Consumers
Payload
student.registered
Student Svc
Enrollment, Notification
studentId, name, email, territory
student.updated
Student Svc
Enrollment, Reporting
studentId, changedFields
enrollment.submitted
Enrollment Svc
Notification
studentId, subjects[], level
enrollment.approved
Enrollment Svc
Student, Exam, Notification
studentId, status, approver
enrollment.rejected
Enrollment Svc
Student, Notification
studentId, reason, rejector
exam.created
Exam Svc
Notification
paperId, subjectId, examDate
exam.submitted
Exam Svc
Notification
studentId, paperId, score
exam.marked
Exam Svc
Grading, Notification
studentId, paperId, score
exam.failed-3x
Exam Svc
Suspension, Notification
studentId, subjectId, retakeCount
assignment.uploaded
Assignment Svc
Notification
studentId, subjectId, fileName
assignment.marked
Assignment Svc
Grading, Notification
studentId, assignmentId, score
grading.calculated
Grading Svc
Reporting
studentId, subjectId, grade
grading.level-completed
Grading Svc
Certificate, Notification
studentId, levelId, finalGrade
suspension.created
Suspension Svc
Notification
studentId, subjectId, deadline
suspension.lifted
Suspension Svc
Notification
studentId, liftedBy
Kafka Configuration
# Partitions: 3 per topic (allows 3x parallel consumers)
# Replication: 1 (single-node dev/staging), 3 (production)
# Retention: 7 days
# Consumer groups: one per service (e.g., notification-svc-group)
6. Docker Compose & Container Orchestration
Complete Container Map (17 Containers)
#
Container
Image
Port
Depends On
1
salt-postgres
postgres:17
5432
—
2
salt-keycloak-db
postgres:17
5433
—
3
salt-redis
redis:7-alpine
6379
—
4
salt-mongodb
mongo:7
27017
—
5
salt-minio
minio/minio:latest
9000/9001
—
6
salt-zookeeper
confluentinc/cp-zookeeper:7.6
2181
—
7
salt-kafka
confluentinc/cp-kafka:7.6
9092
zookeeper
8
salt-keycloak
quay.io/keycloak/keycloak:24
8180
keycloak-db, redis
9
salt-eureka
Custom (Spring Boot)
8761
—
10
salt-gateway
Custom (Spring Cloud Gateway)
8080
eureka, keycloak
11
salt-student-svc
Custom (Spring Boot)
8101
postgres, eureka, kafka
12
salt-enrollment-svc
Custom (Spring Boot)
8102
postgres, eureka, kafka
13
salt-curriculum-svc
Custom (Spring Boot)
8103
postgres, eureka, redis
14
salt-exam-svc
Custom (Spring Boot)
8104
postgres, eureka, kafka, redis, minio
15
salt-notification-svc
Custom (FastAPI)
8200
postgres, kafka
16
salt-chat-svc
Custom (Node.js)
8300
mongodb, redis, kafka
17
salt-web-admin
Custom (Next.js)
8081
gateway
Additional services (certificate, assignment, grading, reporting, config, suspension, chatbot, file-storage) follow the same pattern — each with its own container, port, Dockerfile, and Eureka registration. Total: ~25 containers.
7. Service Communication Matrix
From \ To
Student
Enroll
Curric
Exam
Assign
Grade
Notif
Chat
Cert
File
Student
—
Kafka
REST
—
—
—
Kafka
—
—
—
Enrollment
Kafka
—
REST
Kafka
—
—
Kafka
—
—
—
Exam
—
—
REST
—
—
Kafka
Kafka
—
—
REST
Assignment
—
—
REST
—
—
Kafka
Kafka
—
—
REST
Grading
—
—
—
—
—
—
Kafka
—
Kafka
—
Suspension
—
—
—
—
—
—
Kafka
—
—
—
REST = synchronous HTTP call (via Eureka service discovery). Kafka = asynchronous event via topic.
8. Decomposition Roadmap
Phase A: Infrastructure Foundation
Step
Task
Risk
A1
Deploy Kafka + Zookeeper + MongoDB containers
Low
A2
Deploy Keycloak, configure salt realm, migrate users from tbl_sys_users
Medium
A3
Deploy Eureka Server + Spring Cloud Gateway
Low
A4
Gateway routes ALL traffic to existing monolith (strangler fig pattern)
Largest service (78KB); complex exam lifecycle; Quartz scheduling
Strangler Fig Pattern: During each phase, the API Gateway routes traffic to the NEW microservice for extracted endpoints and to the MONOLITH for everything else. The monolith shrinks incrementally until it's fully decomposed.
9. Monitoring & Observability
Aspect
Tool
Purpose
Logging
ELK Stack (Elasticsearch, Logstash, Kibana)
Centralized log aggregation from all 25 containers
Metrics
Prometheus + Grafana
Service health, request latency, JVM stats, Kafka lag
Tracing
Jaeger / Zipkin
Distributed request tracing across services
Health Checks
Spring Boot Actuator + Eureka
Service health endpoints + registration status
Alerting
Grafana Alerts
Notify on service down, high error rate, Kafka consumer lag
Spring Boot Actuator Endpoints (per service)
/actuator/health # Health status + dependency checks
/actuator/metrics # JVM, HTTP, custom metrics
/actuator/info # Service version, git commit
/actuator/prometheus # Prometheus-compatible metrics export
10. Security Architecture
Authentication Flow
Client sends credentials to /auth/realms/salt/protocol/openid-connect/token (Keycloak)
Enrollment (approve), Students (territory-scoped), Reports
student
12
Own profile, subjects, assignments, exams, chat, performance
Service-to-Service Auth
Internal REST calls between services use a Keycloak service account (salt-internal-client) with client credentials grant. This ensures service-to-service calls are authenticated even within the Docker network.
Kafka Security
SASL/PLAIN authentication between services and Kafka broker. ACLs restrict which services can produce/consume from which topics.
Document ID: SALT-MSA-2026-001 | Prepared: 20th February 2026