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>
306 lines
8.1 KiB
Markdown
306 lines
8.1 KiB
Markdown
# 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
|
|
```bash
|
|
export RDEV_API_URL="https://rdev.masq-ops.orchard9.ai"
|
|
export RDEV_API_KEY="<your-api-key>"
|
|
```
|
|
|
|
### Infrastructure Required
|
|
- rdev-api running with embedded worker
|
|
- Gitea at https://git.threesix.ai
|
|
- Woodpecker CI at https://ci.threesix.ai
|
|
|
|
---
|
|
|
|
## Step 1: Create Project (Monorepo Skeleton)
|
|
|
|
```bash
|
|
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:**
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```bash
|
|
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:**
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```bash
|
|
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:
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
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:
|
|
```bash
|
|
./cookbooks/scripts/landing-test.sh run my-test-landing
|
|
```
|
|
|
|
Check status:
|
|
```bash
|
|
./cookbooks/scripts/landing-test.sh status my-test-landing
|
|
```
|
|
|
|
Cleanup:
|
|
```bash
|
|
./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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# List components
|
|
curl -s "$RDEV_API_URL/projects/my-landing/components" \
|
|
-H "X-API-Key: $RDEV_API_KEY" | jq '.data'
|
|
```
|
|
|
|
---
|
|
|
|
## Related
|
|
|
|
- [Composable App Cookbook](./composable-app.md) - Full-stack apps with multiple components
|
|
- [Worker Pool Guide](../.claude/guides/services/worker-pool.md)
|
|
- [Composable Monorepo Guide](../.claude/guides/services/composable-monorepo.md)
|