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:
- Frontend loads: https://coditect.ai/ shows V5 UI ✅
- theia loads: Click "workspace" tab → theia IDE appears ✅
- Monaco editor works: Can edit files ✅
- terminal works: Can type commands ✅
- File Explorer works: Can browse directories ✅
- AI Chat works: Can send messages to llm ✅
- WebSocket stable: terminal doesn't disconnect ✅
- Health check passes:
curl https://coditect.ai/healthreturns "healthy" ✅
📈 Next Steps After Deployment
-
Monitor Performance
- Set up Prometheus metrics
- Configure Grafana dashboards
- Set up alerts for downtime
-
Optimize Build Time
- Cache npm dependencies
- Use layer caching in Docker
- Consider pre-built base images
-
Implement CI/CD
- Automate builds on git push
- Run tests before deployment
- Blue-green deployment strategy
-
Add Persistence
- User workspace files → FoundationDB
- terminal history → Redis
- Session state → PostgreSQL
-
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:
- https://coditect.ai/ (V5 Frontend)
- https://coditect.ai/theia (theia IDE)
That's it! 🚀