Skip to content
Introducing Aletyx Decision Control — Enterprise decision management with governance and multi-environment deployment ×

Aletyx Decision Control Tower Setup Guide

This guide covers deploying Aletyx Decision Control Tower in your Kubernetes cluster.

Prerequisites

Before deploying Aletyx Decision Control Tower, ensure you have:

  • Kubernetes cluster with Decision Control environments deployed
  • Keycloak configured with the aletyx realm
  • Governance API running
  • DNS entries for Aletyx Decision Control Tower hostname

Architecture

Aletyx Decision Control Tower deployment includes:

graph TB
    subgraph "Aletyx Decision Control Tower Stack"
        LP[Landing Page<br/>nginx]
        GOV[Governance API<br/>Node.js]
        DB[(Governance DB<br/>PostgreSQL)]
    end

    subgraph "Existing Infrastructure"
        KC[Keycloak]
        DC[Decision Control<br/>Environments]
    end

    LP --> GOV
    LP --> KC
    LP --> DC
    GOV --> DB
    GOV --> KC
    GOV --> DC

    style LP fill:#90EE90
    style GOV fill:#FFB6C1

Step 1: Deploy Governance Database

Create PostgreSQL for governance data:

# governance-database.yaml
apiVersion: v1
kind: Secret
metadata:
  name: postgres-governance-secret
  namespace: prod
type: Opaque
stringData:
  POSTGRES_USER: governance_user
  POSTGRES_PASSWORD: CHANGE_ME_SECURE_PASSWORD
  POSTGRES_DB: governance_db
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres-governance
  namespace: prod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres-governance
  template:
    metadata:
      labels:
        app: postgres-governance
    spec:
      containers:
      - name: postgres
        image: postgres:15-alpine
        ports:
        - containerPort: 5432
        env:
        - name: POSTGRES_USER
          valueFrom:
            secretKeyRef:
              name: postgres-governance-secret
              key: POSTGRES_USER
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgres-governance-secret
              key: POSTGRES_PASSWORD
        - name: POSTGRES_DB
          valueFrom:
            secretKeyRef:
              name: postgres-governance-secret
              key: POSTGRES_DB
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
      volumes:
      - name: postgres-storage
        persistentVolumeClaim:
          claimName: postgres-governance-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: postgres-governance
  namespace: prod
spec:
  selector:
    app: postgres-governance
  ports:
  - port: 5432
    targetPort: 5432

Apply:

kubectl apply -f governance-database.yaml

Step 2: Deploy Governance API

Create the Governance API backend:

# governance-api.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: governance-api
  namespace: prod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: governance-api
  template:
    metadata:
      labels:
        app: governance-api
    spec:
      containers:
      - name: governance-api
        image: registry-keystone.aletyx.services/governance-api:1.1.7
        ports:
        - containerPort: 3001
        env:
        - name: PORT
          value: "3001"
        - name: DB_HOST
          value: postgres-governance
        - name: DB_PORT
          value: "5432"
        - name: DB_NAME
          value: governance_db
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: postgres-governance-secret
              key: POSTGRES_USER
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgres-governance-secret
              key: POSTGRES_PASSWORD
        - name: KEYCLOAK_URL
          value: https://keycloak.your-domain.com
        - name: KEYCLOAK_REALM
          value: aletyx
        resources:
          requests:
            cpu: 500m
            memory: 512Mi
          limits:
            cpu: 1000m
            memory: 1Gi
---
apiVersion: v1
kind: Service
metadata:
  name: governance-api
  namespace: prod
spec:
  selector:
    app: governance-api
  ports:
  - port: 3001
    targetPort: 3001
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: governance-api-ingress
  namespace: prod
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://control-tower.your-domain.com"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - governance-api.your-domain.com
    secretName: governance-api-tls
  rules:
  - host: governance-api.your-domain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: governance-api
            port:
              number: 3001

Apply:

kubectl apply -f governance-api.yaml

Step 3: Create Environment Configuration

Create the environment configuration ConfigMap:

# Create config.json
cat <<EOF > config.json
{
  "environments": {
    "dev": {
      "name": "Development",
      "baseUrl": "https://decision-control-dev.your-domain.com",
      "enabled": true,
      "features": {
        "submitForReview": true,
        "governance": true
      },
      "apis": {
        "units": "/api/runtime/units",
        "versions": "/api/runtime/units/{unitId}/versions",
        "models": "/api/runtime/units/{unitId}/versions/{versionId}/models",
        "health": "/actuator/health"
      }
    },
    "test": {
      "name": "Testing",
      "baseUrl": "https://decision-control-test.your-domain.com",
      "enabled": true,
      "features": {
        "submitForReview": true,
        "governance": true
      }
    },
    "prod": {
      "name": "Production",
      "baseUrl": "https://decision-control-prod.your-domain.com",
      "enabled": true,
      "features": {
        "submitForReview": false,
        "governance": true
      }
    }
  },
  "governance": {
    "apiUrl": "https://governance-api.your-domain.com",
    "workflow": {
      "submitForReview": ["BUSINESS_ANALYST"],
      "riskApproval": ["RISK_MANAGER"],
      "complianceApproval": ["COMPLIANCE"],
      "promoteToProduction": ["OPERATOR"]
    }
  },
  "keycloak": {
    "url": "https://keycloak.your-domain.com",
    "realm": "aletyx",
    "clientId": "decision-control-ui"
  }
}
EOF

# Create ConfigMap
kubectl create configmap environment-config \
  --from-file=config.json \
  --namespace=prod

Step 4: Deploy Landing Page

Deploy the Aletyx Decision Control Tower landing page:

# control-tower.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: control-tower
  namespace: prod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: control-tower
  template:
    metadata:
      labels:
        app: control-tower
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        volumeMounts:
        - name: landing-page
          mountPath: /usr/share/nginx/html
        - name: environment-config
          mountPath: /usr/share/nginx/html/environments
      volumes:
      - name: landing-page
        configMap:
          name: control-tower-landing
      - name: environment-config
        configMap:
          name: environment-config
---
apiVersion: v1
kind: Service
metadata:
  name: control-tower
  namespace: prod
spec:
  selector:
    app: control-tower
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: control-tower-ingress
  namespace: prod
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - control-tower.your-domain.com
    secretName: control-tower-tls
  rules:
  - host: control-tower.your-domain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: control-tower
            port:
              number: 80

Apply:

kubectl apply -f control-tower.yaml

Step 5: Configure Keycloak

Ensure Keycloak has the required roles:

Required Realm Roles

Create these roles in the aletyx realm:

  • decision-control-dev-users - Business Analysts
  • decision-control-risk-manager - Risk Managers
  • decision-control-compliance - Compliance Officers
  • decision-control-prod-users - Operations Managers
  • decision-control-admin - Administrators

Client Configuration

Update the decision-control-ui client:

  • Valid redirect URIs: Add https://control-tower.your-domain.com/*
  • Web origins: Add https://control-tower.your-domain.com

Step 6: Verify Deployment

Check all components are running:

# Check pods
kubectl get pods -n prod | grep -E "control-tower|governance"

# Expected output:
# control-tower-xxx         1/1     Running   0
# governance-api-xxx        1/1     Running   0
# postgres-governance-xxx   1/1     Running   0

Test endpoints:

# Landing page
curl -I https://control-tower.your-domain.com

# Governance API
curl https://governance-api.your-domain.com/health

Step 7: First Login

  1. Navigate to https://control-tower.your-domain.com
  2. You'll be redirected to Keycloak for authentication
  3. Log in with a user that has one of the Decision Control roles
  4. You should see the Aletyx Decision Control Tower dashboard

Updating Configuration

To update environment configuration:

# Delete existing ConfigMap
kubectl delete configmap environment-config -n prod

# Create updated ConfigMap
kubectl create configmap environment-config \
  --from-file=config.json \
  --namespace=prod

# Restart Aletyx Decision Control Tower to pick up changes
kubectl rollout restart deployment/control-tower -n prod

Troubleshooting

Cannot Log In

  1. Verify Keycloak is accessible
  2. Check client redirect URIs include Aletyx Decision Control Tower URL
  3. Verify user has a Decision Control role

Environments Not Loading

  1. Check environment URLs are accessible
  2. Verify CORS is configured on Governance API
  3. Check browser console for errors

Tasks Not Appearing

  1. Verify Governance API is running
  2. Check database connectivity
  3. Ensure user has correct role

Next Steps