rdev/cookbooks/landing-page.md
jordan 8282d60c69 feat: implement composable monorepo template system with component architecture
Adds the composable monorepo template system that generates project skeletons
with pluggable components (service, worker, app-react, app-astro, cli).

Key changes:
- Monorepo skeleton templates with shared pkg/, scripts/, and git hooks
- Component templates (service, worker, app-react, app-astro, cli) with
  Dockerfiles, CI steps, and component.yaml manifests
- Component domain model with validation and dependency resolution
- Component handler endpoints for CRUD and composition
- Template provider extended with BuildComposableProject and component assembly
- Deployer extended with composable project deployment support
- Handler timeout constants (TimeoutFastLookup through TimeoutLongRunning)
- envutil package for centralized env var reads with defaults
- api.DecodeJSON helper for standardized request body decoding
- Standardized response helpers (WriteBadRequest, WriteNotFound, etc.)
- Replaced fullstack-app cookbook with composable-app cookbook
- Hardened handler timeouts, logging, and error responses across all handlers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 19:11:42 -07:00

8.1 KiB

Landing Page Cookbook

Deploy a landing page using composable templates through the threesix.ai infrastructure.

Overview

This cookbook creates and deploys a landing page using composable monorepo templates:

POST /projects
    ↓
Creates: Monorepo skeleton + Gitea repo + DNS + CI
    ↓
POST /projects/{id}/components (type: app, template: app-astro)
    ↓
Adds: Astro landing page component with valid CI step
    ↓
Git push triggers Woodpecker CI
    ↓
Live site at https://{slug}.threesix.ai

Template-driven. CI is pre-configured. No AI-generated YAML.


Prerequisites

API Access

export RDEV_API_URL="https://rdev.masq-ops.orchard9.ai"
export RDEV_API_KEY="<your-api-key>"

Infrastructure Required


Step 1: Create Project (Monorepo Skeleton)

curl -X POST "$RDEV_API_URL/projects" \
  -H "X-API-Key: $RDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-landing",
    "description": "Company landing page"
  }'

Response:

{
  "data": {
    "project_id": "my-landing",
    "name": "my-landing",
    "domain": "abc123xy.threesix.ai",
    "url": "https://abc123xy.threesix.ai",
    "git": {
      "owner": "jordan",
      "name": "my-landing",
      "html_url": "https://git.threesix.ai/jordan/my-landing"
    }
  }
}

This creates a monorepo skeleton with:

  • README.md, CLAUDE.md, Procfile
  • .woodpecker.yml (template-provided, valid CI)
  • scripts/ (discover, install, quality, dev)
  • pkg/ (shared Go packages)
  • Empty component directories (services/, apps/, workers/, cli/)

Step 2: Add Landing Page Component

curl -X POST "$RDEV_API_URL/projects/my-landing/components" \
  -H "X-API-Key: $RDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "app",
    "name": "landing",
    "template": "app-astro"
  }'

Response:

{
  "data": {
    "type": "app",
    "name": "landing",
    "path": "apps/landing",
    "port": 3001,
    "template": "app-astro"
  }
}

This adds:

  • apps/landing/ - Astro project with Tailwind CSS
  • Updates .woodpecker.yml with build step for this component
  • Updates Procfile with dev server entry

Step 3: Customize with Claude (Optional)

Submit a build task to customize the landing page:

curl -X POST "$RDEV_API_URL/projects/my-landing/builds" \
  -H "X-API-Key: $RDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Update apps/landing to have: dark gradient background, centered hero section with company name \"Acme Corp\" and tagline \"Building the future\", email signup form with shadcn styling. Keep the existing Astro structure.",
    "auto_commit": true,
    "auto_push": true
  }'

Monitor the build:

curl -s "$RDEV_API_URL/builds/{task_id}" \
  -H "X-API-Key: $RDEV_API_KEY" | jq .data

Step 4: Monitor CI Pipeline

The push triggers Woodpecker CI automatically:

curl -s "$RDEV_API_URL/projects/my-landing/pipelines" \
  -H "X-API-Key: $RDEV_API_KEY" | jq '.data[0]'

Wait for status: "success".


Step 5: Verify Deployment

# Check site is live
curl -I https://abc123xy.threesix.ai

# View the site
open https://abc123xy.threesix.ai

Iterating on the Site

Submit additional builds to modify the site:

curl -X POST "$RDEV_API_URL/projects/my-landing/builds" \
  -H "X-API-Key: $RDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Add a pricing section to apps/landing with three tiers: Free, Pro ($29/mo), Enterprise (contact us). Match the existing dark theme.",
    "auto_commit": true,
    "auto_push": true
  }'

Each build:

  1. Claude clones the repo
  2. Makes the requested changes
  3. Commits and pushes
  4. CI deploys automatically

Adding Custom Domains

# Add www subdomain
curl -X POST "$RDEV_API_URL/projects/my-landing/domains" \
  -H "X-API-Key: $RDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "www.mycompany.com"}'

# List all domains
curl -s "$RDEV_API_URL/projects/my-landing/domains" \
  -H "X-API-Key: $RDEV_API_KEY" | jq '.data.domains'

Teardown

curl -X DELETE "$RDEV_API_URL/projects/my-landing" \
  -H "X-API-Key: $RDEV_API_KEY"

Removes: DNS records, K8s deployment, project metadata. Gitea repo preserved for safety.


E2E Test Script

Run the full flow:

./cookbooks/scripts/landing-test.sh run my-test-landing

Check status:

./cookbooks/scripts/landing-test.sh status my-test-landing

Cleanup:

./cookbooks/scripts/landing-test.sh teardown my-test-landing

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                 Composable Landing Page Deployment                  │
│                                                                     │
│  POST /projects                                                     │
│       │                                                             │
│       ├──► Gitea: creates repo with skeleton                        │
│       ├──► Cloudflare: creates DNS                                  │
│       ├──► Woodpecker: activates CI                                 │
│       └──► Skeleton includes .woodpecker.yml (template-provided)    │
│                                                                     │
│  POST /projects/{id}/components                                     │
│       │                                                             │
│       ├──► Adds apps/landing/ from app-astro template               │
│       ├──► Updates .woodpecker.yml with build step                  │
│       └──► Updates Procfile                                         │
│                                                                     │
│  POST /projects/{id}/builds (optional customization)                │
│       │                                                             │
│       └──► Claude modifies existing files, commits, pushes          │
│                                                                     │
│  Git push triggers Woodpecker CI:                                   │
│       ├──► Builds Docker image via Kaniko                           │
│       ├──► Pushes to registry.threesix.ai                           │
│       └──► Deploys to K8s                                           │
│                                                                     │
│  Site live at https://{slug}.threesix.ai                            │
└─────────────────────────────────────────────────────────────────────┘

Troubleshooting

Build stuck in pending

# Check worker status
curl -s "$RDEV_API_URL/workers" -H "X-API-Key: $RDEV_API_KEY" | jq '.data.summary'

# Should show at least 1 idle worker

Build failed

# Get build details
curl -s "$RDEV_API_URL/builds/{task_id}" -H "X-API-Key: $RDEV_API_KEY" | jq '.result'

# Check rdev-api logs
./scripts/logs.sh -e

Pipeline not triggering

# Check if commit was pushed
curl -s "https://git.threesix.ai/api/v1/repos/jordan/my-landing/commits" | jq '.[0]'

# Check Woodpecker
open https://ci.threesix.ai/jordan/my-landing

Component not appearing

# List components
curl -s "$RDEV_API_URL/projects/my-landing/components" \
  -H "X-API-Key: $RDEV_API_KEY" | jq '.data'