MATIH Platform is in active MVP development. Documentation reflects current implementation status.
18. CI/CD & Build System
Java Builds (Maven)

Java Builds (Maven)

The MATIH platform's Java services use Maven with Spring Boot 3.2 and are structured as a multi-module project with shared commons. The build system uses Maven wrapper (mvnw) for reproducible builds.


Java Service Inventory

Control Plane (8 services)

ServicePortDescription
iam-service8081Identity and access management
tenant-service8082Tenant lifecycle management
config-service8888Spring Cloud Config server
audit-service8086Audit trail and compliance logging
notification-service8085Email, Slack, webhook notifications
billing-service8087Usage metering and billing
platform-registry8084Service registry and discovery
observability-api8088Observability data aggregation API

Data Plane (6 Java services)

ServicePortDescription
query-engine8080SQL query execution and optimization
catalog-service8086Data catalog metadata management
semantic-layer8086Semantic model definitions
bi-service8084Business intelligence service
data-plane-agent8085Data plane orchestration agent
governance-service8080Data governance policies

Commons Library

The commons-java module is built first and installed to the local Maven repository:

cd commons/commons-java
./mvnw clean package -DskipTests
./mvnw install -DskipTests -q

This makes shared classes available to all downstream services:

  • Security: JwtTokenProvider, TenantContext, RBAC utilities
  • Multi-tenancy: TenantContext, tenant-aware repository base classes
  • Observability: Structured logging configuration, metrics utilities
  • Shared models: DTOs, exceptions, response wrappers

Maven Build Process

Each Java service follows the same build flow:

build_maven_project() {
    local project_path="$1"
    local project_name=$(basename "$project_path")
 
    cd "$project_path"
 
    local mvn_cmd="./mvnw"
    if [[ ! -f "mvnw" ]]; then
        mvn_cmd="mvn"
    fi
 
    # clean: Remove previous build artifacts
    # package: Compile, test, and create JAR/WAR
    $mvn_cmd clean package $skip_tests_flag
}

Build Phases

  1. clean - Remove target/ directory
  2. compile - Compile main source code
  3. test-compile - Compile test source code
  4. test - Run unit tests (skipped with --skip-tests)
  5. package - Create executable JAR with embedded Tomcat

Spring Boot Fat JAR

Each service produces a self-contained fat JAR using the Spring Boot Maven plugin:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layers>
            <enabled>true</enabled>
        </layers>
    </configuration>
</plugin>

The layered JAR enables optimized Docker builds by separating dependencies from application code.


Connector Builds

Connectors follow the same Maven pattern but are organized under connectors/:

CONNECTOR_MODULES=(
    "connector-sdk"
    "databases/postgresql-connector"
    "databases/mysql-connector"
    "databases/bigquery-connector"
    "databases/snowflake-connector"
    "crm/salesforce-connector"
    "cloud-storage/s3-connector"
    "cloud-storage/gcs-connector"
    "cloud-storage/azure-blob-connector"
)

The connector-sdk is built first as it provides the base interfaces and utilities that all connectors implement.


Test Execution

Java tests use Maven's Surefire plugin:

run_maven_tests() {
    local project_path="$1"
    cd "$project_path"
 
    local mvn_cmd="./mvnw"
    if [[ ! -f "mvnw" ]]; then
        mvn_cmd="mvn"
    fi
 
    $mvn_cmd test
}

Integration tests (under tests/integration/) require running dependencies and are only executed with --with-deps:

if [[ "$WITH_DEPS" == "true" ]]; then
    # Requires PostgreSQL and Redis containers
    run_maven_tests "${ROOT_DIR}/tests/integration/control-plane"
    run_maven_tests "${ROOT_DIR}/tests/integration/data-plane"
fi

Docker Image Creation

After Maven packaging, a Docker image is built using the service's Dockerfile:

# Build command executed per service
docker build \
    --tag "ghcr.io/matih/${service_name}:${IMAGE_TAG}" \
    --tag "ghcr.io/matih/${service_name}:latest" \
    --build-arg BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --build-arg VERSION="${IMAGE_TAG}" \
    "${service_path}"

Typical Java Dockerfile pattern:

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8081
ENTRYPOINT ["java", "-jar", "app.jar"]