# Landing Page Cookbook > Deploy a static landing page through the threesix.ai infrastructure with agent-driven development. ## Overview This cookbook creates and deploys a simple landing page using the full threesix.ai autonomous infrastructure: ``` rdev-api → Gitea repo → Claude agent → push → Woodpecker CI → K8s deployment ``` **Target:** `landing.threesix.ai` (with future DNS aliases for www/root) **Stack:** Astro (static site generator) **Status:** Coming Soon page --- ## Current Architecture Gap **Two separate systems that need bridging:** | System | Endpoint | What it manages | |--------|----------|-----------------| | Project Management | `POST /project` | Gitea repos, DNS records, K8s deployments | | Claudebox Execution | `POST /projects/{id}/claude` | Code generation in existing claudebox pods | **The problem:** Creating a project via `POST /project` creates a Gitea repo, but there's no claudebox to generate code for it. The claudebox system only knows about pre-existing pods (pantheon, aeries). **The solution:** Use an existing claudebox as a "worker" to clone, build, and push to any project repo. --- ## Prerequisites ### Credentials Required | Secret | Location | Purpose | |--------|----------|---------| | RDEV_ADMIN_KEY | `rdev-credentials` secret | rdev-api authentication | | GITEA_TOKEN | `rdev-credentials` secret | Gitea API access | | WOODPECKER_API_TOKEN | `.secrets` file | Woodpecker repo activation | | CLOUDFLARE_API_TOKEN | `rdev-credentials` secret | DNS management | ### Infrastructure Required - [x] rdev-api running with infrastructure handlers (v0.7.1+) - [x] Gitea at https://git.threesix.ai - [x] Woodpecker CI at https://ci.threesix.ai - [x] Zot registry at zot.threesix.svc.cluster.local:5000 - [x] `projects` namespace in K8s with RBAC - [x] Wildcard TLS cert for *.threesix.ai --- ## Architecture ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ Landing Page Flow │ │ │ │ 1. Create Project │ │ POST /project {"name": "www"} │ │ │ │ │ ├──▶ Creates Gitea repo: jordan/www │ │ └──▶ Creates DNS: www.threesix.ai → 208.122.204.172 │ │ │ │ 2. Activate Woodpecker │ │ POST /api/repos?forge_remote_id={id} │ │ │ │ │ └──▶ Creates webhook in Gitea │ │ │ │ 3. Generate Code (Claude Agent) │ │ claudebox or local Claude Code │ │ │ │ │ ├──▶ Creates Astro project │ │ ├──▶ Creates Dockerfile │ │ ├──▶ Creates .woodpecker.yml │ │ └──▶ Pushes to Gitea │ │ │ │ 4. CI/CD Pipeline (automatic) │ │ Woodpecker triggered by push │ │ │ │ │ ├──▶ Kaniko builds Docker image │ │ ├──▶ Pushes to Zot registry │ │ └──▶ Webhook triggers rdev-api deploy │ │ │ │ 5. Live at https://www.threesix.ai │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` --- ## Step-by-Step Implementation ### Step 1: Create Project via rdev-api ```bash RDEV_KEY="rdev_sk_prod_7f3a9c2e1d8b4a6f0e5c9d2b7a1f8e4c" curl -X POST https://rdev.masq-ops.orchard9.ai/project \ -H "Authorization: Bearer $RDEV_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "landing", "description": "threesix.ai landing page"}' ``` **Response:** ```json { "data": { "name": "landing", "domain": "landing.threesix.ai", "git": { "clone_ssh": "git@git.threesix.ai:jordan/landing.git", "clone_http": "https://git.threesix.ai/jordan/landing.git" } } } ``` ### Step 2: Activate Woodpecker CI ```bash GITEA_TOKEN="5508ff241943e84aad0ced3559f5fbd311a2fb81" WOODPECKER_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoidXNlciIsInVzZXItaWQiOiIxIn0.LcyVHcZ_gSvVH1w3y6TUCp_Jg9ubfsebOAVo-MtiNP8" # Get Gitea repo ID REPO_ID=$(curl -s https://git.threesix.ai/api/v1/repos/jordan/landing \ -H "Authorization: token $GITEA_TOKEN" | jq '.id') # Activate in Woodpecker (creates webhook automatically) curl -X POST "https://ci.threesix.ai/api/repos?forge_remote_id=$REPO_ID" \ -H "Authorization: Bearer $WOODPECKER_TOKEN" ``` ### Step 3: Generate Code via Claudebox Use the `pantheon` claudebox as a worker to generate code for the landing project: ```bash RDEV_KEY="rdev_sk_prod_7f3a9c2e1d8b4a6f0e5c9d2b7a1f8e4c" # Tell Claude to build the landing page in /tmp/landing curl -X POST "https://rdev.masq-ops.orchard9.ai/projects/pantheon/claude" \ -H "Authorization: Bearer $RDEV_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Clone https://git.threesix.ai/jordan/landing.git to /tmp/landing, then create a simple Astro landing page with: Coming Soon message, threesix.ai branding (dark theme), responsive layout, Dockerfile (nginx), and .woodpecker.yml for CI/CD. Commit and push when done." }' ``` **What happens:** 1. Claude receives the prompt in the claudebox 2. Claude clones the repo to `/tmp/landing` 3. Claude generates the Astro project files 4. Claude commits and pushes to Gitea ### Step 4: Monitor Build Watch Woodpecker for the build: - https://ci.threesix.ai/jordan/landing Or via API: ```bash curl -s "https://ci.threesix.ai/api/repos/jordan/landing/pipelines" \ -H "Authorization: Bearer $WOODPECKER_TOKEN" | jq '.[0] | {number, status, started}' ``` ### Step 5: Verify Deployment ```bash curl -s "https://rdev.masq-ops.orchard9.ai/project/landing" \ -H "Authorization: Bearer $RDEV_KEY" | jq '.data.deployment' ``` Site live at: https://landing.threesix.ai ### Step 6: Configure DNS Aliases (Optional) Point `www.threesix.ai` and `threesix.ai` to the landing page: ```bash CF_TOKEN="nGoDhG6Za66XsKMl6W7LNXuowc5EM00glHxkq1KK" CF_ZONE="e0bc8d510f62807b360db0c5994964c5" # Update root A record to point to k3s cluster curl -X PATCH "https://api.cloudflare.com/client/v4/zones/$CF_ZONE/dns_records/{record_id}" \ -H "Authorization: Bearer $CF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "type": "A", "name": "threesix.ai", "content": "208.122.204.172", "proxied": false }' ``` --- ## File Templates ### .woodpecker.yml ```yaml steps: build: image: gcr.io/kaniko-project/executor:latest settings: registry: zot.threesix.svc.cluster.local:5000 tags: - ${CI_COMMIT_SHA:0:8} - latest repo: zot.threesix.svc.cluster.local:5000/${CI_REPO_NAME} context: . dockerfile: Dockerfile insecure: true when: branch: main notify: image: alpine/curl:latest commands: - echo "Build complete, webhook will trigger deployment" when: branch: main status: success ``` ### Dockerfile (Astro + Nginx) ```dockerfile # Build stage FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # Production stage FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` ### nginx.conf ```nginx server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ /index.html; } # Cache static assets location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; } } ``` --- ## Current Gaps & Future Automation ### What's Manual Today | Step | Status | Automation Path | |------|--------|-----------------| | Create project | ✅ API | Already automated | | Activate Woodpecker | 🔧 API call needed | Add to rdev-api | | Generate code | ❌ Manual Claude | Claudebox integration | | Push to Gitea | ❌ Manual git | Claudebox with SSH key | | Deploy | ✅ Webhook | Already automated | ### To Fully Automate (Future Work) 1. **Add Woodpecker activation to rdev-api** - Store WOODPECKER_API_TOKEN in secrets - Call Woodpecker API after creating Gitea repo - Create webhook automatically 2. **Claudebox code generation** - Spawn claudebox with project context - Claudebox has Gitea SSH key - Claude Code generates code based on prompt - Auto-push to Gitea 3. **Single API call** ``` POST /project/create-and-build { "name": "www", "prompt": "Create an Astro landing page with coming soon message", "stack": "astro" } ``` --- ## Verification After deployment, verify: ```bash # Check DNS dig www.threesix.ai # Check site curl -I https://www.threesix.ai # Check deployment status curl https://rdev.masq-ops.orchard9.ai/project/www \ -H "Authorization: Bearer $RDEV_KEY" ``` --- ## Rollback To remove the landing page: ```bash # Delete via rdev-api (removes Gitea repo, DNS, K8s deployment) curl -X DELETE https://rdev.masq-ops.orchard9.ai/project/www \ -H "Authorization: Bearer $RDEV_KEY" ``` --- ## Related - [THREESIX_INFRASTRUCTURE.md](/Users/jordanwashburn/Workspace/orchard9/rdev/docs/plans/THREESIX_INFRASTRUCTURE.md) - Infrastructure plan - [woodpecker-pipeline-template.yaml](../deployments/k8s/base/threesix/woodpecker-pipeline-template.yaml) - CI template