Skip to main content

V5 + theia Combined Deployment Architecture

🎯 The Complete Picture

What We're Deploying

┌─────────────────────────────────────────────────────────────────┐
│ │
│ 📦 Single Docker Image: coditect-combined │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ NGINX (Port 80) │ │
│ │ ├─→ GET / → Serves V5 Frontend (HTML/JS/CSS) │ │
│ │ ├─→ GET /theia → Proxies to theia (localhost:3000) │ │
│ │ └─→ WebSocket /theia/services → theia WebSocket │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Node.js Process (Port 3000) │ │
│ │ └─→ Eclipse theia 1.65 │ │
│ │ ├─ Monaco editor │ │
│ │ ├─ terminal (xterm.js) │ │
│ │ ├─ File Explorer │ │
│ │ ├─ AI Chat (with Coditect branding) │ │
│ │ └─ WebSocket Server │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

🌐 User Journey

1. User Visits https://coditect.ai/

User Browser

├─→ GET /
│ └─→ NGINX returns V5 Frontend (index.html)
│ └─→ React SPA loads (Header, Footer, Pages)

└─→ User clicks "workspace" tab
└─→ React renders <iframe src="/theia">

├─→ GET /theia/
│ └─→ NGINX proxies to theia (localhost:3000)
│ └─→ theia returns its HTML/JS
│ └─→ Monaco editor renders in iframe

└─→ WebSocket /theia/services
└─→ NGINX upgrades to WebSocket
└─→ theia handles terminal I/O

📂 What Gets Built

Build Stage 1: V5 Frontend

Input:  src/ (React + TypeScript)
Build: npm run build (Vite)
Output: dist/
├── index.html (0.6 KB)
├── assets/
│ ├── index-*.js (1.2 MB)
│ ├── index-*.css (5 KB)
│ └── logo.png (79 KB)

Build Stage 2: theia Backend

Input:  theia-app/src/ (TypeScript + theia extensions)
Build: npm run prepare (theia CLI)
Output: theia-app/
├── lib/ (compiled backend code)
├── src-gen/ (generated code)
│ └── backend/main.js (theia entry point)
├── plugins/ (VS Code extensions)
└── node_modules/ (runtime dependencies)

Build Stage 3: Combined Runtime

Runtime Image (node:20-slim + NGINX):
├── /app/v5-frontend/ (V5 dist/)
├── /app/theia/ (theia built app)
├── /etc/nginx/sites-available/default (nginx-combined.conf)
└── /start.sh (start both services)

🚀 Deployment Flow

Step-by-Step Process

1. Developer runs: gcloud builds submit --config cloudbuild-combined.yaml

├─→ Cloud Build triggers

2. Cloud Build VM starts (E2_HIGHCPU_8, 8 CPUs, 100GB disk)

├─→ Stage 1: Build V5 Frontend
│ ├─ npm ci (install dependencies)
│ ├─ npm run build (Vite build)
│ └─ Output: dist/ (1.2 MB)
│ ⏱️ ~3 minutes

├─→ Stage 2: Build theia Backend
│ ├─ npm ci (install theia + extensions)
│ │ ⏱️ ~10 minutes (large dependency tree)
│ ├─ npm run prepare (theia build)
│ │ ⏱️ ~15 minutes (webpack compilation)
│ └─ Output: lib/, src-gen/ (~500 MB)
│ ⏱️ ~25 minutes total

├─→ Stage 3: Create Runtime Image
│ ├─ Copy dist/ → /app/v5-frontend/
│ ├─ Copy theia/ → /app/theia/
│ ├─ Install NGINX
│ └─ Copy nginx-combined.conf
│ ⏱️ ~5 minutes

├─→ Push to Artifact Registry
│ └─ us-central1-docker.pkg.dev/.../coditect-combined:$BUILD_ID
│ ⏱️ ~5 minutes

└─→ Deploy to GKE
├─ kubectl apply k8s-combined-deployment.yaml
├─ Create 3 pods
├─ Create ClusterIP service
└─ Update Ingress (route traffic)
⏱️ ~10 minutes

Total Build Time: 60-80 minutes

🔌 How V5 Connects to theia

Current Setup (Development)

// src/components/workspace/workspace-tab.tsx
<iframe
src="http://localhost:3000" // theia dev server
width="100%"
height="100%"
/>

Production Setup (After Deployment)

// V5 Frontend detects it's in production
const theiaUrl = process.env.VITE_THEIA_URL || '/theia'

<iframe
src="/theia" // Same-origin, proxied by NGINX
width="100%"
height="100%"
/>

Why This Works:

  • NGINX receives request for /theia
  • NGINX rewrites /theia/
  • NGINX proxies to localhost:3000 (theia)
  • theia doesn't know it's behind a proxy
  • WebSocket connections work (NGINX upgrades)

🔐 Security Considerations

Network Security

Internet (Port 443)

└─→ Google Cloud Load Balancer (SSL termination)
└─→ GKE Ingress (SSL cert: coditect.ai)
└─→ coditect-combined-service (ClusterIP, internal)
└─→ Pod (Port 80, internal network only)
├─ NGINX (public interface)
└─ theia (localhost:3000, not exposed)

Key Points:

  • ✅ theia is NOT directly exposed to internet
  • ✅ Only NGINX port 80 is accessible (internal to cluster)
  • ✅ SSL/TLS handled by Google Load Balancer
  • ✅ WebSocket connections are encrypted (WSS)

Container Security

securityContext:
runAsNonRoot: false # NGINX needs root to bind port 80
readOnlyRootFilesystem: false # theia writes temp files

To Harden (Future):

  • Run NGINX on port 8080 (non-privileged)
  • Use read-only root filesystem
  • Add AppArmor/SELinux policies

📊 Resource Requirements

Per Pod

Resources:
CPU: 500m request, 1000m limit
Memory: 1Gi request, 2Gi limit
Disk: Ephemeral (no persistent volume needed)

Processes:
- NGINX: ~20 MB RAM, 0.01 CPU
- Node.js (theia): ~800 MB RAM, 0.5-0.8 CPU
- Total: ~820 MB RAM, 0.5-0.8 CPU (under normal load)

Total Cluster (3 Pods)

CPU: 1.5-2.4 cores
Memory: 2.5-3.5 GB
Cost: ~$130/month (us-central1)

🐛 Debugging Checklist

If Frontend Doesn't Load

# 1. Check if pod is running
kubectl get pods | grep coditect-combined

# 2. Check NGINX logs
kubectl logs deployment/coditect-combined | grep nginx

# 3. Check if static files exist
kubectl exec deployment/coditect-combined -- ls -la /app/v5-frontend/

# 4. Test from inside pod
kubectl exec -it deployment/coditect-combined -- curl localhost/

If theia Doesn't Load

# 1. Check if theia process is running
kubectl exec deployment/coditect-combined -- ps aux | grep node

# 2. Check theia logs
kubectl logs deployment/coditect-combined | grep theia

# 3. Test theia from inside pod
kubectl exec -it deployment/coditect-combined -- curl localhost:3000

# 4. Check if plugins loaded
kubectl logs deployment/coditect-combined | grep plugin

If WebSocket Fails

# 1. Check NGINX WebSocket config
kubectl exec deployment/coditect-combined -- cat /etc/nginx/sites-available/default

# 2. Check WebSocket upgrade headers
kubectl logs deployment/coditect-combined | grep -i upgrade

# 3. Test WebSocket from browser console
const ws = new WebSocket('wss://coditect.ai/theia/services');
ws.onopen = () => console.log('Connected!');
ws.onerror = (e) => console.error('Failed:', e);

✅ Success Criteria

Your deployment is successful when:

  1. Frontend loads: https://coditect.ai/ shows V5 UI ✅
  2. theia loads: Click "workspace" tab → theia IDE appears ✅
  3. Monaco editor works: Can edit files ✅
  4. terminal works: Can type commands ✅
  5. File Explorer works: Can browse directories ✅
  6. AI Chat works: Can send messages to llm ✅
  7. WebSocket stable: terminal doesn't disconnect ✅
  8. Health check passes: curl https://coditect.ai/health returns "healthy" ✅

📈 Next Steps After Deployment

  1. Monitor Performance

    • Set up Prometheus metrics
    • Configure Grafana dashboards
    • Set up alerts for downtime
  2. Optimize Build Time

    • Cache npm dependencies
    • Use layer caching in Docker
    • Consider pre-built base images
  3. Implement CI/CD

    • Automate builds on git push
    • Run tests before deployment
    • Blue-green deployment strategy
  4. Add Persistence

    • User workspace files → FoundationDB
    • terminal history → Redis
    • Session state → PostgreSQL
  5. Scale for Production

    • Increase replicas to 10+
    • Add geographic load balancing
    • Implement rate limiting

🎉 Summary

You now have:

Single Docker image containing both V5 and theia ✅ NGINX reverse proxy serving both services ✅ WebSocket support for theia terminal ✅ Auto-scaling from 3-10 pods ✅ Health checks and monitoring ✅ Production-ready deployment on GKE

Deployment command:

gcloud builds submit --config cloudbuild-combined.yaml

Access your app:

That's it! 🚀