Skip to content

Deployment Guide

This guide covers deploying ICOSYS services and the React frontend to test and production environments.


Environments

Environment Profile Purpose
Development dev Local workstation, all defaults
Test test Staging server, restricted CORS
Production prod Live system, full security

Each Spring Boot service selects its profile at startup:

java -jar icglb-services.jar --spring.profiles.active=prod

Build Artifacts

Backend — Executable JARs

Build all services
# Shared libraries (if not already installed)
cd ICOM-Api-4.0          && mvn clean install -DskipTests && cd ..
cd ICOM-Services-Api-1.0 && mvn clean install -DskipTests && cd ..
cd Icglb-Entities-1.0    && mvn clean install -DskipTests && cd ..
cd Icglb-Entities-Dto-1.0 && mvn clean install -DskipTests && cd ..
cd ICOM-Micro-Services-Api-1.0 && mvn clean install -DskipTests && cd ..

# Service JARs
cd Icglb-Services-1.0 && mvn clean package -DskipTests && cd ..
cd ICoSys-BPM/ICoSys-BPM-Services-1.0 && mvn clean package -DskipTests && cd ../..
cd ICoSys-DMS-Service-1.0/ICoSys-DMS-Service-1.0 && mvn clean package -DskipTests && cd ../..

Output JARs:

Service JAR Location
Icglb Icglb-Services-1.0/target/icglb-services-1.0.0.jar
BPM ICoSys-BPM/ICoSys-BPM-Services-1.0/target/icosys-bpm-services-1.0.0.jar
DMS ICoSys-DMS-Service-1.0/ICoSys-DMS-Service-1.0/target/icosys-dms-service-1.0.0.jar

Frontend — Static Files

Build React app
cd ICoSys-Web-React-1.0
npm ci
npm run build

Output: dist/ directory containing optimized HTML, JS, and CSS.


Server Directory Structure

/opt/icosys/                          # or C:\server\ICOSYS\
├── bin/
│   ├── icglb-services.jar
│   ├── icosys-bpm-services.jar
│   └── icosys-dms-services.jar
├── config/
│   ├── icglb/
│   │   └── application-prod.properties
│   ├── icbpm/
│   │   └── application-prod.properties
│   └── icdms/
│       └── application-prod.properties
├── data/
│   └── dms/                          # DMS file storage
├── log/
│   ├── icglb/
│   ├── icbpm/
│   └── icdms/
└── web/
    └── dist/                         # React build output

Environment Variables

Required (All Environments)

Variable Description Example
DB_USERNAME MySQL user icosys_app
DB_PASSWORD MySQL password (secret)
JWT_SECRET HS512 signing key (64+ hex chars) openssl rand -hex 32
ICGLB_SECURITY_API_KEY API key for protected endpoints openssl rand -hex 16

Required (DMS Only)

Variable Description Example
DMS_URL_SECRET HMAC secret for signed download URLs openssl rand -hex 16
ENCRYPTION_KEY AES key for encrypted fields (32 chars) openssl rand -hex 16

Optional

Variable Description Default
SPRING_PROFILES_ACTIVE Active profile dev
JAVA_OPTS JVM options -Xmx2g
RECAPTCHA_SECRET_KEY Google reCAPTCHA v3 secret

Secret Generation

Always generate fresh secrets for each environment:

# JWT secret (64 characters)
openssl rand -hex 32

# API key (32 characters)
openssl rand -hex 16

# Encryption key (32 characters)
openssl rand -hex 16

Never reuse dev defaults in test or production.


Database Setup

Create Dedicated User

Production database setup
-- Create application user (not root!)
CREATE USER 'icosys_app'@'%' IDENTIFIED BY 'strong_password_here';

-- Grant per-schema permissions
GRANT SELECT, INSERT, UPDATE, DELETE ON icglb2.* TO 'icosys_app'@'%';
GRANT SELECT, INSERT, UPDATE, DELETE ON icbpm.*  TO 'icosys_app'@'%';
GRANT SELECT, INSERT, UPDATE, DELETE ON icdms.*  TO 'icosys_app'@'%';

FLUSH PRIVILEGES;

No DDL Privileges

The application user should not have CREATE, ALTER, or DROP privileges. Schema changes are applied manually via DDL scripts.

Run DDL Scripts

Execute DDL scripts in order:

  1. Icglb-Services-1.0/docs/database/ddl_scripts.md (core tables first)
  2. ICoSys-BPM/.../docs/database/ddl_scripts.md
  3. ICoSys-DMS-Service-1.0/.../docs/database/ddl_scripts.md

Service Startup

Using systemd (Linux)

/etc/systemd/system/icglb.service
[Unit]
Description=ICOSYS Icglb Services
After=mysql.service
Requires=mysql.service

[Service]
Type=simple
User=icosys
WorkingDirectory=/opt/icosys/bin
ExecStart=/usr/bin/java \
  -Xmx2g \
  -jar icglb-services.jar \
  --spring.profiles.active=prod \
  --spring.config.additional-location=/opt/icosys/config/icglb/
Environment=DB_PASSWORD=your_password
Environment=JWT_SECRET=your_jwt_secret
Environment=ICGLB_SECURITY_API_KEY=your_api_key
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
Enable and start
sudo systemctl enable icglb
sudo systemctl start icglb
sudo systemctl status icglb

Repeat for icbpm (port 8020) and icdms (port 8030).

Using Windows Service

Use WinSW or NSSM to register JARs as Windows services:

icglb-service.xml (WinSW)
<service>
  <id>icglb-services</id>
  <name>ICOSYS Icglb Services</name>
  <executable>java</executable>
  <arguments>-Xmx2g -jar C:\server\ICOSYS\bin\icglb-services.jar --spring.profiles.active=prod</arguments>
  <logpath>C:\server\ICOSYS\log\icglb</logpath>
  <env name="DB_PASSWORD" value="your_password"/>
  <env name="JWT_SECRET" value="your_jwt_secret"/>
</service>

Startup Order

Services are independent but the following order is recommended:

  1. MySQL — Database must be available
  2. Icglb-Services (8010) — Core auth, required for login
  3. BPM-Services (8020) — Optional, depends on business need
  4. DMS-Service (8030) — Optional, depends on business need

Reverse Proxy (Nginx)

All services sit behind a single Nginx reverse proxy with SSL termination.

/etc/nginx/sites-available/icosys.conf
server {
    listen 443 ssl;
    server_name app.icosys.com;

    ssl_certificate     /etc/ssl/certs/icosys.crt;
    ssl_certificate_key /etc/ssl/private/icosys.key;

    # React SPA
    location / {
        root /opt/icosys/web/dist;
        try_files $uri $uri/ /index.html;

        # Cache static assets
        location ~* \.(js|css|png|jpg|svg|ico|woff2)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }

    # Backend services
    location /icglb/services/ {
        proxy_pass http://127.0.0.1:8010;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /icbpm/services/ {
        proxy_pass http://127.0.0.1:8020;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /icdms/services/ {
        proxy_pass http://127.0.0.1:8030;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # DMS file upload — increase body size limit
        client_max_body_size 100M;
    }
}

# HTTP → HTTPS redirect
server {
    listen 80;
    server_name app.icosys.com;
    return 301 https://$host$request_uri;
}

Health Checks

All services expose Spring Boot Actuator health endpoints:

Service Health URL
Icglb http://localhost:8010/icglb/services/actuator/health
BPM http://localhost:8020/icbpm/services/actuator/health
DMS http://localhost:8030/icdms/services/actuator/health

Monitoring Script

health-check.sh
#!/bin/bash
SERVICES=(
  "http://localhost:8010/icglb/services/actuator/health"
  "http://localhost:8020/icbpm/services/actuator/health"
  "http://localhost:8030/icdms/services/actuator/health"
)

for url in "${SERVICES[@]}"; do
  status=$(curl -s -o /dev/null -w "%{http_code}" "$url" --max-time 5)
  if [ "$status" != "200" ]; then
    echo "ALERT: $url returned $status"
    # Send notification (email, Slack, etc.)
  fi
done

Log Management

Log Locations

Service Log File
Icglb /opt/icosys/log/icglb/icglb-services.log
BPM /opt/icosys/log/icbpm/icbpm-services.log
DMS /opt/icosys/log/icdms/icdms-services.log

Log Rotation

Spring Boot uses Logback with built-in rotation:

  • Max file size: 10 MB
  • History: 7 days
  • Total cap: 100 MB per service

Production Log Levels

application-prod.properties
logging.level.root=WARN
logging.level.com.icom=INFO
logging.level.org.springframework=ERROR
logging.level.org.hibernate=ERROR

Security Checklist

Before Go-Live

  • [ ] All secrets generated fresh (JWT_SECRET, API_KEY, DMS_URL_SECRET, ENCRYPTION_KEY)
  • [ ] DB_PASSWORD is not the default
  • [ ] MySQL user has no DDL privileges (SELECT, INSERT, UPDATE, DELETE only)
  • [ ] CORS origins restricted to production domain(s)
  • [ ] IP whitelist configured (if enabled)
  • [ ] SSL/TLS enabled on reverse proxy
  • [ ] Secure flag on JWT cookie (HTTPS only)
  • [ ] Rate limiting enabled
  • [ ] Health endpoints not publicly exposed (or behind auth)
  • [ ] Log levels set to WARN/ERROR (no DEBUG)
  • [ ] No dev default keys in any properties file
  • [ ] DMS storage directory has correct file permissions
  • [ ] Firewall: only ports 80/443 exposed, backend ports internal only
application-prod.properties
jwt.cookie.secure=true
jwt.cookie.same-site=Lax

CI/CD Pipeline

GitHub Actions (React Frontend)

The React project includes a GitHub Actions workflow that runs on every push:

Push → Lint → TypeScript Check → Unit Tests → Build → SonarQube

See .github/workflows/ci.yml in ICoSys-Web-React-1.0/.

Backend CI

Each backend service can be analyzed with SonarQube:

mvn clean verify sonar:sonar \
  -DskipTests \
  -Dsonar.projectKey=icglb-services \
  -Dsonar.host.url=$SONAR_HOST_URL \
  -Dsonar.token=$SONAR_TOKEN

Rollback Procedure

Backend

  1. Stop the service: sudo systemctl stop icglb
  2. Replace JAR with previous version
  3. Start the service: sudo systemctl start icglb
  4. Verify health check

Frontend

  1. Replace dist/ with previous build
  2. Nginx serves static files — no restart needed

Database

Database Rollback

DDL changes (new tables, columns) are not automatically reversible. Always create a database backup before applying DDL scripts:

mysqldump -u root -p icglb2 > icglb2_backup_$(date +%Y%m%d).sql
mysqldump -u root -p icbpm  > icbpm_backup_$(date +%Y%m%d).sql
mysqldump -u root -p icdms  > icdms_backup_$(date +%Y%m%d).sql

Deployment Checklist

Per Release

  • [ ] All tests pass locally
  • [ ] CI pipeline green
  • [ ] SonarQube Grade A (no blockers or criticals)
  • [ ] Database backups taken
  • [ ] DDL scripts reviewed and applied (if any)
  • [ ] JARs built with correct profile
  • [ ] React build completed (npm run build)
  • [ ] Artifacts copied to server
  • [ ] Services restarted
  • [ ] Health checks pass
  • [ ] Smoke test: login, list, create, update, delete
  • [ ] Logs checked for errors in first 5 minutes

What's Next?