Separate Web Console from Admin Control Plane
Context
Prism's administrative functionality has two distinct concerns:
-
Control Plane (prism-admin): gRPC-based control plane for:
- Raft-based HA cluster coordination
- Namespace management state machine
- Proxy/launcher registration and heartbeats
- Backend provisioning and configuration
- Serves as the source of truth for cluster state
-
Web Console (planned): Browser-based UI for:
- Human-friendly namespace management
- Session monitoring dashboards
- Backend health visualization
- Operational tasks through web forms
Current State:
prism-adminis implemented as a gRPC control plane server (RFC-038)- No web console implementation exists yet
- Two RFCs propose different web console approaches:
- ADR-028: FastAPI + gRPC-Web + Vanilla JavaScript (Python-based)
- RFC-036: templ + htmx + Gin (Go-based)
Problem: Combining the web console with the control plane in a single process would:
- Mix critical cluster coordination logic with UI rendering
- Create tight coupling between control plane and UI technology choices
- Make independent scaling difficult (UI vs control plane load)
- Increase control plane container size and startup time
- Complicate testing (need to test both control plane and UI together)
Decision
Create prism-web-console as a separate Go process that communicates with prism-admin via gRPC.
Architecture
┌─────────────────────────────────────────────────┐
│ Browser │
│ ┌──────────────────────────────────────────┐ │
│ │ Web UI (HTML/CSS/JS) │ │
│ │ - Namespace management │ │
│ │ - Session monitoring │ │
│ │ - Health dashboard │ │
│ └────────────┬─────────────────────────────┘ │
│ │ HTTP (htmx AJAX) │
└───────────────┼─────────────────────────────────┘
│
┌───────────────▼─────────────────────────────────┐
│ prism-web-console (:8000) │
│ - Gin HTTP server │
│ - templ templates (HTML rendering) │
│ - htmx integration │
│ - OIDC authentication │
│ └────────────┬────────────────────────────────┘│
│ │ gRPC │
└───────────────┼──────────────────────────────────┘
│
┌───────────────▼──────────────────────────────────┐
│ prism-admin (:8981) │
│ - Control Plane gRPC API │
│ - Raft consensus cluster │
│ - Namespace state machine │
│ - Proxy/Launcher coordination │
└──────────────────────────────────────────────────┘
Implementation Approach
Follow RFC-036's Go-based stack:
- Gin: HTTP routing and middleware
- templ: Type-safe HTML templates (to be added)
- htmx: HTML over the wire interactions
- Tailwind CSS: Styling
Rationale
Why Separate Processes?
-
Separation of Concerns
- Control plane focuses on cluster coordination and state management
- Web console focuses on UI rendering and user interactions
- Each can evolve independently
-
Independent Scaling
- Control plane scales based on cluster size and request rate
- Web console scales based on number of admin users
- Different resource requirements (CPU, memory)
-
Technology Flexibility
- Control plane stays lean and focused on gRPC
- Web console can use web-optimized frameworks without affecting control plane
- Can switch UI framework without touching control plane code
-
Simpler Testing
- Control plane tests focus on gRPC APIs and Raft logic
- Web console tests focus on UI rendering and user flows
- No need to mock UI components in control plane tests
-
Container Efficiency
- Control plane: ~15-20MB (Go binary only)
- Web console: ~20-30MB (Go binary + static assets)
- Combined would be 35-50MB but with mixed responsibilities
Why Go-based (RFC-036) over Python-based (ADR-028)?
-
Language Consolidation
- All admin tooling in Go: prismctl, prism-admin, prism-web-console
- No Python runtime dependency for web console
- Shared code and patterns across admin tools
-
Type Safety
- templ provides compile-time template validation
- Go's type system catches errors early
- Better IDE support and refactoring
-
Performance
- 20-40x faster startup (<50ms vs 1-2s)
- Lower memory usage (20-30MB vs 50-100MB)
- Better suited for container environments
-
Deployment
- Smaller container images (15-20MB vs 100-150MB)
- Single binary deployment
- No Python package dependency management
Consequences
Positive
- Clean Architecture: Clear separation between control plane and UI
- Independent Evolution: Control plane and UI can be versioned separately
- Flexible Scaling: Scale control plane and UI independently based on load
- Simplified Testing: Each component has focused test suites
- Language Consistency: All admin tooling in Go
- Container Efficiency: Smaller, faster containers
Negative
- Additional Process: Need to deploy and manage two processes instead of one
- Network Hop: Web console → control plane adds latency (mitigated by local gRPC)
- Configuration: Need to configure web console endpoint separately
Neutral
- Deployment Options: Can still deploy both in same pod/VM if desired
- Development: Requires running two processes during development (docker-compose simplifies this)
Implementation Plan
Phase 1: Foundation (Week 1)
- ✅ Create
cmd/prism-web-consoledirectory structure - ✅ Implement basic Gin server with health check
- ✅ Add Makefile auto-discovery support
- ✅ Create placeholder handlers and middleware
- ✅ Document separation decision (this ADR)
Phase 2: Core UI (Week 2-3)
- Add templ template support
- Implement namespace CRUD handlers
- Connect to prism-admin gRPC API
- Add htmx interactions
- Basic styling with Tailwind CSS
Phase 3: Authentication (Week 4)
- Integrate OIDC authentication (RFC-010)
- Session management
- JWT validation middleware
- Login/logout flows
Phase 4: Advanced Features (Week 5-6)
- Session monitoring dashboard
- Backend health visualization
- Real-time updates (htmx polling or WebSocket)
- User testing and feedback
Phase 5: Production Readiness (Week 7-8)
- Security audit
- Load testing
- Documentation
- Docker deployment
- CI/CD integration
Deployment Examples
Docker Compose
services:
prism-admin:
image: prism/admin:latest
ports:
- "8981:8981" # gRPC Control Plane
environment:
- PRISM_CLUSTER_NODE_ID=1
- PRISM_CLUSTER_PEERS=1=localhost:8990
prism-web-console:
image: prism/web-console:latest
ports:
- "8000:8000" # HTTP Web UI
environment:
- PRISM_ADMIN_ENDPOINT=prism-admin:8981
- PRISM_LOGGING_LEVEL=info
depends_on:
- prism-admin
Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: prism-web-console
spec:
replicas: 2 # Scale UI independently
template:
spec:
containers:
- name: web-console
image: prism/web-console:latest
ports:
- containerPort: 8000
env:
- name: PRISM_ADMIN_ENDPOINT
value: prism-admin:8981
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: prism-admin
spec:
replicas: 3 # Raft cluster
template:
spec:
containers:
- name: admin
image: prism/admin:latest
ports:
- containerPort: 8981 # gRPC
- containerPort: 8990 # Raft
Alternatives Considered
Alternative 1: Embed Web Console in prism-admin
Pros:
- Single process to deploy
- No network hop between UI and control plane
Cons:
- Mixed responsibilities (control plane + UI)
- Cannot scale independently
- Tighter coupling between control plane and UI
- Larger container image
Decision: Rejected - Separation provides better architecture
Alternative 2: Python-based Web Console (ADR-028)
Pros:
- FastAPI is mature and well-documented
- gRPC-Web enables browser communication
Cons:
- Language fragmentation (Python + Go)
- Larger container (100-150MB vs 15-20MB)
- Slower startup (1-2s vs <50ms)
- Different testing infrastructure
Decision: Rejected in favor of Go-based approach (RFC-036)
Alternative 3: Static SPA (React/Vue/Angular)
Pros:
- Rich client-side interactions
- Large ecosystem and tooling
Cons:
- Build complexity
- Large bundle size (100KB+)
- Overkill for admin CRUD operations
- Requires gRPC-Web proxy
Decision: Rejected - htmx provides sufficient interactivity for admin UI
References
- RFC-036: Minimalist Web Framework for Prism Admin UI
- RFC-038: Admin Leader Election with Hashicorp Raft
- ADR-028: Admin UI with FastAPI and gRPC-Web
- ADR-027: Admin API via gRPC
- RFC-010: Admin Protocol with OIDC Authentication
Revision History
- 2025-10-22: Initial ADR for web console separation decision