Skip to content

Component Integration

Eric Fitzgerald edited this page Nov 12, 2025 · 1 revision

Component Integration

This guide covers integrating all TMI components to create a complete working system.

Overview

A fully operational TMI deployment consists of:

  • TMI Web Application (Frontend)
  • TMI Server (API Backend)
  • PostgreSQL (Database)
  • Redis (Cache)
  • OAuth Providers (Authentication)
  • Load Balancer/Reverse Proxy (Optional, recommended for production)

Integration Architecture

┌─────────────────┐
│   User Browser  │
└────────┬────────┘
         │ HTTPS
         ↓
┌─────────────────┐
│  Load Balancer  │ (Optional)
│   / Reverse     │
│     Proxy       │
└────┬──────┬─────┘
     │      │
     │      └─────────────┐
     │ HTTPS              │ HTTPS
     ↓                    ↓
┌──────────────┐    ┌────────────────┐
│  TMI Web App │    │  TMI Server    │
│  (Static)    │    │  (API/WebSoc...│
└──────────────┘    └───┬────────┬───┘
                        │        │
                        │ TCP    │ TCP
                        ↓        ↓
                  ┌──────────┐  ┌──────────┐
                  │PostgreSQL│  │  Redis   │
                  └──────────┘  └──────────┘
                        ↓
                  ┌──────────────┐
                  │OAuth Provider│
                  │(Google/GitHub│
                  │ /Microsoft)  │
                  └──────────────┘

Prerequisites

Before integration, ensure you have:

  • TMI server deployed and running
  • TMI web application built and deployed
  • PostgreSQL configured with migrations run
  • Redis configured and running
  • OAuth providers configured
  • DNS records configured (for production)
  • SSL/TLS certificates (for production)

Integration Steps

Step 1: Configure API Connection

The web application needs to know where to find the API server.

Web Application Configuration

Edit src/environments/environment.prod.ts:

export const environment = {
  production: true,
  apiUrl: 'https://api.tmi.example.com',  // Your TMI API server URL
  logLevel: 'ERROR',
  authTokenExpiryMinutes: 60,
  operatorName: 'TMI Operator',
  operatorContact: 'support@example.com',
};

Important: The apiUrl must be accessible from users' browsers. Options:

  1. Separate subdomain (recommended):

    • Web app: https://tmi.example.com
    • API: https://api.tmi.example.com
  2. Same domain, different path:

    • Web app: https://tmi.example.com
    • API: https://tmi.example.com/api
    • Requires reverse proxy to route /api to TMI server
  3. Development:

    • Web app: http://localhost:4200
    • API: http://localhost:8080

CORS Configuration

If web app and API are on different domains, configure CORS in TMI server.

Environment Variable:

WEBSOCKET_ALLOWED_ORIGINS="https://tmi.example.com,https://www.tmi.example.com"

Configuration File (config-production.yml):

server:
  cors:
    allowed_origins:
      - "https://tmi.example.com"
      - "https://www.tmi.example.com"
  websocket:
    allowed_origins:
      - "https://tmi.example.com"
      - "https://www.tmi.example.com"

Step 2: Configure OAuth Flow

OAuth requires coordination between web app, TMI server, and OAuth providers.

OAuth Redirect URIs

Configure redirect URIs in OAuth provider dashboards:

Web Application Callback: https://tmi.example.com/oauth2/callback

This is where users land after authenticating with the provider.

TMI Server OAuth Configuration

Configure the OAuth callback URL that TMI server uses:

Environment Variable:

OAUTH_CALLBACK_URL="https://api.tmi.example.com/oauth2/callback"

Configuration File:

auth:
  oauth:
    callback_url: "https://api.tmi.example.com/oauth2/callback"

Important: The web app handles the user-facing callback, then sends the authorization code to the TMI server's token exchange endpoint.

OAuth Flow Integration

The complete OAuth flow:

  1. User clicks login → Web app redirects to OAuth provider
  2. User authenticates → Provider redirects to web app callback
  3. Web app receives code → Sends code to TMI server
  4. TMI server exchanges code → Gets user info from provider
  5. TMI server issues JWT → Returns tokens to web app
  6. Web app stores tokens → Uses for subsequent API requests

Step 3: Database Integration

Ensure TMI server can connect to PostgreSQL and Redis.

PostgreSQL Connection

Test connection from TMI server:

# From TMI server host
psql -h postgres-host -U tmi_user -d tmi -c "SELECT version();"

Configure TMI server:

POSTGRES_HOST=postgres.example.com
POSTGRES_PORT=5432
POSTGRES_USER=tmi_user
POSTGRES_PASSWORD=secure_password
POSTGRES_DATABASE=tmi
POSTGRES_SSL_MODE=require

Verify migrations:

# Check database schema
go run cmd/check-db/main.go

# Should show all tables present

Redis Connection

Test connection from TMI server:

# From TMI server host
redis-cli -h redis-host -p 6379 -a redis_password ping
# Expected: PONG

Configure TMI server:

REDIS_HOST=redis.example.com
REDIS_PORT=6379
REDIS_PASSWORD=redis_password
REDIS_DB=0

Network Configuration

Ensure TMI server can reach databases:

# Test PostgreSQL connectivity
telnet postgres.example.com 5432

# Test Redis connectivity
telnet redis.example.com 6379

Firewall rules:

  • PostgreSQL: Allow only from TMI server IPs
  • Redis: Allow only from TMI server IPs
  • Do not expose databases to internet

Step 4: Configure Reverse Proxy

A reverse proxy provides SSL termination, load balancing, and routing.

Nginx Configuration

Create /etc/nginx/sites-available/tmi:

# Upstream servers
upstream tmi_api {
    server localhost:8080;
    # Add more servers for load balancing
    # server 10.0.0.11:8080;
    # server 10.0.0.12:8080;
    keepalive 32;
}

# Web application
server {
    listen 443 ssl http2;
    server_name tmi.example.com;

    ssl_certificate /etc/letsencrypt/live/tmi.example.com/fullchain.pem;
    ssl_private_key /etc/letsencrypt/live/tmi.example.com/privkey.pem;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # Web application (static files)
    root /var/www/tmi-ux;
    index index.html;

    # Enable gzip
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;

    # Static assets with long cache
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Angular routing
    location / {
        try_files $uri $uri/ /index.html;
    }
}

# API server
server {
    listen 443 ssl http2;
    server_name api.tmi.example.com;

    ssl_certificate /etc/letsencrypt/live/api.tmi.example.com/fullchain.pem;
    ssl_private_key /etc/letsencrypt/live/api.tmi.example.com/privkey.pem;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000" always;

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req zone=api burst=20 nodelay;

    location / {
        proxy_pass http://tmi_api;
        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;

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Timeouts for WebSocket
        proxy_read_timeout 86400;
        proxy_send_timeout 86400;
    }
}

# HTTP to HTTPS redirect
server {
    listen 80;
    server_name tmi.example.com api.tmi.example.com;
    return 301 https://$server_name$request_uri;
}

Enable configuration:

sudo ln -s /etc/nginx/sites-available/tmi /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Alternative: Combined Domain with Path Routing

For same-domain deployment:

server {
    listen 443 ssl http2;
    server_name tmi.example.com;

    ssl_certificate /etc/letsencrypt/live/tmi.example.com/fullchain.pem;
    ssl_private_key /etc/letsencrypt/live/tmi.example.com/privkey.pem;

    # API routes
    location /api/ {
        rewrite ^/api/(.*) /$1 break;
        proxy_pass http://localhost:8080;
        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;

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    # Web application
    root /var/www/tmi-ux;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

Update web app configuration:

apiUrl: 'https://tmi.example.com/api'

Step 5: SSL/TLS Configuration

Let's Encrypt with Certbot

# Install Certbot
sudo apt install certbot python3-certbot-nginx

# Get certificate for web app
sudo certbot --nginx -d tmi.example.com -d www.tmi.example.com

# Get certificate for API
sudo certbot --nginx -d api.tmi.example.com

# Test renewal
sudo certbot renew --dry-run

Certbot automatically:

  • Obtains certificates
  • Configures nginx
  • Sets up auto-renewal

Manual Certificate Installation

If using custom certificates:

# Copy certificates
sudo cp tmi.example.com.crt /etc/ssl/certs/
sudo cp tmi.example.com.key /etc/ssl/private/
sudo chmod 600 /etc/ssl/private/tmi.example.com.key

Configure in nginx (shown in Step 4).

Step 6: DNS Configuration

Configure DNS records for your domains:

A Records

tmi.example.com       A    203.0.113.10
api.tmi.example.com   A    203.0.113.10

Or use separate IPs:

tmi.example.com       A    203.0.113.10  (web app server)
api.tmi.example.com   A    203.0.113.11  (API server)

CNAME Records (Alternative)

tmi.example.com       A       203.0.113.10
www.tmi.example.com   CNAME   tmi.example.com
api.tmi.example.com   CNAME   tmi.example.com

Verify DNS

# Check DNS resolution
dig tmi.example.com
dig api.tmi.example.com

# Or with nslookup
nslookup tmi.example.com
nslookup api.tmi.example.com

Testing Integration

Step 1: Test API Server

# Health check
curl https://api.tmi.example.com/version

# Expected response:
{
  "version": "1.0.0",
  "build": "2025-11-12",
  "go_version": "1.24"
}

# Check OAuth providers
curl https://api.tmi.example.com/oauth2/providers

# Expected response:
{
  "providers": [
    {"id": "google", "name": "Google", "icon": "google"},
    {"id": "github", "name": "GitHub", "icon": "github"}
  ]
}

Step 2: Test Web Application

# Check if web app loads
curl -I https://tmi.example.com

# Should return 200 OK

# Check static assets
curl -I https://tmi.example.com/main.js

# Should return 200 OK with long cache headers

Step 3: Test OAuth Flow

  1. Open web app in browser: https://tmi.example.com
  2. Click login button
  3. Select OAuth provider (Google/GitHub/Microsoft)
  4. Complete authentication
  5. Verify redirect to application
  6. Check browser console for errors
  7. Verify JWT token received

Step 4: Test API Integration

After logging in:

// In browser console
fetch('https://api.tmi.example.com/threat_models', {
  headers: {
    'Authorization': 'Bearer ' + localStorage.getItem('tmi_access_token')
  }
})
.then(r => r.json())
.then(console.log)

Should return threat models (empty array if none created yet).

Step 5: Test WebSocket Connection

// In browser console (after login)
const ws = new WebSocket('wss://api.tmi.example.com/ws/diagrams/test-id');
ws.onopen = () => console.log('WebSocket connected');
ws.onerror = (error) => console.error('WebSocket error:', error);
ws.onclose = () => console.log('WebSocket closed');

Note: This will fail with 401 if not properly authenticated, but confirms WebSocket endpoint is accessible.

Common Integration Issues

Issue 1: CORS Errors

Symptom: Browser console shows CORS errors when calling API.

Solution:

  1. Verify WEBSOCKET_ALLOWED_ORIGINS includes web app domain
  2. Check API server CORS configuration
  3. Ensure preflight requests are handled

Test CORS:

curl -H "Origin: https://tmi.example.com" \
     -H "Access-Control-Request-Method: GET" \
     -H "Access-Control-Request-Headers: Authorization" \
     -X OPTIONS \
     https://api.tmi.example.com/threat_models

Issue 2: OAuth Redirect Loop

Symptom: After OAuth login, app redirects back to provider repeatedly.

Causes:

  • Redirect URI mismatch in OAuth provider configuration
  • State parameter validation failing
  • Token exchange failing

Debug:

  1. Check browser network tab for failed requests
  2. Verify OAuth redirect URI matches exactly
  3. Check TMI server logs for token exchange errors
  4. Verify OAuth client credentials are correct

Issue 3: WebSocket Connection Fails

Symptom: Real-time collaboration doesn't work.

Solutions:

  1. Check reverse proxy WebSocket configuration
  2. Verify Upgrade and Connection headers are forwarded
  3. Check WebSocket allowed origins
  4. Increase proxy timeouts for long-lived connections

Test WebSocket:

# Test WebSocket endpoint (requires wscat)
npm install -g wscat
wscat -c wss://api.tmi.example.com/ws/diagrams/test-id \
  -H "Authorization: Bearer YOUR_TOKEN"

Issue 4: Database Connection Timeouts

Symptom: API requests fail with database timeout errors.

Solutions:

  1. Check database server is running
  2. Verify firewall allows TMI server to database
  3. Check connection pool settings
  4. Verify database credentials

Test database connection:

# From TMI server host
psql -h postgres-host -U tmi_user -d tmi -c "SELECT 1;"

Issue 5: Static Assets Not Loading

Symptom: Web app loads but shows blank page, missing CSS/JS.

Solutions:

  1. Check nginx static file configuration
  2. Verify file permissions on /var/www/tmi-ux
  3. Check browser console for 404 errors
  4. Verify nginx is serving correct directory

Debug:

# Check files exist
ls -la /var/www/tmi-ux/

# Check nginx error log
sudo tail -f /var/log/nginx/error.log

# Test static file
curl -I https://tmi.example.com/main.js

Security Checklist

After integration, verify security:

  • All traffic uses HTTPS
  • HTTP redirects to HTTPS
  • Security headers configured (CSP, X-Frame-Options, etc.)
  • Database not accessible from internet
  • Redis not accessible from internet
  • OAuth secrets in environment variables, not config files
  • JWT secret is strong and unique
  • Rate limiting configured
  • CORS properly restricted
  • Firewall rules limiting access
  • SSL certificates valid and auto-renewing

Performance Optimization

Connection Keep-Alive

Configure nginx:

upstream tmi_api {
    server localhost:8080;
    keepalive 32;  # Keep connections alive
}

location / {
    proxy_http_version 1.1;
    proxy_set_header Connection "";  # Clear connection header
}

Caching

Configure caching headers:

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

# Don't cache API responses
location /api/ {
    add_header Cache-Control "no-store, no-cache, must-revalidate";
}

Compression

Enable compression in nginx:

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
           application/json application/javascript application/xml+rss;

Monitoring Integration

Set up monitoring for integrated system:

Health Check Endpoints

Create /usr/local/bin/check-tmi-health.sh:

#!/bin/bash

# Check web app
if ! curl -f -s https://tmi.example.com > /dev/null; then
    echo "ERROR: Web app not responding"
    exit 1
fi

# Check API
if ! curl -f -s https://api.tmi.example.com/version > /dev/null; then
    echo "ERROR: API not responding"
    exit 1
fi

# Check database
if ! psql -h postgres-host -U tmi_user -d tmi -c "SELECT 1;" > /dev/null 2>&1; then
    echo "ERROR: Database not responding"
    exit 1
fi

# Check Redis
if ! redis-cli -h redis-host -a password ping > /dev/null 2>&1; then
    echo "ERROR: Redis not responding"
    exit 1
fi

echo "OK: All components healthy"
exit 0

Monitoring Stack

Consider deploying:

  • Prometheus: Metrics collection
  • Grafana: Dashboards and visualization
  • Loki: Log aggregation
  • Alertmanager: Alert routing

Deployment Checklist

Before going live:

Pre-Production

  • All components tested individually
  • Integration tests pass
  • OAuth flow works end-to-end
  • WebSocket connections successful
  • Database migrations complete
  • Redis cache functioning

Production

  • DNS records configured and propagated
  • SSL certificates installed and valid
  • Reverse proxy configured and tested
  • Firewall rules in place
  • Monitoring and alerting active
  • Backup procedures tested
  • Rollback plan documented

Verification

  • Can access web app via domain
  • Can login with OAuth providers
  • Can create threat model
  • Can edit diagrams
  • Real-time collaboration works
  • No errors in browser console
  • No errors in server logs

Next Steps

Related Pages

Clone this wiki locally