← Click here to go back to Home Page Documentation
College Logo
SALT
Salvation Army SALT College of Africa

Microservice Architecture

Monolith Decomposition & Container Orchestration Guide

Document ID:SALT-MSA-2026-001
Version:2.0
Date:18th February 2026
Prepared By:Sumba Group Limited
Developed BySumba Group Limited
Classification:Internal — Confidential
IMPLEMENTED — Microservice Codebase Built

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.

Repository: https://github.com/SGL2024/Salvation-Army-Backend-Microservice.git

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.

Table of Contents

1. Executive Summary 2. Architecture Overview 2.1 High-Level Architecture Diagram 2.2 Infrastructure Components 2.3 Communication Patterns 3. Service Catalog 3.1 API Gateway (Spring Cloud Gateway) 3.2 Authentication Service (Keycloak) 3.3 Service Discovery (Eureka) 3.4 Student Management Service 3.5 Curriculum & Subject Service 3.6 Enrollment & Approval Service 3.7 Examination Service 3.8 Assignment & Tutor Service 3.9 Grading & Billing Service 3.10 Notification Service (FastAPI) 3.11 Chat Service (Node.js + MongoDB) 3.12 File Storage Service 3.13 Certificate & Transcript Service 3.14 Reporting & Analytics Service 3.15 System Configuration Service 3.16 Suspension & Intake Service 3.17 Chatbot & FAQ Service 4. Shared Database Strategy 5. Event-Driven Communication (Kafka) 6. Docker Compose & Container Orchestration 7. Service Communication Matrix 8. Decomposition Roadmap 9. Monitoring & Observability 10. Security Architecture

1. Executive Summary

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

DecisionChoiceRationale
Database StrategyShared PostgreSQL 17Existing production data in salvation DB; avoids complex data migration. Services share the database with schema-level isolation.
Message BrokerApache Kafka + ZookeeperEvent-driven decoupling between services; supports async notifications, audit trails, and eventual consistency.
AuthenticationKeycloakReplaces custom JWT implementation; provides SSO, role management, OAuth2/OIDC, and admin console out-of-the-box.
Service DiscoveryNetflix EurekaSpring Cloud native; automatic registration/deregistration with health checks.
API GatewaySpring Cloud GatewayRoute management, rate limiting, circuit breaking, JWT validation — all Spring ecosystem native.
Notification ServiceFastAPI (Python)Lightweight, async-native, ideal for I/O-bound notification dispatch (email, SMS, FCM push).
Chat ServiceNode.js + MongoDBWebSocket-native runtime; MongoDB for flexible chat document storage.
ContainerizationDocker + Docker ComposeEvery 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

CLIENTS Next.js Web Admin Flutter Mobile Exec Dashboard External APIs QR Verify (Public) Spring Cloud Gateway Route Management • Rate Limiting • JWT Validation • Circuit Breaker Keycloak OAuth2 / OIDC / SSO Eureka Server Service Discovery BUSINESS SERVICES (Spring Boot + FastAPI + Node.js) Student MgmtSpring Boot • :8101 EnrollmentSpring Boot • :8102 CurriculumSpring Boot • :8103 ExaminationSpring Boot • :8104 Assignment & TutorSpring Boot • :8105 Grading & BillingSpring Boot • :8106 NotificationFastAPI • :8200 ChatNode.js • :8300 CertificateSpring Boot • :8107 Reporting & AnalyticsSpring Boot • :8108 Apache Kafka Event Bus • Topics: student.*, enrollment.*, exam.*, notification.*, chat.*, grading.* Zookeeper DATA & STORAGE LAYER PostgreSQL 17salvation DB • Shared • :543235+ tables • Flyway V1-V8 MongoDBChat data • :27017 Redis 7Cache • Sessions • :6379 MinIO (S3)Files • :9000 / :9001 Keycloak DBPostgreSQL • :5433 EXTERNAL SERVICES SMTP (Email) SMS Gateway (Retrofit) Firebase Cloud Messaging Let's Encrypt SSL (Nginx) Docker Compose 17 Containers Nginx Reverse Proxy (:443) EC2 (Ubuntu 22.04)
Figure 1: Microservice Architecture — 14 business services + 3 infrastructure services, event-driven via Kafka

2.2 Infrastructure Components

ComponentTechnologyPortContainer NamePurpose
GATEWAY API GatewaySpring Cloud Gateway8080salt-gatewaySingle entry point, routing, rate limiting, JWT validation
AUTH KeycloakKeycloak 24+8180salt-keycloakOAuth2/OIDC identity provider, SSO, role management
DISCOVERY EurekaSpring Cloud Netflix Eureka8761salt-eurekaService registration & discovery
BROKER KafkaApache Kafka 3.7+9092salt-kafkaEvent-driven messaging between services
ZK ZookeeperApache Zookeeper2181salt-zookeeperKafka cluster coordination
DB PostgreSQLPostgreSQL 175432salt-postgresShared database (salvation)
CACHE RedisRedis 7 Alpine6379salt-redisCaching, sessions, Keycloak sessions
STORE MinIOMinIO Latest9000/9001salt-minioS3-compatible file storage
CHAT-DB MongoDBMongoDB 727017salt-mongodbChat message storage (document DB)
AUTH-DB Keycloak DBPostgreSQL 175433salt-keycloak-dbKeycloak-specific database (separate from salvation)

2.3 Communication Patterns

PatternUse CaseTechnology
Synchronous (REST)Client → Gateway → Service (CRUD operations)HTTP/JSON via Spring Cloud Gateway
Asynchronous (Events)Service → Kafka → Service (notifications, audit, sync)Apache Kafka topics
WebSocketReal-time chat between usersSocket.IO (Node.js Chat Service)
Service DiscoveryServices locating each other dynamicallyNetflix Eureka (heartbeat-based)
Token-Based AuthJWT bearer tokens on all requestsKeycloak-issued OIDC tokens

3. Service Catalog

3.1 API Gateway INFRASTRUCTURE

TechnologySpring Cloud Gateway (Java 17)
Containersalt-gateway
Port8080 (internal), exposed via Nginx on 443
ResponsibilitiesRoute requests to services, validate JWT tokens against Keycloak, rate limiting, circuit breaking, CORS

Route Configuration

spring:
  cloud:
    gateway:
      routes:
        - id: student-service
          uri: lb://student-service
          predicates:
            - Path=/api/v2/students/**
        - id: enrollment-service
          uri: lb://enrollment-service
          predicates:
            - Path=/api/v2/enrollment/**, /SaltELearnAppApi/student/**
        - id: curriculum-service
          uri: lb://curriculum-service
          predicates:
            - Path=/api/v2/subjects/**, /api/v2/countries/**, /api/v2/territories/**
        - id: exam-service
          uri: lb://exam-service
          predicates:
            - Path=/api/v2/exam/**
        - id: assignment-service
          uri: lb://assignment-service
          predicates:
            - Path=/api/v2/assignments/**, /api/v2/materials/**
        - id: grading-service
          uri: lb://grading-service
          predicates:
            - Path=/api/v2/grading/**, /api/v2/billing/**
        - id: notification-service
          uri: lb://notification-service
          predicates:
            - Path=/api/v2/notifications/**
        - id: chat-service
          uri: lb://chat-service
          predicates:
            - Path=/api/v2/chat/**, /ws/**
        - id: certificate-service
          uri: lb://certificate-service
          predicates:
            - Path=/api/v2/certificates/**, /api/v2/transcripts/**
        - id: reporting-service
          uri: lb://reporting-service
          predicates:
            - Path=/api/v2/analytics/**, /api/v2/reports/**
        - id: config-service
          uri: lb://config-service
          predicates:
            - Path=/api/v2/settings/**, /api/v2/admin/schema/**
        - id: chatbot-service
          uri: lb://chatbot-service
          predicates:
            - Path=/api/v2/chatbot/**

3.2 Authentication Service (Keycloak) INFRASTRUCTURE

TechnologyKeycloak 24+ (Quarkus-based)
Containersalt-keycloak
Port8180
DatabaseDedicated PostgreSQL on port 5433 (salt-keycloak-db)
ResponsibilitiesUser authentication, JWT issuance, role management, SSO, password policies, OTP/2FA

Realm Configuration

User Migration

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

TechnologySpring Cloud Netflix Eureka Server
Containersalt-eureka
Port8761
Dashboardhttp://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.

# Each service's application.yml
eureka:
  client:
    service-url:
      defaultZone: http://salt-eureka:8761/eureka/
  instance:
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 30

3.4 Student Management Service SPRING BOOT

Containersalt-student-svc
Port8101
SourceExtracted from: StudentService.java (63KB), StudentController.java
Database Tablestbl_student, tbl_tbl_ranks, tbl_student_achievements

Endpoints

MethodPathDescription
GET/api/v2/studentsList all students (paginated, searchable)
GET/api/v2/students/{id}Get student details
POST/api/v2/studentsRegister new student
PUT/api/v2/students/{id}Update student profile
GET/api/v2/students/{id}/performanceGet academic performance summary
POST/api/v2/students/importBulk CSV import

Kafka Events

3.5 Curriculum & Subject Service SPRING BOOT

Containersalt-curriculum-svc
Port8103
SourceExtracted from: SubjectsService.java, CountryService.java, TerritoryService.java
Database Tablestbl_subjects, tbl_learning_level, tbl_countries, tbl_territory, tbl_languages, tbl_announcements

Key Endpoints

MethodPathDescription
GET/api/v2/subjectsList all subjects
GET/api/v2/subjects/by-level/{levelId}Subjects filtered by learning level + language
GET/api/v2/countriesCountries with flags (Africa-first sorting)
GET/api/v2/territoriesTerritories with country grouping
GET/api/v2/learning-levelsFoundation, Certificate, Diploma

Caching: Subjects, countries, territories cached in Redis (TTL: 1 hour). Announcements cached (TTL: 5 min).

3.6 Enrollment & Approval Service SPRING BOOT

Containersalt-enrollment-svc
Port8102
SourceExtracted from: AdminApproval.java, EtoApproval.java, EnrollmentValidationService.java, AcademicLevelService.java
Database Tablestbl_academic_level, tbl_student_subjects_selection, tbl_sessions

Key Endpoints

MethodPathDescription
POST/api/v2/enrollment/enrollStudent self-enrollment with subject selection
POST/api/v2/enrollment/{id}/eto-approveETO approval (status N→EP)
POST/api/v2/enrollment/{id}/admin-approveAdmin approval (status EP→P)
POST/api/v2/enrollment/{id}/rejectReject enrollment
GET/api/v2/enrollment/pendingPending approvals for ETO/Admin

Kafka Events

3.7 Examination Service SPRING BOOT

Containersalt-exam-svc
Port8104
SourceExtracted from: ExamService.java (78KB — largest service), ExamEnhancementService.java
Database Tablestbl_exam_paper, tbl_questions, tbl_student_quiz, tbl_paper_answer, tbl_exam_dates

Key Endpoints

MethodPathDescription
POST/api/v2/exam/papersCreate exam paper (MCQ/Essay)
POST/api/v2/exam/papers/{id}/questionsAdd questions to paper
POST/api/v2/exam/papers/{id}/startStudent starts exam attempt
POST/api/v2/exam/papers/{id}/submitStudent submits exam
POST/api/v2/exam/papers/{id}/upload-pdfUpload downloadable exam
GET/api/v2/exam/papers/{id}/downloadStudent downloads exam PDF
POST/api/v2/exam/oral-scoreEnter oral exam score

Kafka Events

Scheduling: Uses Quartz Scheduler for exam timers. Timer state stored in Redis for cross-instance consistency.

3.8 Assignment & Tutor Service SPRING BOOT

Containersalt-assignment-svc
Port8105
SourceExtracted from: AssignnementService.java (50KB), TutorService.java (32KB)
Database Tablestbl_materials_upload, tbl_assignment_marking, tbl_tutor_subject_assigment, tbl_late_assignment

Key Endpoints

MethodPathDescription
POST/api/v2/assignments/uploadStudent uploads assignment (max 3/month/subject)
POST/api/v2/assignments/{id}/markTutor marks assignment
POST/api/v2/materials/uploadTutor uploads reading material
GET/api/v2/assignments/pendingUnmarked assignments for tutor

Kafka Events

3.9 Grading & Billing Service SPRING BOOT

Containersalt-grading-svc
Port8106
SourceExtracted from: GradingService.java, BillingService.java
Database Tablestbl_grading_config, tbl_billing, tbl_billing_items

Key Endpoints

MethodPathDescription
GET/api/v2/grading/configGet grading thresholds (6 tiers)
PUT/api/v2/grading/configUpdate grading config (Admin)
GET/api/v2/grading/student/{id}/summaryCalculate all subject grades
POST/api/v2/billing/calculate/{studentId}Generate billing (sum subject costs)
GET/api/v2/billing/exportDownload billing Excel

Grading Formula

total = (AVG(assignments) * assignment_weight_pct / 100)
      + (exam_score * exam_weight_pct / 100)
grade = lookup(tbl_grading_config WHERE total BETWEEN min AND max)

Kafka Events

3.10 Notification Service FASTAPI

TechnologyPython 3.12 + FastAPI + Celery
Containersalt-notification-svc
Port8200
Database Tablestbl_sms_log (PostgreSQL, shared DB)

Notification Channels (Admin-Configurable)

ChannelTechnologyDefaultConfiguration
EmailSMTP (aiosmtplib)Enabled (default)SMTP host/port/credentials from tbl_sys_settings
SMSHTTP Gateway (httpx)DisabledSMS API URL + credentials from tbl_sys_settings
Push (FCM)Firebase Cloud MessagingDisabledFCM server key from tbl_sys_settings
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

MethodPathDescription
POST/api/v2/notifications/sendSend notification (internal, from other services)
GET/api/v2/notifications/channelsGet active notification channels
PUT/api/v2/notifications/channelsAdmin updates active channels
GET/api/v2/notifications/logSMS/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

Architecture

# Internal structure
notification-service/
├── app/
│   ├── main.py              # FastAPI entry point
│   ├── config.py            # DB + Kafka config
│   ├── routers/
│   │   ├── notifications.py # REST endpoints
│   │   └── channels.py      # Channel management
│   ├── services/
│   │   ├── email_sender.py  # SMTP async sender
│   │   ├── sms_sender.py    # SMS HTTP gateway
│   │   ├── fcm_sender.py    # Firebase push
│   │   └── dispatcher.py    # Routes to active channels
│   ├── kafka/
│   │   └── consumer.py      # Kafka event listener
│   └── models/
│       └── schemas.py       # Pydantic models
├── Dockerfile
├── requirements.txt
└── .env

3.11 Chat Service NODE.JS

TechnologyNode.js 20 + Express + Socket.IO + MongoDB
Containersalt-chat-svc
Port8300
DatabaseMongoDB 7 (salt-mongodb, port 27017)

Why MongoDB for Chat?

MongoDB Collections

// messages collection
{
  _id: ObjectId,
  roomId: "user_101_user_202",
  senderId: 101,        // Maps to tbl_sys_users.id
  recipientId: 202,
  content: "Hello!",
  type: "text",         // text | image | file
  filePath: null,       // MinIO path if file/image
  readAt: null,         // Timestamp when read
  createdAt: ISODate("2026-02-14T10:30:00Z")
}

// rooms collection
{
  _id: ObjectId,
  roomId: "user_101_user_202",
  participants: [101, 202],
  lastMessage: "Hello!",
  lastMessageAt: ISODate("2026-02-14T10:30:00Z"),
  unreadCount: { "202": 3 }
}

Endpoints & WebSocket

TypePathDescription
WS/wsSocket.IO connection (JWT auth via handshake)
GET/api/v2/chat/roomsUser's chat rooms
GET/api/v2/chat/messages/{roomId}Message history (paginated)
GET/api/v2/chat/unread-countTotal unread messages

Migration from PostgreSQL

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.

3.12 File Storage Service SPRING BOOT

Containersalt-file-svc
Port8109
SourceExtracted from: FileStorageService.java, FileHandlerService.java

Dual-Read Strategy

READ:  Try MinIO (salt-files bucket) → Fallback to /opt/salt_files → 404
WRITE: Always MinIO

Endpoints

MethodPathDescription
POST/api/v2/files/uploadUpload file to MinIO
GET/api/v2/files/{path}Download file (dual-read)
DELETE/api/v2/files/{id}Soft-delete file

3.13 Certificate & Transcript Service SPRING BOOT

Containersalt-certificate-svc
Port8107
SourceExtracted from: CertificateService.java, PdfGenerator.java
Database Tablestbl_certificates
LibrariesOpenPDF 2.0.3, ZXing 3.5.3

Endpoints

MethodPathDescription
POST/api/v2/certificates/generate/{studentId}/{levelId}Generate certificate PDF with QR
GET/api/v2/certificates/{serial}Download certificate PDF
GET/api/v2/certificates/verify/{serial}Public QR verification (no auth)
GET/api/v2/transcripts/{studentId}Generate transcript PDF

Kafka Events

3.14 Reporting & Analytics Service SPRING BOOT

Containersalt-reporting-svc
Port8108
SourceExtracted from: AnalyticsService.java, ReportRepository.java (complex native SQL)

Key Endpoints

MethodPathDescription
GET/api/v2/analytics/dashboardExecutive dashboard stats
GET/api/v2/analytics/enrollment-trendsEnrollment over time
GET/api/v2/analytics/territory-breakdownTerritory-level analytics
GET/api/v2/reports/progressiveExcel progressive report
GET/api/v2/reports/exam-registerExcel exam register
Read-Only: This service only reads from the database. It can optionally use a read replica for zero production impact.

3.15 System Configuration Service SPRING BOOT

Containersalt-config-svc
Port8110
SourceExtracted from: SystemSettingService.java, SchemaManagementService.java, DataIntegrityService.java
Database Tablestbl_sys_settings (singleton ID=1), tbl_event_logs, tbl_data_integrity_log

Other services fetch settings from this service's REST API (cached in Redis, TTL: 30 min). This replaces the direct settingService.isRequestValid() call pattern.

3.16 Suspension & Intake Service SPRING BOOT

Containersalt-suspension-svc
Port8111
SourceExtracted from: SuspensionService.java, IntakeService.java
Database Tablestbl_suspension_log, tbl_intake_config

Kafka Events

3.17 Chatbot & FAQ Service SPRING BOOT

Containersalt-chatbot-svc
Port8112
Database Tablestbl_chatbot_faq, tbl_chatbot_escalations

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.

Table Ownership

ServiceOwned TablesRead-Only Access To
Student Mgmttbl_student, tbl_tbl_ranks, tbl_student_achievementstbl_sys_users, tbl_territory
Enrollmenttbl_academic_level, tbl_student_subjects_selection, tbl_sessionstbl_student, tbl_subjects
Curriculumtbl_subjects, tbl_learning_level, tbl_countries, tbl_territory, tbl_announcements
Examinationtbl_exam_paper, tbl_questions, tbl_student_quiz, tbl_paper_answer, tbl_exam_datestbl_student_subjects_selection
Assignmenttbl_materials_upload, tbl_assignment_marking, tbl_tutor_subject_assigment, tbl_late_assignmenttbl_student_subjects_selection
Gradingtbl_grading_config, tbl_billing, tbl_billing_itemstbl_student_subjects_selection, tbl_subjects
Notificationtbl_sms_logtbl_sys_settings
Certificatetbl_certificatestbl_student, tbl_academic_level
Reporting— (read-only)ALL tables (analytics queries)
Configurationtbl_sys_settings, tbl_event_logs, tbl_data_integrity_log
Suspensiontbl_suspension_log, tbl_intake_configtbl_student_subjects_selection
Chatbottbl_chatbot_faq, tbl_chatbot_escalations
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

TopicProducerConsumersPayload
student.registeredStudent SvcEnrollment, NotificationstudentId, name, email, territory
student.updatedStudent SvcEnrollment, ReportingstudentId, changedFields
enrollment.submittedEnrollment SvcNotificationstudentId, subjects[], level
enrollment.approvedEnrollment SvcStudent, Exam, NotificationstudentId, status, approver
enrollment.rejectedEnrollment SvcStudent, NotificationstudentId, reason, rejector
exam.createdExam SvcNotificationpaperId, subjectId, examDate
exam.submittedExam SvcNotificationstudentId, paperId, score
exam.markedExam SvcGrading, NotificationstudentId, paperId, score
exam.failed-3xExam SvcSuspension, NotificationstudentId, subjectId, retakeCount
assignment.uploadedAssignment SvcNotificationstudentId, subjectId, fileName
assignment.markedAssignment SvcGrading, NotificationstudentId, assignmentId, score
grading.calculatedGrading SvcReportingstudentId, subjectId, grade
grading.level-completedGrading SvcCertificate, NotificationstudentId, levelId, finalGrade
suspension.createdSuspension SvcNotificationstudentId, subjectId, deadline
suspension.liftedSuspension SvcNotificationstudentId, 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)

#ContainerImagePortDepends On
1salt-postgrespostgres:175432
2salt-keycloak-dbpostgres:175433
3salt-redisredis:7-alpine6379
4salt-mongodbmongo:727017
5salt-miniominio/minio:latest9000/9001
6salt-zookeeperconfluentinc/cp-zookeeper:7.62181
7salt-kafkaconfluentinc/cp-kafka:7.69092zookeeper
8salt-keycloakquay.io/keycloak/keycloak:248180keycloak-db, redis
9salt-eurekaCustom (Spring Boot)8761
10salt-gatewayCustom (Spring Cloud Gateway)8080eureka, keycloak
11salt-student-svcCustom (Spring Boot)8101postgres, eureka, kafka
12salt-enrollment-svcCustom (Spring Boot)8102postgres, eureka, kafka
13salt-curriculum-svcCustom (Spring Boot)8103postgres, eureka, redis
14salt-exam-svcCustom (Spring Boot)8104postgres, eureka, kafka, redis, minio
15salt-notification-svcCustom (FastAPI)8200postgres, kafka
16salt-chat-svcCustom (Node.js)8300mongodb, redis, kafka
17salt-web-adminCustom (Next.js)8081gateway
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 \ ToStudentEnrollCurricExamAssignGradeNotifChatCertFile
StudentKafkaRESTKafka
EnrollmentKafkaRESTKafkaKafka
ExamRESTKafkaKafkaREST
AssignmentRESTKafkaKafkaREST
GradingKafkaKafka
SuspensionKafka

REST = synchronous HTTP call (via Eureka service discovery). Kafka = asynchronous event via topic.

8. Decomposition Roadmap

Phase A: Infrastructure Foundation

StepTaskRisk
A1Deploy Kafka + Zookeeper + MongoDB containersLow
A2Deploy Keycloak, configure salt realm, migrate users from tbl_sys_usersMedium
A3Deploy Eureka Server + Spring Cloud GatewayLow
A4Gateway routes ALL traffic to existing monolith (strangler fig pattern)Low

Phase B: Extract Standalone Services (Low Coupling)

StepServiceWhy First
B1Notification Service (FastAPI)Cross-cutting, no business logic; event-driven makes it easy to decouple
B2Chat Service (Node.js + MongoDB)Clean WebSocket boundary; different DB (MongoDB)
B3Chatbot & FAQ ServiceStandalone lookup service, no external dependencies
B4File Storage ServiceInfrastructure adapter; clear API boundary

Phase C: Extract Domain Services (Medium Coupling)

StepServiceComplexity
C1Curriculum & Subject ServiceRead-heavy reference data; low write coupling
C2Certificate & Transcript ServiceIsolated PDF generation; minimal dependencies
C3Reporting & Analytics ServiceRead-only; can use read replica
C4Grading & Billing ServiceComputational logic; events trigger recalculation
C5Suspension & Intake ServiceSmall service; event-driven (Kafka consumer)
C6System Configuration ServiceSingleton pattern; provides config API to all services

Phase D: Extract Core Business Services (High Coupling)

StepServiceKey Challenge
D1Student Management ServiceShared tbl_student; used by enrollment, exam, grading
D2Enrollment & Approval ServiceComplex approval workflow (N→EP→P); touches student + subject data
D3Assignment & Tutor ServiceShared tbl_materials_upload; tutor-student relationships
D4Examination ServiceLargest 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

AspectToolPurpose
LoggingELK Stack (Elasticsearch, Logstash, Kibana)Centralized log aggregation from all 25 containers
MetricsPrometheus + GrafanaService health, request latency, JVM stats, Kafka lag
TracingJaeger / ZipkinDistributed request tracing across services
Health ChecksSpring Boot Actuator + EurekaService health endpoints + registration status
AlertingGrafana AlertsNotify 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

  1. Client sends credentials to /auth/realms/salt/protocol/openid-connect/token (Keycloak)
  2. Keycloak validates credentials, returns JWT access token + refresh token
  3. Client includes Authorization: Bearer <token> on all API requests
  4. API Gateway validates the JWT signature against Keycloak's public key (JWKS endpoint)
  5. Gateway forwards request to target service with validated token claims
  6. Service reads role/user info from token claims — no second auth call needed

Role Mapping

Keycloak RoleLegacy access_levelServices Access
admin5All services, all endpoints
tutor8Assignment (mark), Exam (create/mark), Materials (upload)
eto9Enrollment (approve), Students (territory-scoped), Reports
student12Own 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

© 2021-2026 College E-Learning — Developed by Sumba Group Limited for Salvation Army SALT College of Africa