# AI Stack Deployer # ***NEVER FORGET THE PRINCIPLES RULES*** > Self-service portal for deploying personal OpenCode AI coding assistant stacks [![Powered by Dokploy](https://img.shields.io/badge/Powered%20by-Dokploy-blue)](https://dokploy.com) [![Built with Bun](https://img.shields.io/badge/Built%20with-Bun-black)](https://bun.sh) [![Hono Framework](https://img.shields.io/badge/Framework-Hono-orange)](https://hono.dev) ## Overview AI Stack Deployer is a production-ready web application that allows users to deploy their own personal AI coding assistant in seconds. Each deployment creates a fully functional OpenCode instance at `{name}.ai.flexinit.nl` with automatic HTTPS via wildcard SSL certificate. ### Key Features - **One-Click Deployment**: Deploy AI stacks with a single form submission - **Real-Time Progress**: SSE-powered live updates during deployment - **Name Validation**: Real-time availability checking and format validation - **Modern UI**: Responsive design with smooth animations - **Production Ready**: Docker containerized with health checks - **No DNS Setup**: Leverages pre-configured wildcard DNS and SSL ## Architecture ``` User Browser ↓ AI Stack Deployer (Hono + Bun) ↓ Dokploy API (10.100.0.20:3000) ↓ Traefik (*.ai.flexinit.nl → 144.76.116.169) ↓ User's AI Stack Container (OpenCode + ttyd) ``` ### Technology Stack - **Runtime**: Bun 1.3+ - **Framework**: Hono 4.11.3 - **Language**: TypeScript - **Container**: Docker with multi-stage builds - **Orchestration**: Dokploy - **Reverse Proxy**: Traefik with wildcard SSL ## Quick Start ### Prerequisites - Bun 1.3 or higher - Docker (for containerized deployment) - Valid Dokploy API token - Access to Dokploy instance at `http://10.100.0.20:3000` ### Local Development 1. **Clone and Install**: ```bash git clone cd ai-stack-deployer bun install ``` 2. **Configure Environment**: ```bash cp .env.example .env # Edit .env and add your DOKPLOY_API_TOKEN ``` 3. **Run Development Server**: ```bash bun run dev ``` 4. **Access the Application**: Open http://localhost:3000 in your browser ### Production Deployment #### Option 1: Docker Compose (Recommended) ```bash # Build and run docker-compose up -d # View logs docker-compose logs -f # Stop docker-compose down ``` #### Option 2: Manual Docker ```bash # Build docker build -t ai-stack-deployer:latest . # Run docker run -d \ --name ai-stack-deployer \ -p 3000:3000 \ --env-file .env \ ai-stack-deployer:latest # Check health curl http://localhost:3000/health ``` #### Option 3: Deploy to Dokploy 1. Build and push to registry: ```bash docker build -t your-registry/ai-stack-deployer:latest . docker push your-registry/ai-stack-deployer:latest ``` 2. In Dokploy UI: - Create project: `ai-stack-deployer-portal` - Create application from Docker image - Set domain: `portal.ai.flexinit.nl` - Configure environment variables - Deploy 3. Verify: ```bash curl https://portal.ai.flexinit.nl/health ``` ## API Documentation ### Endpoints #### Health Check ```http GET /health ``` Response: ```json { "status": "healthy", "timestamp": "2026-01-09T12:00:00.000Z", "version": "0.1.0", "service": "ai-stack-deployer", "activeDeployments": 0 } ``` #### Check Name Availability ```http GET /api/check/:name ``` Response: ```json { "available": true, "valid": true, "name": "john-dev" } ``` #### Deploy Stack ```http POST /api/deploy Content-Type: application/json { "name": "john-dev" } ``` Response: ```json { "success": true, "deploymentId": "dep_1234567890_abc123", "url": "https://john-dev.ai.flexinit.nl", "statusEndpoint": "/api/status/dep_1234567890_abc123" } ``` #### Deployment Status (SSE) ```http GET /api/status/:deploymentId ``` Server-Sent Events stream with progress updates: ``` event: progress data: {"status":"creating_project","progress":25,"currentStep":"Creating Dokploy project"} event: progress data: {"status":"creating_application","progress":50,"currentStep":"Creating application container"} event: progress data: {"status":"deploying","progress":85,"currentStep":"Deploying application"} event: complete data: {"url":"https://john-dev.ai.flexinit.nl","status":"ready"} ``` ## Environment Variables ### Required - `DOKPLOY_URL` - Dokploy API URL (default: `http://10.100.0.20:3000`) - `DOKPLOY_API_TOKEN` - Dokploy API authentication token ### Optional - `PORT` - HTTP server port (default: `3000`) - `HOST` - Bind address (default: `0.0.0.0`) - `STACK_DOMAIN_SUFFIX` - Domain suffix for stacks (default: `ai.flexinit.nl`) - `STACK_IMAGE` - Docker image for user stacks (default: `git.app.flexinit.nl/flexinit/agent-stack:latest`) - `RESERVED_NAMES` - Comma-separated forbidden names (default: `admin,api,www,root,system,test,demo,portal`) ### Not Used in Deployment - `HETZNER_API_TOKEN` - Only for testing/manual DNS operations - `HETZNER_ZONE_ID` - DNS zone ID (343733 for flexinit.nl) - `TRAEFIK_IP` - Public IP reference (144.76.116.169) ## Name Validation Rules Stack names must follow these rules: - 3-20 characters long - Lowercase letters (a-z), numbers (0-9), and hyphens (-) only - Cannot start or end with a hyphen - Cannot be a reserved name (admin, api, www, root, system, test, demo, portal) ## Development ### Commands ```bash # Development server with hot reload bun run dev # Production server bun run start # MCP server (for Claude Code integration) bun run mcp # Type checking bun run typecheck # Build for production bun run build # Test API clients bun run src/test-clients.ts ``` ### Project Structure ``` ai-stack-deployer/ ├── src/ │ ├── api/ │ │ ├── dokploy.ts # Dokploy API client │ │ └── hetzner.ts # Hetzner DNS client (testing only) │ ├── frontend/ │ │ ├── index.html # Web UI │ │ ├── style.css # Styles │ │ └── app.js # Frontend logic │ ├── index.ts # HTTP server (production) │ ├── mcp-server.ts # MCP server (development) │ └── test-clients.ts # API client tests ├── Dockerfile # Multi-stage Docker build ├── docker-compose.yml # Docker Compose configuration ├── .dockerignore # Docker build exclusions ├── CLAUDE.md # Claude Code guidance └── README.md # This file ``` ### MCP Server (Development Tool) The MCP server provides Claude Code integration for deployment automation: ```bash # Start MCP server bun run mcp ``` Available MCP tools: - `deploy_stack` - Deploy a new AI stack - `check_deployment_status` - Query deployment progress - `list_deployments` - List all deployments - `check_name_availability` - Validate stack name - `test_api_connections` - Test Dokploy connectivity ## Infrastructure Requirements ### Pre-configured Components - **Wildcard DNS**: `*.ai.flexinit.nl` → `144.76.116.169` - **Traefik**: Wildcard SSL certificate for `*.ai.flexinit.nl` - **Dokploy**: Running at `http://10.100.0.20:3000` - **OpenCode Image**: `git.app.flexinit.nl/flexinit/agent-stack:latest` ### Network Access The deployer must be able to reach: - Dokploy API at `10.100.0.20:3000` (internal network) - No public internet access required for deployment - Frontend users connect via Traefik at `144.76.116.169` ## Troubleshooting ### Health Check Failing ```bash # Check if server is running curl http://localhost:3000/health # Check Docker logs docker-compose logs -f ai-stack-deployer # Restart container docker-compose restart ``` ### Deployment Stuck 1. Check Dokploy API connectivity: ```bash curl -H "x-api-key: YOUR_TOKEN" http://10.100.0.20:3000/api/project.all ``` 2. View deployment logs in browser console (F12) 3. Check server logs for errors: ```bash docker-compose logs -f | grep ERROR ``` ### Name Already Taken If a deployment fails but the name is marked as taken: 1. Check Dokploy UI for the project `ai-stack-{name}` 2. Delete the partial deployment if present 3. Try deployment again ## Security Notes - All API tokens stored in environment variables (never in code) - Dokploy API accessible only on internal network - No authentication on HTTP endpoints (add if exposing publicly) - Name validation prevents injection attacks - Container runs as non-root user (nodejs:1001) ## Performance - **Deployment Time**: ~2-3 minutes per stack - **Concurrent Deployments**: No limit (background processing) - **Memory Usage**: ~50MB base + ~10MB per active deployment - **State Persistence**: In-memory only (implement database for persistence) ## Contributing See `CLAUDE.md` for development guidelines and architecture documentation. ## Branching Strategy This project uses a Git Flow branching model: - **`main`** - Production branch (deployed to https://portal.ai.flexinit.nl) - **`staging`** - Pre-production testing environment - **`dev`** - Active development branch ### Workflow ``` feature/xyz → dev → staging → main ``` ### Quick Commands ```bash # Start new feature git checkout dev git checkout -b feature/my-feature # Deploy to staging (via PR) # Create PR: dev → staging # Deploy to production (via PR) # Create PR: staging → main ``` See `BRANCHING_STRATEGY.md` for complete workflow documentation. ## License [Your License Here] ## Support For issues or questions: - Check the troubleshooting section above - Review logs: `docker-compose logs -f` - Verify environment variables in `.env` --- **Built with ❤️ using Bun, Hono, and Dokploy**