# AI Stack Deployer - Deployment Strategy

## Overview

Deploy the AI Stack Deployer portal to production, making it accessible at `deploy.ai.flexinit.nl`.

## User Stack Container (oh-my-opencode-free)

### Image Details

| Property | Value |
|----------|-------|
| Registry | `git.app.flexinit.nl` |
| Image | `oussamadouhou/oh-my-opencode-free:latest` |
| Base | `oven/bun:debian` |
| Port | 8080 (OpenCode server) |
| CI/CD | Gitea Actions (auto-build on push) |

### Pre-configured Free Models

| Agent | Model | Purpose |
|-------|-------|---------|
| Sisyphus (main) | `glm-4.7-free` | Primary coding |
| Oracle | `gpt-5-nano` | Architecture |
| Librarian | `minimax-m2.1-free` | Documentation |
| Explore | `grok-code` | Codebase search |
| Frontend | `glm-4.7-free` | UI/UX |
| Document Writer | `gpt-5-nano` | Docs |

### Baked Configuration

```
/shared/config/
├── opencode.json       # CLI config
├── opencode.jsonc      # Permissions
└── oh-my-opencode.json # Agent model assignments
```

### Persistent Storage (per user)

| Volume | Mount Path | Purpose |
|--------|------------|---------|
| `workspace-{name}` | `/workspace` | User projects |

## Architecture

```
Internet
    │
    ▼
┌─────────────────────────────────────────────┐
│  Traefik (144.76.116.169)                   │
│  - SSL termination (wildcard *.ai.flexinit.nl)│
│  - Routes deploy.ai.flexinit.nl → portal    │
└─────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────┐
│  AI Stack Deployer Container                │
│  - Port 3000                                │
│  - Needs access to 10.100.0.20 (Dokploy)    │
└─────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────┐
│  Dokploy (10.100.0.20:3000)                 │
│  - Creates user stacks                      │
│  - Manages containers                       │
└─────────────────────────────────────────────┘
```

## Deployment Options

### Option A: Deploy via Dokploy (Recommended)

**Pros**: Self-service, consistent with stack deployments, automatic restarts
**Cons**: Circular dependency (if Dokploy is down, can't redeploy)

### Option B: Direct Docker on Traefik Host

**Pros**: Independent of Dokploy, simpler network (same host as Traefik)
**Cons**: Manual management, no Dokploy UI

### Option C: Separate VM with Docker Compose

**Pros**: Isolation, can use docker-compose.yml directly
**Cons**: Extra VM, network routing complexity

**Decision: Option A (Dokploy)** - Eat our own dog food, leverage existing infrastructure.

## Step-by-Step Deployment

### Phase 1: Prepare Image

```bash
# 1. Build and tag image
docker build -t git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:latest .

# 2. Push to registry
docker push git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:latest
```

### Phase 2: Create Dokploy Project

1. Open Dokploy UI: https://app.flexinit.nl
2. Create project: `ai-stack-deployer-portal`
3. Create application:
   - Name: `deployer`
   - Type: Docker Image
   - Image: `git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:latest`

### Phase 3: Configure Environment

Set these environment variables in Dokploy:

| Variable | Value | Source |
|----------|-------|--------|
| `NODE_ENV` | `production` | Static |
| `PORT` | `3000` | Static |
| `HOST` | `0.0.0.0` | Static |
| `DOKPLOY_URL` | `http://10.100.0.20:3000` | Static |
| `DOKPLOY_API_TOKEN` | `<token>` | BWS: `6b3618fc-ba02-49bc-bdc8-b3c9004087bc` |
| `STACK_DOMAIN_SUFFIX` | `ai.flexinit.nl` | Static |
| `STACK_IMAGE` | `git.app.flexinit.nl/oussamadouhou/oh-my-opencode-free:latest` | Static |
| `RESERVED_NAMES` | `admin,api,www,root,system,test,demo,portal,deploy` | Static |

### Phase 4: Configure Domain

1. In Dokploy application settings, add domain:
   - Host: `deploy.ai.flexinit.nl`
   - HTTPS: Enabled
   - Port: 3000

2. DNS is already configured (wildcard `*.ai.flexinit.nl` → 144.76.116.169)

### Phase 5: Deploy

1. Click "Deploy" in Dokploy UI
2. Wait for container to start (~30s)
3. Verify health: `curl https://deploy.ai.flexinit.nl/health`

## Network Requirements

The deployer container MUST be able to reach:
- `10.100.0.20:3000` - Dokploy API (internal network)

This works automatically when deployed via Dokploy since containers share the internal network.

## Secrets Management

### Using BWS

```bash
# Get Dokploy token
bws secret get 6b3618fc-ba02-49bc-bdc8-b3c9004087bc

# Set in Dokploy environment variables (manually or via API)
```

### Rotation Strategy

1. Generate new token in Dokploy UI
2. Store in BWS
3. Update environment variable in Dokploy
4. Redeploy application

## Monitoring

### Health Checks

- **Endpoint**: `GET /health`
- **Interval**: 30 seconds
- **Expected**: `{"status":"healthy",...}`

### Alerting

Set up monitoring for:
- Health endpoint failures
- High error rates in deployment logs
- Circuit breaker state changes

## Rollback Procedure

### Quick Rollback

```bash
# Via Dokploy UI
1. Go to application → Deployments
2. Click "Rollback" on previous successful deployment
```

### Manual Rollback

```bash
# Re-deploy previous image tag
docker pull git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:v0.1.0
# Update image in Dokploy and redeploy
```

## CI/CD Pipeline (Future)

```yaml
# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Build and push
        run: |
          docker build -t git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:${{ github.sha }} .
          docker push git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:${{ github.sha }}
      
      - name: Deploy via Dokploy API
        run: |
          curl -X POST "$DOKPLOY_URL/api/application.update" \
            -H "x-api-key: $DOKPLOY_API_TOKEN" \
            -H "Content-Type: application/json" \
            -d '{"applicationId": "$APP_ID", "dockerImage": "...:${{ github.sha }}"}'
          
          curl -X POST "$DOKPLOY_URL/api/application.deploy" \
            -H "x-api-key: $DOKPLOY_API_TOKEN" \
            -d '{"applicationId": "$APP_ID"}'
```

## Pre-Deployment Checklist

- [ ] Docker image builds successfully: `docker build -t test .`
- [ ] TypeScript compiles: `bun run typecheck`
- [ ] Health endpoint works locally: `curl localhost:3000/health`
- [ ] Dokploy API token is valid
- [ ] Registry credentials configured
- [ ] Domain DNS resolves correctly

## Post-Deployment Verification

```bash
# 1. Health check
curl https://deploy.ai.flexinit.nl/health

# 2. Name validation
curl https://deploy.ai.flexinit.nl/api/check/test-name

# 3. Frontend loads
curl -s https://deploy.ai.flexinit.nl | grep -q "AI Stack Deployer"

# 4. Full deployment test (optional)
curl -X POST https://deploy.ai.flexinit.nl/api/deploy \
  -H "Content-Type: application/json" \
  -d '{"name": "smoke-test"}'

# 5. Cleanup test
curl -X DELETE https://deploy.ai.flexinit.nl/api/stack/smoke-test
```

## Security Considerations

1. **No public auth yet** - Consider adding authentication for production
2. **Rate limiting** - Not implemented, consider adding
3. **API token exposure** - Stored in Dokploy env vars (encrypted at rest)
4. **Delete endpoint** - Should require authentication in production

## Estimated Timeline

| Phase | Duration | Notes |
|-------|----------|-------|
| Image build & push | 5 min | Automated |
| Dokploy project setup | 10 min | One-time |
| Environment config | 5 min | One-time |
| Deployment | 2 min | Per deploy |
| Verification | 5 min | Per deploy |
| **Total first deploy** | ~30 min | |
| **Subsequent deploys** | ~10 min | |

## Next Steps

1. Build and push Docker image
2. Create Dokploy project and application
3. Configure environment variables
4. Add domain
5. Deploy and verify
6. Set up monitoring
7. (Optional) Implement CI/CD
