All-in-One UI Services Deployment

1. Overview

This deployment runs all UI services on a single host using Docker Compose:

  • UI Backend (Spring Boot)

  • UI Portals (Angular on Nginx)

  • FT Device Network Service (Spring Boot)

  • AI Agent Service (Python)

  • PostgreSQL database (for AI Agent)

2. Architecture

component-diagram

3. Prerequisites

3.1. Required External Components

The following components must be installed and accessible before deployment:

Component Purpose Default Port

MySQL or Oracle

Main application database

3306 (MySQL) / 1521 (Oracle)

Hazelcast

Distributed cache

5701

FTACS Application

ACS web service

8080

Clickhouse

Analytics database

9000

3.2. System Requirements

  • Docker Engine 20.10+

  • Docker Compose 2.0+

  • Minimum 4GB RAM

  • 20GB free disk space

4. Preparation

4.1. Prepare Configuration Directory

Create the required directory structure:

/usr/local/ft-system may require sudo on most Linux systems. Alternatively, use a path in your home directory (e.g., ~/ft-system) and adjust all paths accordingly. This layout follows the same base directory and per-service config/logs convention as the Full System Deployment guide; this deployment only prepares the subset of directories needed for the UI services group.

mkdir -p /usr/local/ft-system/ui-backend/{config,logs}
mkdir -p /usr/local/ft-system/portals/nginx/logs
mkdir -p /usr/local/ft-system/ft-device-network/logs
mkdir -p /usr/local/ft-system/ui-ai-agent/logs
mkdir -p /usr/local/ft-system/postgres/data
cd /usr/local/ft-system

Download the deployment files (compose.yml, .env.mysql, .env.oracle) from the FT_DISK on SharePoint and place them into the working directory.

4.1.1. Volume Mounts & Directory Layout

The ui-backend/config folder contains essential configuration files for the backend service. Download pre-configured files from the FT_DISK on SharePoint (SharePoint folder ui-backend-conf) and place them into the ui-backend/config/ directory. See Installation & Deployment for detailed configuration instructions.

The tree below shows the baseline layout plus common environment-dependent entries. Not every deployment needs every entry, but the standard SharePoint package can include them because some are default runtime config, some are loaded only when present, and some are used only for specific integrations.

/usr/local/ft-system/
├── ui-backend/
│   ├── config/                   # Configuration (backup required)
│   │   ├── hazelcast-client.xml  # Main Hazelcast client configuration
│   │   ├── ftacs.keystore        # Backend keystore used when HTTPS is enabled
│   │   ├── logback-spring.xml    # Default external logging configuration
│   │   ├── interfaceItems.json   # Interface seed data, loaded if present
│   │   ├── customization/        # Portal customization JSON files
│   │   │   ├── def/               # Default system-wide customizations
│   │   │   ├── mc/                # Management Console customizations
│   │   │   └── sc/                # Support Center customizations
│   │   ├── ssl/                  # TLS certificates for Nginx/portals when configured
│   │   └── keys/                 # Integration credentials (when used)
│   └── logs/                     # Backend application logs
├── portals/
│   └── nginx/logs/               # Portals Nginx access/error logs
├── ft-device-network/
│   └── logs/                     # FT Device Network application logs
├── ui-ai-agent/
│   └── logs/                     # AI Agent application logs
└── postgres/
    └── data/                     # PostgreSQL data directory (AI Agent)
Path Content Backup Required

ui-backend/config/

Configuration files. At minimum this includes hazelcast-client.xml and customizations; the SharePoint package may also include additional service-specific files and directories.

Yes

ui-backend/logs/

Backend application logs

No

portals/nginx/logs/

Nginx access and error logs

No

ft-device-network/logs/

FT Device Network application logs

No

ui-ai-agent/logs/

AI Agent application logs

No

postgres/data/

PostgreSQL database files

Yes

4.2. Prepare Environment File

The compose.yml references the env file via env_file directive. Make sure it points to the file matching your database:

MySQL
env_file:
  - .env.mysql
Oracle
env_file:
  - .env.oracle

The all-in-one package ships one environment file per database vendor (.env.mysql / .env.oracle), and every service in the group reads the same file. The platform stack described in Full System Deployment uses a different model — a shared .env plus a per-service <service>/.env, with the vendor selected inside the shared file (DB_PROFILE). The dedicated-host guide for the backend, Installation & Deployment, documents that two-layer model. Use the model that matches the package you downloaded; do not mix variable names between them.

4.3. Configure Host Variables

Edit .env.mysql or .env.oracle and replace all ~PLACEHOLDER~ values with actual hostnames or IP addresses.

The env files contain placeholders in the format ~NAME~ that must be replaced before starting the services:

Placeholder Variable in .env Description

~HOST~

FT_UI_HOST

Public hostname or IP address of this server (the machine where all services are being deployed). Used by the Portals entrypoint to patch Angular app-config.json so that browsers know where to send API requests. Must be accessible from end-user browsers — use a real IP or DNS name, not localhost.

~HAZEL_HOST~

HZ_MEMBERS

Hazelcast cluster member address(es). Format: host:port (comma-separated for multiple members). The backend connects to this cluster for distributed caching and session sharing.

~FTACS_HOST~

ACS_WEB_SERVICE_HOST

Hostname or IP of the FTACS application server. The backend uses this to make SOAP calls for device provisioning, parameter reads, and firmware management.

~CLICKHOUSE_HOST~

CLICKHOUSE_HOST

Hostname or IP of the ClickHouse server. Used for QoE analytics queries. If ClickHouse is not deployed, leave the default value — the application will skip analytics features.

~MYSQL_HOST~

DB_HOST

Hostname or IP of the MySQL server (only in .env.mysql). Both FTACS and IOTW schemas must be accessible at this address.

~ORACLE_HOST~

DB_HOST

Hostname or IP of the Oracle server (only in .env.oracle). Both FTACS and IOTW schemas must be accessible at this address.

Example (.env.mysql):

FT_UI_HOST=192.168.1.100
HZ_MEMBERS=192.168.1.50:5701,192.168.1.51:5701,192.168.1.52:5701
ACS_WEB_SERVICE_HOST=192.168.1.60
CLICKHOUSE_HOST=192.168.1.70
DB_HOST=192.168.1.80

FT_UI_HOST must be the address that end-user browsers can reach. If users access the portal through a load balancer or public DNS (e.g., iot.example.com), use that value instead of the server’s internal IP.

4.4. Docker Networking: host.docker.internal

If the database, Hazelcast, FTACS, or ClickHouse runs on the host machine (not inside Docker), use host.docker.internal as the hostname in .env variables (DB_HOST, HZ_MEMBERS, ACS_WEB_SERVICE_HOST, etc.):

DB_HOST=host.docker.internal
HZ_MEMBERS=host.docker.internal:5701
ACS_WEB_SERVICE_HOST=host.docker.internal
CLICKHOUSE_HOST=host.docker.internal

Why this is needed:

  • Inside a Docker container, localhost and 127.0.0.1 point to the container itself, not to the host machine. Any connection attempt to a host-side service via localhost will fail.

  • host.docker.internal is a special DNS name that Docker resolves to the host’s internal IP address.

  • The provided compose.yml already includes the required mapping:

    extra_hosts:
      - "host.docker.internal:host-gateway"
  • On Docker Desktop (macOS, Windows) this works out of the box. On Linux the extra_hosts directive above is required (already present in compose.yml).

Alternatively, use the host machine’s real IP address (e.g., 192.168.1.10) instead of host.docker.internal.

5. Environment Variables

5.1. Common Variables

Variable Description Default Required

DATA_FOLDER

Base directory for persistent data and configurations

/usr/local/ft-system

Yes

TZ

Timezone for all services

Europe/Kiev

Yes

DB_VENDOR

Database type: mysql or oracle

mysql

Yes

DB_PASSWORD

Database password

ftacs

Yes

5.2. Database Configuration

MySQL
Variable Description Default

DB_HOST

MySQL server address

-

MYSQL_PORT

MySQL port

3306

MYSQL_USER

MySQL username

ftacs

Oracle
Variable Description Default

DB_HOST

Oracle server address

-

ORACLE_PORT

Oracle port

1521

ORACLE_SERVICE

Oracle service name

XEPDB1

ORACLE_USER_FTACS

Oracle username

ftacs

5.3. External Dependencies

Variable Description Default Required

HZ_MEMBERS

Hazelcast cluster members (comma-separated list of HOST:PORT)

HAZEL_HOST:5701

Yes

ACS_WEB_SERVICE_HOST

FTACS application host

FTACS_HOST

Yes

ACS_WEB_SERVICE_PORT

FTACS application port

8080

Yes

CLICKHOUSE_HOST

Clickhouse server address

CLICKHOUSE_HOST

Yes

CLICKHOUSE_PORT

Clickhouse port

9000

Yes

CLICKHOUSE_DATABASE

Clickhouse database name

ftacs_qoe_ui_data

Yes

CLICKHOUSE_USERNAME

Clickhouse username

ftacs

Yes

CLICKHOUSE_PASSWORD

Clickhouse password

ftacs

Yes

5.4. UI Services Configuration

Variable Description Default Required

HOST

Public hostname for UI access

HOST

Yes

FT_UI_HTTP_PORT

UI Portals HTTP port

8880

Yes

FT_UI_HTTPS_PORT

UI Portals HTTPS port

8843

Yes

FT_UI_BACKEND_HTTP_PORT

Backend API port

8881

Yes

FT_GRAFANA_API_URL

Grafana url for dashboards exporting (http://IP:PORT/)

No

SUPERSET_URL

Superset base URL for dashboard embedding

https://superset.friendly-tech.com

No

SUPERSET_USERNAME

Superset API username for backend authentication

superset

No

SUPERSET_PASSWORD

Superset API password for backend authentication

superset-12345

No

FT_UI_BACKEND_JAVA_RAM

Backend JVM memory settings

-Xms512m -Xmx2g

No

FT_UI_BACKEND_LOG_LEVEL

Backend log level

info

No

FT_UI_BACKEND_KEYWORD

Internal authentication keyword for cross-application communication (see separate-host deployment for details)

ft12Internal%^

Yes

5.5. FT Device Network Configuration

Variable Description Default Required

FT_DEVICE_NETWORK_HTTP_PORT

Service HTTP port

8383

Yes

FT_DEVICE_NETWORK_JAVA_RAM

JVM memory settings

-Xms256m -Xmx1g

No

FT_DEVICE_NETWORK_LOG_LEVEL

Log level

info

No

5.6. AI Agent Configuration

Variable Description Default Required

POSTGRES_HOST

PostgreSQL hostname (internal)

postgres

Yes

POSTGRES_PORT

PostgreSQL port

5432

Yes

POSTGRES_DB

PostgreSQL database name

ftl_ai

Yes

POSTGRES_USER

PostgreSQL username

postgres

Yes

POSTGRES_PASSWORD

PostgreSQL password

postgres

Yes

GOOGLE_API_KEY

Google API key for AI features

-

Yes

FTL_REQUESTS_TIMEOUT_IN_SEC

API request timeout in seconds

60

No

FTL_COMMANDS_TIMEOUT_IN_SEC

Device command timeout in seconds

180

No

TOTAL_MAX_TOKENS

Maximum tokens for LLM

5000

No

MAX_AUDIO_SIZE_IN_BYTES

Maximum audio file size

5242880 (5MB)

No

DB_MIN_POOL_SIZE

Minimum db pool size

10

Yes

DB_MAX_POOL_SIZE

Maximum db pool size

1000

Yes

MAIN_AGENT_MODEL

Model used by the main conversational agent

gemini-flash-latest

No

MAIN_AGENT_TEMPERATURE

Sampling temperature for the main agent

0.7

No

DISCOVERY_AGENT_MODEL

Model used by the discovery agent

gemini-flash-lite-latest

No

DISCOVERY_AGENT_TEMPERATURE

Sampling temperature for the discovery agent

1.0

No

DISCOVERY_AGENT_GLOBAL_TOOL_CALL_LIMIT

Maximum total tool calls the discovery agent may make

10

No

SUMMARIZATION_MODEL

Model used for conversation summarization

gemini-flash-lite-latest

No

SUMMARIZATION_TEMPERATURE

Sampling temperature for summarization

0.7

No

TITLE_MODEL

Model used for generating conversation titles

gemini-flash-lite-latest

No

TITLE_TEMPERATURE

Sampling temperature for title generation

0.7

No

INTERCEPTION_NODE_MODEL

Model used by the interception node

gemini-flash-lite-latest

No

INTERCEPTION_NODE_TEMPERATURE

Sampling temperature for the interception node

0.7

No

SUPERVISOR_NODE_MODEL

Model used by the supervisor node

gemini-flash-lite-latest

No

SUPERVISOR_NODE_TEMPERATURE

Sampling temperature for the supervisor node

0.7

No

6. Deployment

6.1. Registry Authentication

All images of this group are pulled from hub.friendly-tech.com. Authenticate once per host before the first docker compose up:

docker login hub.friendly-tech.com

Enter the read-only pull credentials when prompted:

Field Value

Username

readonly

Password

fokxuw-fymte1-taSxyc

The readonly account provides pull-only access to the published images. It cannot push. For hosts without registry access, skip this step and use Offline Servers.

6.2. Deploy Services

docker compose --env-file .env.mysql up -d

OR

docker compose --env-file .env.oracle up -d

6.3. Offline Servers

When the target server has no access to the Harbor registry, every image referenced in compose.yml must be pulled on a machine that does have Harbor access, exported to a tar archive, transferred to the offline server, and loaded there.

An explicit --platform matching the offline target server’s architecture is required. The images in Harbor are multi-arch (linux/amd64, linux/arm64); without --platform, docker pull selects the host architecture, which may not match the target. For example, on an Apple Silicon (arm64) Mac without --platform, the resulting archive will be arm64 and will fail with a platform does not match warning on amd64 servers. The examples use linux/amd64; replace it with the platform of your offline target server (linux/arm64, etc.).

  1. Identify the images referenced in your compose.yml. For the all-in-one deployment they are:

    • hub.friendly-tech.com/ui/backend:<version>

    • hub.friendly-tech.com/ui/portals:<version>

    • hub.friendly-tech.com/ftacs/ft-device-network-service:<version>

    • hub.friendly-tech.com/ui/ai-agent:<version>

      Replace <version> with the tag pinned in your compose.yml.

  2. On a machine with Harbor access, log in:

    docker login hub.friendly-tech.com
  3. Pull every image for the target server’s architecture:

    docker pull --platform linux/amd64 hub.friendly-tech.com/ui/backend:<version>
    docker pull --platform linux/amd64 hub.friendly-tech.com/ui/portals:<version>
    docker pull --platform linux/amd64 hub.friendly-tech.com/ftacs/ft-device-network-service:<version>
    docker pull --platform linux/amd64 hub.friendly-tech.com/ui/ai-agent:<version>
  4. Save each image to a tar archive:

    docker save hub.friendly-tech.com/ui/backend:<version>            -o backend-<version>.tar
    docker save hub.friendly-tech.com/ui/portals:<version>            -o portals-<version>.tar
    docker save hub.friendly-tech.com/ftacs/ft-device-network-service:<version>  -o ft-device-network-<version>.tar
    docker save hub.friendly-tech.com/ui/ai-agent:<version>           -o ai-agent-<version>.tar
  5. Compress each archive:

    gzip backend-<version>.tar
    gzip portals-<version>.tar
    gzip ft-device-network-<version>.tar
    gzip ai-agent-<version>.tar
  6. Transfer all four *.tar.gz archives to the offline server (e.g., via scp or removable media).

  7. On the offline server, load each archive:

    gzip -dc backend-<version>.tar.gz            | docker load
    gzip -dc portals-<version>.tar.gz            | docker load
    gzip -dc ft-device-network-<version>.tar.gz  | docker load
    gzip -dc ai-agent-<version>.tar.gz           | docker load
  8. Start (or restart) services:

    docker compose --env-file .env.mysql up -d

The same flow applies to upgrades — pull the new image tags on the connected machine, save and transfer the archives, load them on the offline server, then run docker compose up -d to recreate containers with the new images. See Update Services for the full upgrade procedure.

6.4. Verify Deployment

Check service health:

docker compose ps

All services should show status as healthy or running.

7. Service Startup Order

Services start in the following order with health checks:

  1. PostgreSQL - Database for AI Agent

  2. UI Backend - REST API service (waits for DB)

  3. UI Portals - Web interface (waits for backend)

  4. FT Device Network - Device management service (independent start)

  5. AI Agent - AI service (waits for PostgreSQL, UI Backend, and FT Device Network)

8. Service Access

After successful deployment, access services at:

Service URL Description

UI Portals

http://<FT_UI_HOST>:8880

Main web interface

UI Backend API

http://<FT_UI_HOST>:8881/iot-webservice/swagger-ui/index.html

API documentation

FT Device Network

http://<FT_UI_HOST>:8383/api/actuator/health

Health check endpoint

AI Agent

http://<FT_UI_HOST>:8882

AI agent service

9. Port Reference

The following ports are exposed on the host:

Port Service Protocol Configurable Via

8880

UI Portals (Nginx)

HTTP

FT_UI_HTTP_PORT

8843

UI Portals (Nginx)

HTTPS

FT_UI_HTTPS_PORT

8881

UI Backend (Spring Boot)

HTTP

FT_UI_BACKEND_HTTP_PORT

8383

FT Device Network (Spring Boot)

HTTP

FT_DEVICE_NETWORK_HTTP_PORT

To verify ports are listening:

netstat -tlnp | grep -E '8880|8881|8383|8882'
# or
ss -tlnp | grep -E '8880|8881|8383|8882'

10. Troubleshooting

10.1. Check Service Logs

# All services
docker compose logs -f

# Specific service
docker compose logs -f ui-backend
docker compose logs -f portals
docker compose logs -f ft-device-network-service
docker compose logs -f ui-ai-agent
docker compose logs -f postgres

10.2. Common Issues

10.2.1. Services Not Starting

Check if all external dependencies are accessible:

# Test database connection
telnet <DB_HOST> 3306    # MySQL
telnet <DB_HOST> 1521    # Oracle

# Test Hazelcast
telnet <HAZEL_HOST> 5701

# Test FTACS
curl http://<FTACS_HOST>:8080

# Test Clickhouse
telnet <CLICKHOUSE_HOST> 9000

10.2.2. Health Check Failing

Wait for services to fully initialize. Health checks run every 10-30 seconds:

docker compose ps

If a service remains unhealthy after 5 minutes, check its logs.

10.2.3. Port Already in Use

If ports are already in use, modify port mappings in .env.mysql or .env.oracle:

FT_UI_HTTP_PORT=8880
FT_UI_HTTPS_PORT=8843
FT_UI_BACKEND_HTTP_PORT=8881
FT_DEVICE_NETWORK_HTTP_PORT=8383

10.3. Restart Services

# Restart all
docker compose restart

# Restart specific service
docker compose restart ui-backend

11. Stack Management

11.1. Update Services

Pull latest images and restart:

# Pull latest images
docker compose pull

For servers without Harbor access, replace the docker compose pull step with the manual image transfer flow described in Offline Servers. After loading the new archives, run docker compose up -d as shown below to recreate containers with the new images.

# Restart with new images
docker compose --env-file .env.mysql up -d

OR

# Restart with new images
docker compose --env-file .env.oracle up -d

11.2. Force Repull Images

Force Docker to pull fresh images (ignores cache):

# Stop services
docker compose down

# Remove existing images
docker compose pull --ignore-pull-failures

# Or remove images manually
docker images | grep "hub.friendly-tech.com" | awk '{print $3}' | xargs docker rmi -f
# Start with fresh images
docker compose --env-file .env.mysql up -d

OR

# Start with fresh images
docker compose --env-file .env.oracle up -d

11.3. Stop Services

# Stop services (keeps data)
docker compose down

# Stop services and remove all data (WARNING: deletes all persistent data)
docker compose down -v

# Remove specific volumes only
docker volume rm ft-ui-services_postgres_data

11.4. Backup PostgreSQL

docker compose exec postgres pg_dump -U postgres ftl_ai > backup_$(date +%Y%m%d).sql

11.5. View Resource Usage

docker stats

12. Production Checklist

  • Change all default passwords in the env file: DB_PASSWORD, CLICKHOUSE_PASSWORD, POSTGRES_PASSWORD, and FT_UI_BACKEND_KEYWORD.

  • Set FT_UI_HOST to the address end-user browsers actually reach — not localhost.

  • Pin explicit image tags in compose.yml rather than latest, so a restart cannot silently change the deployed version.

  • Confirm the external components are reachable: MySQL/Oracle, Hazelcast, FTACS, and ClickHouse.

  • Configure firewall rules — publish only the ports listed in Port Reference, and restrict database access to this host.

  • Enable auto-restart — restart: unless-stopped for every service in compose.yml.

  • Configure TLS — see SSL / HTTPS Configuration.

  • Set up backups — ui-backend/config/ and the PostgreSQL dump (see Backup PostgreSQL); the MySQL/Oracle database has its own backup strategy.

  • Tune the JVM — FT_UI_BACKEND_JAVA_RAM and FT_DEVICE_NETWORK_JAVA_RAM to match host memory.

  • Protect the AI Agent credentials — GOOGLE_API_KEY and the mounted service-account key file.