# 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+ (production), Node.js 20 (build)
- **Framework**: Hono 4.11.3
- **Language**: TypeScript
- **Frontend**: React 19 + Vite + Tailwind CSS 4
- **Container**: Docker with multi-stage builds (Node.js build, Bun runtime)
- **Orchestration**: Dokploy
- **Reverse Proxy**: Traefik with wildcard SSL

**Build Strategy**: Uses Node.js for building (avoids AVX CPU requirement) and Bun for runtime (performance).

## 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 <repository-url>
   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

### Docker Build Fails with "CPU lacks AVX support"

**Error**: `panic(main thread): Illegal instruction at address 0x...`

**Cause**: Bun requires AVX CPU instructions which may not be available in all Docker build environments.

**Solution**: Already implemented in Dockerfile. The build uses Node.js (no AVX requirement) for building and Bun for runtime:

```dockerfile
FROM node:20-alpine AS builder
RUN npm install
RUN npm run build:client

FROM oven/bun:1.3-alpine AS runner
```

If you see this error, ensure you're using the latest Dockerfile from the repository.

## 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**
