Work Package: Backend Core
Channel: #ai-dev-gateway-backend
Session: Session 2 (Backend Core)
Namespace: ai-dev-gateway-backend-lab
Estimated Duration: 5-7 days
Dependencies: API Contract v1.0.0
Objective
Build the backend orchestration that manages OpenCode sessions, BMAD routing, workspace initialization, deployment, and testing.
Deliverables
1. FastAPI Service Structure
File: services/gateway/src/main.py
- FastAPI app initialization
- API router configuration
- Middleware (CORS, auth, logging)
- Health check endpoint
- OpenAPI spec generation
Endpoints:
GET /health- Health checkGET /docs- OpenAPI documentation
2. Session Manager
File: services/gateway/src/core/session_manager.py
- Create session (with workspace init)
- Get session status
- List active sessions
- Send message to session
- Close/pause session
OpenCode Integration:
class SessionManager:
async def create_session(self, category, project, repos):
# 1. Initialize workspace: task builder:init BUILDER_NAME=... REPOS=...
# 2. Start OpenCode session: opencode serve --session <id>
# 3. Store session state in git
async def send_message(self, session_id, message):
# opencode run --session <id> "message"
async def capture_output(self, session_id):
# Stream output from OpenCode
# Parse for questions, progress, etc.3. BMAD Router
File: services/gateway/src/core/bmad_router.py
- Analyze task complexity
- Generate routing suggestion with confidence
- Route to architect/PM/builder/party-mode
- Handle routing confirmation
Complexity Analysis:
class BMADRouter:
def analyze_complexity(self, task_title, task_description):
# Analyze for:
# - Security keywords → architect
# - Business logic → PM
# - Simple implementation → builder
# - Complex/unknown → party-mode
return {
"suggested": "architect",
"confidence": 0.85,
"reason": "Security-sensitive feature..."
}4. Workspace Manager
File: services/gateway/src/core/workspace_manager.py
- Initialize workspace with git worktrees
- Invoke
task builder:init BUILDER_NAME=... REPOS=... - Create workspace directory structure
- Store workspace metadata
Directory Structure:
.builders/
└── {category}-{project}/
├── repos/
│ ├── repo1/ # git worktree
│ └── repo2/ # git worktree
├── .session-state.yaml
└── arch-decisions.md
5. Deployment Orchestrator
File: services/gateway/src/deployment/orchestrator.py
- Generate deployment plan
- Request confirmation via webhook
- Execute deployment on confirmation
- Stream progress via SSE
- Run tests after deployment
Deployment Flow:
class DeploymentOrchestrator:
async def request_deployment(self, session_id, branch):
# 1. Generate deployment plan
# 2. Send webhook to Slack for confirmation
# 3. Wait for confirmation
async def execute_deployment(self, deployment_id):
# 1. Create namespace
# 2. Create ConfigMaps/PVCs
# 3. Apply kustomize
# 4. Setup ingress
# 5. Wait for pods ready
# 6. Run tests
# 7. Stream all progress via SSE6. Namespace Manager
File: services/gateway/src/deployment/namespace_manager.py
- Create namespace per builder
- Setup RBAC
- Delete namespace (with lifecycle options)
- List active namespaces
K8s Operations:
class NamespaceManager:
async def create_namespace(self, project_id):
namespace = f"{project_id}-lab"
# kubectl create namespace {namespace}
# Apply RBAC
async def delete_namespace(self, namespace, after_days=None):
# Immediate or scheduled deletion7. Manifest Manager
File: services/gateway/src/deployment/manifest_manager.py
- Create ConfigMaps from code files
- Create PVCs for larger files
- Generate kustomize overlays
- Apply manifests with kubectl
Fast Deployment:
class ManifestManager:
async def deploy_code_via_configmap(self, namespace, code_files):
# Small files → ConfigMap
# Large files → PVC
# Mount in pods
# Use uv/camel-jbang to run8. Ingress Manager
File: services/gateway/src/deployment/ingress_manager.py
- Create ingress for namespace
- Setup domain:
<project>.builder.lab.ctoaas.co - Configure TLS (cert-manager)
- Return lab URL
9. Test Orchestrator
File: services/gateway/src/deployment/test_orchestrator.py
- Run unit tests (pytest from session)
- Run integration tests (against lab URL)
- Run acceptance tests (critical flows)
- Aggregate and format results
Test Execution:
class TestOrchestrator:
async def run_all_tests(self, session_id, lab_url):
unit = await self.run_unit_tests(session_id)
integration = await self.run_integration_tests(session_id, lab_url)
acceptance = await self.run_acceptance_tests(session_id, lab_url)
return {
"unit": unit,
"integration": integration,
"acceptance": acceptance,
"all_passing": all([unit.passed, integration.passed, acceptance.passed])
}10. OpenCode Bridge
File: services/gateway/src/integrations/opencode_bridge.py
- Spawn OpenCode sessions
- Send messages to sessions
- Capture and parse output
- Detect questions and progress
OpenCode CLI Integration:
class OpenCodeBridge:
async def spawn_session(self, session_id, workspace_path):
# opencode serve --session {session_id} --project {workspace_path}
async def send_message(self, session_id, message):
# opencode run --session {session_id} "{message}"
async def capture_output(self, session_id):
# Stream and parse output
# Detect: questions, progress, completions11. Webhook Client
File: services/gateway/src/integrations/webhook_client.py
- Send events to Slack webhook
- Retry logic
- Event queue for reliability
Events:
- Progress updates
- Questions
- Deployment ready
- Test results
12. SSE Endpoint for Deployment Progress
File: services/gateway/src/api/deployments.py
- SSE stream for deployment progress
- Event types: progress, step_complete, test_results, complete
- Handle client disconnections
@router.get("/api/deployments/{deployment_id}/progress")
async def deployment_progress(deployment_id: str):
async def event_stream():
async for event in deployment_service.stream_progress(deployment_id):
yield {
"event": event.type,
"data": json.dumps(event.data)
}
return EventSourceResponse(event_stream())Testing Strategy
Unit Tests
Directory: services/gateway/tests/core/
- Session manager (mock OpenCode CLI)
- BMAD router (complexity analysis)
- Workspace initialization (mock subprocess)
- Deployment orchestrator (mock K8s)
Integration Tests
Directory: services/gateway/tests/integration/
- Full workflow with mock Slack
- Deployment pipeline with mock K8s
- Test orchestrator with mock pytest
Mocking:
Use api-contract.md to create mock Slack webhook.
Development Environment
Local Setup
# Install dependencies
cd repos/ai-dev/services/gateway
uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
# Run locally
uvicorn src.main:app --reload --port 8000
# Access docs
open http://localhost:8000/docsMock Slack Webhook
File: services/gateway/tests/mocks/slack_mock.py
from fastapi import FastAPI
app = FastAPI()
@app.post("/webhook/slack")
async def mock_slack_webhook(payload):
print(f"Received event: {payload['event_type']}")
return {"ok": True}Dependencies
Python Packages
fastapi==0.110.0
uvicorn==0.27.0
kubernetes==28.1.0
pyyaml==6.0.1
httpx==0.26.0
pydantic==2.5.0
sse-starlette==1.8.2External Dependencies
- kubectl (for K8s operations)
- OpenCode CLI (installed)
- Git (for workspace management)
Configuration
File: services/gateway/config/backend.yaml
opencode:
cli_path: /usr/local/bin/opencode
sessions_dir: /workspace/.opencode-sessions
kubernetes:
namespace_prefix: builder
service_account: gateway-sa
ingress_domain: builder.lab.ctoaas.co
deployment:
default_strategy: configmap_pvc
max_configmap_size: 1048576 # 1 MB
test_timeout: 300 # 5 minutes
workspace:
base_path: /workspace/.builders
taskfile_path: /workspace/Taskfile.yaml
webhooks:
slack_url: ${SLACK_WEBHOOK_URL}
retry_attempts: 3
retry_delay: 1000 # msAcceptance Criteria
- Session creation initializes workspace correctly
- OpenCode sessions spawn and accept messages
- BMAD routing provides accurate suggestions
- Deployment creates namespace and applies manifests
- ConfigMap/PVC strategy works for fast deployment
- Ingress creates accessible URLs
- Test orchestrator runs all test types
- SSE streams deployment progress correctly
- Webhook events send to Slack
- All contract endpoints implemented
- Unit tests: 80%+ coverage
- Integration tests: All workflows covered
K8s Setup Required
Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
name: gateway-sa
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gateway-role
rules:
- apiGroups: [""]
resources: ["namespaces", "pods", "services", "configmaps", "persistentvolumeclaims"]
verbs: ["create", "get", "list", "delete", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["create", "get", "list", "delete", "watch"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["create", "get", "list", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gateway-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: gateway-role
subjects:
- kind: ServiceAccount
name: gateway-sa
namespace: defaultNotes
- Contract Compliance: All endpoints must match
api-contract.md - OpenCode CLI: Ensure OpenCode is available and sessions work
- K8s Access: Service needs proper RBAC to create namespaces
- Fast Deployment: Prioritize ConfigMap/PVC over image builds
Handoff to Slack Team
When ready to integrate:
- Deploy backend API to test environment
- Provide API URL to Slack team
- Configure webhook URL for Slack events
- Run contract tests together
- Integration testing in shared environment