feat: add feature development E2E test and SDLC handler fixes

- Add feature-dev-test.sh: full 10-step E2E test for SDLC + Claude Code workflow
- Update feature-development.md cookbook with complete workflow documentation
- Fix SDLC orchestrator and project management handler improvements
- Update scaffold-test.sh with minor fixes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jordan 2026-02-02 20:12:40 -07:00
parent fc2cfa139c
commit 64ccf0b85d
6 changed files with 813 additions and 37 deletions

View File

@ -269,8 +269,10 @@ POST /project/landing/build
| Script | Description | | Script | Description |
|--------|-------------| |--------|-------------|
| `scripts/landing-test.sh` | Landing page E2E test | | `scripts/landing-test.sh` | Landing page E2E test |
| `scripts/feature-test.sh` | Feature development E2E test | | `scripts/feature-dev-test.sh` | Feature development E2E test (Claude + SDLC flow) |
| `scripts/scaffold-test.sh` | Scaffold validation E2E test (patterns/components) |
| `scripts/composable-test.sh` | Composable monorepo E2E test | | `scripts/composable-test.sh` | Composable monorepo E2E test |
| `scripts/sdlc-test.sh` | SDLC API endpoint validation |
| `scripts/template-validation.sh` | Template validation checks | | `scripts/template-validation.sh` | Template validation checks |
--- ---

View File

@ -4,15 +4,208 @@
## Overview ## Overview
This cookbook documents the end-to-end workflow for developing features in a composable monorepo project. It assumes you have: This cookbook documents the end-to-end workflow for developing features in a composable monorepo project. There are two approaches:
- An rdev project with monorepo skeleton (created via `POST /project`) 1. **SDLC-Driven** (Recommended) - Structured workflow using the SDLC system and Claude Code
- At least one API service component (`services/api`) 2. **Manual** - Traditional development with manual planning and implementation
- A Next.js or React app component (`apps/dashboard`)
The SDLC-driven approach uses skeleton commands that Claude executes inside the project pod, producing structured artifacts (spec, design, tasks) that can be approved and tracked.
``` ```
Feature Development Workflow SDLC Feature Development Workflow
──────────────────────────── ──────────────────────────────────
1. Create Feature → POST /sdlc/features
2. Generate Spec → Claude runs /spec-feature
3. Approve Spec → POST /sdlc/features/{slug}/artifacts/spec/approve
4. Generate Design → Claude runs /design-feature
5. Approve Design → POST /sdlc/features/{slug}/artifacts/design/approve
6. Break Down Tasks → Claude runs /breakdown-feature
7. Approve Tasks → POST /sdlc/features/{slug}/artifacts/tasks/approve
8. Implement Tasks → Claude runs /implement-task for each
9. Review & Merge → Claude runs /review-feature, /merge-feature
```
---
## Quick Start: API-Driven Feature Development
This section shows the minimal API calls to develop a feature using Claude Code and the SDLC system.
### Prerequisites
```bash
export RDEV_API_URL="https://rdev.masq-ops.orchard9.ai"
export RDEV_API_KEY="<your-api-key>"
```
### 1. Create Feature
```bash
curl -X POST "$RDEV_API_URL/projects/myapp/sdlc/features" \
-H "X-API-Key: $RDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"slug": "add-hello", "title": "Add /hello endpoint"}'
```
### 2. Generate Spec with Claude
```bash
curl -X POST "$RDEV_API_URL/projects/myapp/builds" \
-H "X-API-Key: $RDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "/spec-feature add-hello",
"auto_commit": true,
"auto_push": true,
"git_clone_url": "https://git.threesix.ai/jordan/myapp.git"
}'
# Returns: {"data": {"task_id": "abc123", ...}}
```
### 3. Check Build Status
```bash
curl "$RDEV_API_URL/builds/abc123" \
-H "X-API-Key: $RDEV_API_KEY"
# Wait for status: "completed"
```
### 4. Check Classifier for Next Action
```bash
curl "$RDEV_API_URL/projects/myapp/sdlc/next?feature=add-hello" \
-H "X-API-Key: $RDEV_API_KEY"
# Returns: {"action": "AWAIT_APPROVAL", "artifact": "spec", ...}
```
### 5. Approve Spec
```bash
curl -X POST "$RDEV_API_URL/projects/myapp/sdlc/features/add-hello/artifacts/spec/approve" \
-H "X-API-Key: $RDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
```
### 6. Continue Through Phases
Repeat the pattern: **Generate artifact****Check classifier****Approve** → **Next phase**
```bash
# Generate design
curl -X POST "$RDEV_API_URL/projects/myapp/builds" \
-H "X-API-Key: $RDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "/design-feature add-hello", "auto_commit": true, "auto_push": true, "git_clone_url": "https://git.threesix.ai/jordan/myapp.git"}'
# Approve design
curl -X POST "$RDEV_API_URL/projects/myapp/sdlc/features/add-hello/artifacts/design/approve" \
-H "X-API-Key: $RDEV_API_KEY" -H "Content-Type: application/json" -d '{}'
# Generate tasks
curl -X POST "$RDEV_API_URL/projects/myapp/builds" \
-H "X-API-Key: $RDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "/breakdown-feature add-hello", "auto_commit": true, "auto_push": true, "git_clone_url": "https://git.threesix.ai/jordan/myapp.git"}'
# Approve tasks
curl -X POST "$RDEV_API_URL/projects/myapp/sdlc/features/add-hello/artifacts/tasks/approve" \
-H "X-API-Key: $RDEV_API_KEY" -H "Content-Type: application/json" -d '{}'
# Implement first task
curl -X POST "$RDEV_API_URL/projects/myapp/builds" \
-H "X-API-Key: $RDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "/implement-task add-hello T1", "auto_commit": true, "auto_push": true, "git_clone_url": "https://git.threesix.ai/jordan/myapp.git"}'
```
### E2E Test Script
Run the full workflow automatically:
```bash
./cookbooks/scripts/feature-dev-test.sh run my-test-project
./cookbooks/scripts/feature-dev-test.sh status my-test-project
./cookbooks/scripts/feature-dev-test.sh teardown my-test-project
```
---
## Skeleton Commands Reference
These commands are installed in every project's `.claude/commands/` directory and can be invoked via the `/builds` endpoint.
| Command | Description | Artifacts |
|---------|-------------|-----------|
| `/spec-feature <slug>` | Create specification document | `.sdlc/features/<slug>/spec.md` |
| `/design-feature <slug>` | Create technical design | `.sdlc/features/<slug>/design.md` |
| `/breakdown-feature <slug>` | Break feature into tasks | `.sdlc/features/<slug>/tasks.md` |
| `/implement-task <slug> <task-id>` | Implement a specific task | Code changes |
| `/create-qa-plan <slug>` | Create QA test plan | `.sdlc/features/<slug>/qa-plan.md` |
| `/run-qa <slug>` | Execute QA tests | Test results |
| `/review-feature <slug>` | Code review all changes | Review report |
| `/audit-feature <slug>` | Audit feature for compliance | Audit report |
| `/fix-review-issues <slug>` | Fix issues from review | Code changes |
| `/remediate-audit <slug>` | Fix audit findings | Code changes |
| `/fix-qa-failures <slug>` | Fix failing QA tests | Code changes |
| `/merge-feature <slug>` | Merge feature to main | Merged branch |
| `/archive-feature <slug>` | Archive completed feature | Archived state |
| `/next <slug>` | Get classifier recommendation | Next action |
| `/deliver <slug>` | Run full delivery pipeline | All artifacts |
---
## SDLC API Reference
### Feature Management
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/projects/{id}/sdlc/state` | GET | Get SDLC state for project |
| `/projects/{id}/sdlc/features` | GET | List all features |
| `/projects/{id}/sdlc/features` | POST | Create new feature |
| `/projects/{id}/sdlc/features/{slug}` | GET | Get feature details |
| `/projects/{id}/sdlc/features/{slug}` | DELETE | Delete feature |
### Artifacts
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/projects/{id}/sdlc/features/{slug}/artifacts` | GET | List artifact status |
| `/projects/{id}/sdlc/features/{slug}/artifacts/{type}/approve` | POST | Approve artifact |
### Tasks
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/projects/{id}/sdlc/features/{slug}/tasks` | GET | List tasks |
| `/projects/{id}/sdlc/features/{slug}/tasks` | POST | Add task |
### Workflow Control
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/projects/{id}/sdlc/features/{slug}/block` | POST | Block feature |
| `/projects/{id}/sdlc/features/{slug}/unblock` | POST | Unblock feature |
| `/projects/{id}/sdlc/next` | GET | Get classifier recommendation |
### Queries
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/projects/{id}/sdlc/query/blocked` | GET | List blocked features |
| `/projects/{id}/sdlc/query/ready` | GET | List ready features |
| `/projects/{id}/sdlc/query/needs-approval` | GET | List features awaiting approval |
---
## Manual Development Workflow
For cases where you want direct control without the SDLC system, you can follow the traditional development workflow below.
```
Manual Feature Development Workflow
────────────────────────────────────
1. Planning → Define requirements, break into tasks 1. Planning → Define requirements, break into tasks
2. API Dev → Bind + Wrap patterns, OpenAPI annotations 2. API Dev → Bind + Wrap patterns, OpenAPI annotations
3. Frontend Dev → Auth hooks, design system, API client 3. Frontend Dev → Auth hooks, design system, API client
@ -21,17 +214,14 @@ Feature Development Workflow
6. Deployment → Git push, Woodpecker CI, verify 6. Deployment → Git push, Woodpecker CI, verify
``` ```
--- This approach assumes you have:
## Prerequisites - An rdev project with monorepo skeleton (created via `POST /project`)
- At least one API service component (`services/api`)
### API Access - A Next.js or React app component (`apps/dashboard`)
```bash
export RDEV_API_URL="https://rdev.masq-ops.orchard9.ai"
export RDEV_API_KEY="<your-api-key>"
```
### Project Structure ### Project Structure
Your composable monorepo should have: Your composable monorepo should have:
``` ```
@ -728,24 +918,41 @@ import { DashboardShell, Sidebar, Header } from '@my-project/layout';
--- ---
## E2E Test Script ## E2E Test Scripts
Validate the complete feature development flow: ### Feature Development (Claude + SDLC)
Test the complete feature development flow with Claude Code:
```bash ```bash
# Create test project with components # Run full SDLC feature development flow
./cookbooks/scripts/feature-test.sh run test-feature ./cookbooks/scripts/feature-dev-test.sh run test-feature
# Check status # Check status
./cookbooks/scripts/feature-test.sh status test-feature ./cookbooks/scripts/feature-dev-test.sh status test-feature
# Cleanup # Cleanup
./cookbooks/scripts/feature-test.sh teardown test-feature ./cookbooks/scripts/feature-dev-test.sh teardown test-feature
```
### Scaffold Validation
Test that project scaffolding creates correct patterns:
```bash
# Create project and verify patterns
./cookbooks/scripts/scaffold-test.sh run test-scaffold
# Verify specific patterns
./cookbooks/scripts/scaffold-test.sh verify-patterns test-scaffold
# Cleanup
./cookbooks/scripts/scaffold-test.sh teardown test-scaffold
``` ```
--- ---
## Troubleshooting ## Manual Troubleshooting
### Handler returns 500 instead of proper error ### Handler returns 500 instead of proper error
Check that you're using `httperror.*` functions, not raw `errors.New()`. Check that you're using `httperror.*` functions, not raw `errors.New()`.
@ -824,9 +1031,80 @@ All use CSS custom properties: `var(--background)`, `var(--accent)`, `var(--bord
--- ---
## SDLC Troubleshooting
### Build returns "completed" but no artifacts created
The skeleton command may have failed silently. Check the build output:
```bash
curl "$RDEV_API_URL/builds/<task-id>" -H "X-API-Key: $RDEV_API_KEY" | jq '.data.result'
```
Common causes:
- Feature doesn't exist (create it first via `/sdlc/features`)
- Previous artifacts missing (spec must exist before design)
- SDLC CLI not installed in pod
### Classifier returns AWAIT_ARTIFACT but artifact exists
The artifact may exist in the file system but not registered with SDLC:
```bash
# Register artifact manually
curl -X POST "$RDEV_API_URL/projects/$PROJECT/builds" \
-H "X-API-Key: $RDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "sdlc artifact create <slug> <type>", "auto_commit": true, "auto_push": true, "git_clone_url": "<url>"}'
```
### Task implementation doesn't commit changes
Check that `auto_commit` and `auto_push` are set to `true`, and `git_clone_url` is provided:
```bash
curl -X POST "$RDEV_API_URL/projects/$PROJECT/builds" \
-H "X-API-Key: $RDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "/implement-task <slug> <task-id>",
"auto_commit": true,
"auto_push": true,
"git_clone_url": "https://git.threesix.ai/jordan/<project>.git"
}'
```
### Build times out
Builds have a default timeout of 10 minutes. Complex implementations may need longer. Check the build status periodically:
```bash
# Poll status
while true; do
status=$(curl -s "$RDEV_API_URL/builds/<task-id>" -H "X-API-Key: $RDEV_API_KEY" | jq -r '.data.status // .status')
echo "Status: $status"
[[ "$status" == "completed" || "$status" == "failed" ]] && break
sleep 10
done
```
### Feature stuck in wrong phase
Check the classifier recommendation to understand what's blocking:
```bash
curl "$RDEV_API_URL/projects/$PROJECT/sdlc/next?feature=<slug>" \
-H "X-API-Key: $RDEV_API_KEY" | jq '.'
```
If needed, you can manually advance the phase by approving the pending artifact.
---
## Related ## Related
- [Composable App Cookbook](./composable-app.md) - Creating projects with components - [Composable App Cookbook](./composable-app.md) - Creating projects with components
- [Landing Page Cookbook](./landing-page.md) - Simple single-component sites - [Landing Page Cookbook](./landing-page.md) - Simple single-component sites
- [Composable Monorepo Guide](../.claude/guides/services/composable-monorepo.md) - [Composable Monorepo Guide](../.claude/guides/services/composable-monorepo.md)
- [API Framework Guide](../.claude/guides/packages/api-framework.md) - [API Framework Guide](../.claude/guides/packages/api-framework.md)
- [SDLC Guide](../.claude/guides/services/sdlc.md) - Full SDLC orchestration documentation

View File

@ -0,0 +1,493 @@
#!/bin/bash
set -euo pipefail
# Feature Development E2E Test Script
# Tests the complete Claude Code + SDLC feature development workflow:
# 1. Create composable project with skeleton
# 2. Add service component
# 3. Create SDLC feature via API
# 4. Invoke Claude to generate spec (via /builds with skeleton command)
# 5. Approve spec via API
# 6. Invoke Claude to generate design
# 7. Approve design via API
# 8. Invoke Claude to break down tasks
# 9. Approve tasks via API
# 10. Invoke Claude to implement first task
# 11. Verify code was generated
# 12. Teardown
#
# Usage: ./cookbooks/scripts/feature-dev-test.sh <command> <project-name>
# Commands: run, status, teardown
#
# This is the definitive E2E test for the SDLC + Claude Code integration.
# It exercises the full feature development workflow from project creation
# to implemented code.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"
# Parse --auto-teardown flag from args
ARGS=("$@")
for i in "${!ARGS[@]}"; do
if [[ "${ARGS[$i]}" == "--auto-teardown" ]]; then
AUTO_TEARDOWN="true"
unset 'ARGS[$i]'
fi
done
ARGS=("${ARGS[@]}") # Re-index array
COMMAND="${ARGS[0]:-}"
PROJECT_NAME="${ARGS[1]:-}"
FEATURE_SLUG="add-hello-endpoint"
# Register cleanup trap for auto-teardown
register_cleanup_trap
if [[ -z "$COMMAND" || -z "$PROJECT_NAME" ]]; then
echo "Feature Development E2E Test Script"
echo ""
echo "Tests the complete Claude Code + SDLC feature development workflow."
echo ""
echo "Usage: $0 <command> <project-name> [--auto-teardown]"
echo ""
echo "Commands:"
echo " run - Execute full feature development flow"
echo " status - Check project and SDLC status"
echo " teardown - Delete the project"
echo ""
echo "Examples:"
echo " $0 run feature-dev-test"
echo " $0 run test-feat --auto-teardown"
echo " $0 status feature-dev-test"
echo " $0 teardown feature-dev-test"
echo ""
echo "Environment Variables:"
echo " RDEV_API_URL - rdev API base URL"
echo " RDEV_API_KEY - rdev API key"
echo " GITEA_TOKEN - Gitea API token (optional, for repo verification)"
exit 1
fi
# Check response for success/error
check_response() {
local response="$1"
local step="$2"
local error
error=$(echo "$response" | jq -r '.error // ""')
if [[ -n "$error" && "$error" != "" && "$error" != "null" ]]; then
print_error "$step failed: $error"
echo "$response" | jq '.'
return 1
fi
return 0
}
# Wait for a build to complete
# Arguments: task_id step_name [max_attempts]
wait_for_build_step() {
local task_id="$1"
local step_name="$2"
local max_attempts="${3:-120}" # 10 minutes default (5s * 120)
local attempt=0
echo " Waiting for build to complete (task: $task_id)..."
while [[ $attempt -lt $max_attempts ]]; do
local result
result=$(api_call GET "/builds/$task_id")
local status
status=$(echo "$result" | jq -r '.data.status // .status // "unknown"')
case "$status" in
completed)
local success
success=$(echo "$result" | jq -r '.data.result.success // .result.success // false')
if [[ "$success" == "true" ]]; then
print_success "$step_name completed successfully"
return 0
else
print_error "$step_name completed but failed:"
echo "$result" | jq '.data.result // .result'
return 1
fi
;;
failed)
print_error "$step_name failed:"
echo "$result" | jq '.'
return 1
;;
running)
echo " Build running... (attempt $((attempt + 1))/$max_attempts)"
;;
pending)
echo " Build pending... (attempt $((attempt + 1))/$max_attempts)"
;;
*)
echo " Unknown status: $status (attempt $((attempt + 1))/$max_attempts)"
;;
esac
sleep 5
((attempt++))
done
print_error "Timeout waiting for $step_name to complete"
return 2
}
# Submit a build and wait for completion
# Arguments: project_id prompt step_name
submit_build_and_wait() {
local project_id="$1"
local prompt="$2"
local step_name="$3"
local git_owner
git_owner=$(get_git_owner)
local git_clone_url="https://git.threesix.ai/${git_owner}/${project_id}.git"
echo " Submitting build: $prompt"
local payload
payload=$(jq -n \
--arg prompt "$prompt" \
--arg git_clone_url "$git_clone_url" \
'{
prompt: $prompt,
auto_commit: true,
auto_push: true,
git_clone_url: $git_clone_url
}')
local result
result=$(api_call POST "/projects/$project_id/builds" "$payload")
if ! check_response "$result" "Submit build"; then
return 1
fi
local task_id
task_id=$(echo "$result" | jq -r '.data.task_id // .task_id // ""')
if [[ -z "$task_id" ]]; then
print_error "No task_id in response"
echo "$result" | jq '.'
return 1
fi
wait_for_build_step "$task_id" "$step_name"
}
# Approve an SDLC artifact
# Arguments: project_id feature_slug artifact_type
approve_artifact() {
local project_id="$1"
local feature_slug="$2"
local artifact_type="$3"
echo " Approving $artifact_type artifact..."
local result
result=$(api_call POST "/projects/$project_id/sdlc/features/$feature_slug/artifacts/$artifact_type/approve" "{}")
if check_response "$result" "Approve $artifact_type"; then
print_success "$artifact_type artifact approved"
return 0
fi
return 1
}
# Add a component to the project
add_component() {
local comp_type="$1"
local comp_name="$2"
echo "Adding $comp_type component: $comp_name"
local payload
payload=$(jq -n \
--arg type "$comp_type" \
--arg name "$comp_name" \
'{type: $type, name: $name}')
local result
result=$(api_call POST "/projects/$PROJECT_NAME/components" "$payload")
local path
path=$(echo "$result" | jq -r '.data.path // .path // ""')
if [[ -z "$path" ]]; then
print_error "Failed to add component"
echo "$result" | jq '.'
return 1
fi
print_success "Added $comp_type/$comp_name at $path"
return 0
}
# Verify the feature artifacts exist in Gitea
verify_artifacts() {
local project_id="$1"
local feature_slug="$2"
local git_owner
git_owner=$(get_git_owner)
print_header "Verifying Feature Artifacts"
local artifacts=("spec.md" "design.md" "tasks.md")
local all_found=true
for artifact in "${artifacts[@]}"; do
local path=".sdlc/features/$feature_slug/$artifact"
echo " Checking $path..."
local check
check=$(curl -s "https://git.threesix.ai/api/v1/repos/$git_owner/$project_id/contents/$path" \
-H "Authorization: token ${GITEA_TOKEN:-}" 2>/dev/null | jq -r '.name // "not found"')
if [[ "$check" == "$artifact" ]]; then
print_success " $artifact exists"
else
print_warning " $artifact not found"
all_found=false
fi
done
if [[ "$all_found" == "true" ]]; then
print_success "All artifacts verified"
return 0
else
print_warning "Some artifacts missing (may still be propagating)"
return 0 # Don't fail on verification, may be timing
fi
}
# Main run flow
run_flow() {
print_header "Feature Development E2E Test"
echo "Project: $PROJECT_NAME"
echo "Feature: $FEATURE_SLUG"
echo ""
# =========================================================================
# Step 1: Create project skeleton
# =========================================================================
print_header "Step 1: Creating project skeleton"
local create_payload
create_payload=$(jq -n \
--arg name "$PROJECT_NAME" \
--arg desc "Feature development E2E test" \
'{name: $name, description: $desc}')
local create_result
create_result=$(api_call POST "/project" "$create_payload")
echo "$create_result" | jq '.'
local domain
domain=$(echo "$create_result" | jq -r '.data.domain // .domain // ""')
if [[ -z "$domain" ]]; then
print_error "Failed to create project"
exit 1
fi
# Track project for auto-cleanup
CLEANUP_PROJECT="$PROJECT_NAME"
print_success "Project created with domain: $domain"
# =========================================================================
# Step 2: Add service component
# =========================================================================
print_header "Step 2: Adding service component"
if ! add_component "service" "api"; then
exit 1
fi
# Wait for git sync
echo " Waiting for git sync..."
sleep 10
# =========================================================================
# Step 3: Create SDLC feature via build (using worker pod)
# =========================================================================
# Note: Composable projects don't have dedicated pods, so we use builds
# to execute SDLC commands on worker pods that clone the repo.
print_header "Step 3: Creating SDLC feature via build"
# Initialize SDLC and create feature in one build
if ! submit_build_and_wait "$PROJECT_NAME" \
"Initialize SDLC for this project and create a feature with slug '$FEATURE_SLUG' and title 'Add /hello endpoint to API service'. Use the sdlc CLI: 'sdlc init' then 'sdlc feature create $FEATURE_SLUG \"Add /hello endpoint to API service\"'" \
"SDLC initialization"; then
print_error "SDLC initialization failed"
exit 1
fi
# =========================================================================
# Step 4: Generate spec via Claude
# =========================================================================
print_header "Step 4: Claude generates spec"
if ! submit_build_and_wait "$PROJECT_NAME" "/spec-feature $FEATURE_SLUG" "Spec generation"; then
print_error "Spec generation failed"
exit 1
fi
# =========================================================================
# Step 5: Approve spec via build
# =========================================================================
print_header "Step 5: Approve spec"
if ! submit_build_and_wait "$PROJECT_NAME" \
"Approve the spec artifact for feature $FEATURE_SLUG using: sdlc artifact approve $FEATURE_SLUG spec" \
"Spec approval"; then
print_warning "Spec approval may have failed, continuing..."
fi
# =========================================================================
# Step 6: Generate design via Claude
# =========================================================================
print_header "Step 6: Claude generates design"
if ! submit_build_and_wait "$PROJECT_NAME" "/design-feature $FEATURE_SLUG" "Design generation"; then
print_error "Design generation failed"
exit 1
fi
# =========================================================================
# Step 7: Approve design via build
# =========================================================================
print_header "Step 7: Approve design"
if ! submit_build_and_wait "$PROJECT_NAME" \
"Approve the design artifact for feature $FEATURE_SLUG using: sdlc artifact approve $FEATURE_SLUG design" \
"Design approval"; then
print_warning "Design approval may have failed, continuing..."
fi
# =========================================================================
# Step 8: Break down into tasks via Claude
# =========================================================================
print_header "Step 8: Claude breaks down into tasks"
if ! submit_build_and_wait "$PROJECT_NAME" "/breakdown-feature $FEATURE_SLUG" "Task breakdown"; then
print_error "Task breakdown failed"
exit 1
fi
# =========================================================================
# Step 9: Approve tasks via build
# =========================================================================
print_header "Step 9: Approve tasks"
if ! submit_build_and_wait "$PROJECT_NAME" \
"Approve the tasks artifact for feature $FEATURE_SLUG using: sdlc artifact approve $FEATURE_SLUG tasks" \
"Tasks approval"; then
print_warning "Tasks approval may have failed, continuing..."
fi
# =========================================================================
# Step 10: Implement first task via Claude
# =========================================================================
print_header "Step 10: Claude implements first task"
# First task is typically T1
local first_task_id="T1"
echo " First task ID: $first_task_id"
if ! submit_build_and_wait "$PROJECT_NAME" "/implement-task $FEATURE_SLUG $first_task_id" "Task implementation"; then
print_error "Task implementation failed"
exit 1
fi
# =========================================================================
# Step 11: Verify artifacts exist
# =========================================================================
verify_artifacts "$PROJECT_NAME" "$FEATURE_SLUG"
# =========================================================================
# Summary
# =========================================================================
print_header "E2E Test Results"
print_success "Feature development flow completed!"
echo ""
echo " Project: $PROJECT_NAME"
echo " Feature: $FEATURE_SLUG"
echo " Domain: https://$domain"
echo " Git: https://git.threesix.ai/$(get_git_owner)/$PROJECT_NAME"
echo " CI: https://ci.threesix.ai/$(get_git_owner)/$PROJECT_NAME"
echo ""
echo "Workflow completed:"
echo " 1. Project skeleton created"
echo " 2. Service component added"
echo " 3. SDLC initialized + feature created (via build)"
echo " 4. Claude generated spec"
echo " 5. Spec approved"
echo " 6. Claude generated design"
echo " 7. Design approved"
echo " 8. Claude broke down into tasks"
echo " 9. Tasks approved"
echo " 10. Claude implemented first task"
echo ""
echo "View the feature artifacts at:"
echo " https://git.threesix.ai/$(get_git_owner)/$PROJECT_NAME/src/branch/main/.sdlc/features/$FEATURE_SLUG"
}
# Show status
check_status() {
print_header "Project Status: $PROJECT_NAME"
# Get project info
echo "Project:"
api_call GET "/project/$PROJECT_NAME" | jq '.data // .'
echo ""
# Get components
echo "Components:"
api_call GET "/projects/$PROJECT_NAME/components" | jq '.data // .'
echo ""
# Get recent builds
print_header "Recent Builds"
api_call GET "/projects/$PROJECT_NAME/builds?limit=10" | jq '.data.builds[:10] // .builds[:10] // []'
echo ""
# Note about SDLC status
echo "Note: SDLC status is stored in the git repo at .sdlc/"
echo "View at: https://git.threesix.ai/$(get_git_owner)/$PROJECT_NAME/src/branch/main/.sdlc"
}
# Teardown
teardown() {
print_header "Tearing down: $PROJECT_NAME"
local result
result=$(api_call DELETE "/project/$PROJECT_NAME")
echo "$result" | jq '.'
echo ""
print_success "Project deleted. Gitea repo preserved."
}
# Dispatch
case "$COMMAND" in
run)
run_flow
;;
status)
check_status
;;
teardown)
teardown
;;
*)
echo "Unknown command: $COMMAND"
echo "Valid commands: run, status, teardown"
exit 1
;;
esac

View File

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
# Feature Development E2E Test Script # Scaffold Validation E2E Test Script
# Tests the complete feature development workflow: # Tests the composable monorepo scaffold creation:
# 1. Create composable project with skeleton # 1. Create composable project with skeleton
# 2. Add service component # 2. Add service component
# 3. Add app-nextjs component # 3. Add app-nextjs component
@ -11,7 +11,10 @@ set -euo pipefail
# 6. Test auth integration # 6. Test auth integration
# 7. Verify CI pipeline # 7. Verify CI pipeline
# #
# Usage: ./cookbooks/scripts/feature-test.sh <command> <project-name> # NOTE: This tests scaffold creation and patterns, NOT feature development.
# For feature development E2E tests, see feature-dev-test.sh instead.
#
# Usage: ./cookbooks/scripts/scaffold-test.sh <command> <project-name>
# Commands: run, status, verify-patterns, teardown # Commands: run, status, verify-patterns, teardown
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

View File

@ -56,12 +56,10 @@ func (h *ProjectManagementHandler) Mount(r api.Router) {
Get("/{name}", h.Status) Get("/{name}", h.Status)
}) })
// Bulk operations on projects (admin only) // Bulk operations - cleanup test projects (admin only)
r.Route("/projects", func(r chi.Router) { // Note: Uses direct route to avoid conflict with /projects in projects.go
// Cleanup test projects - admin only for safety
r.With(auth.RequireScope(auth.ScopeAdmin)). r.With(auth.RequireScope(auth.ScopeAdmin)).
Delete("/cleanup", h.CleanupTestProjects) Delete("/projects/cleanup", h.CleanupTestProjects)
})
// Template endpoints (read-only) // Template endpoints (read-only)
r.With(auth.RequireScope(auth.ScopeProjectsRead, auth.ScopeAdmin)). r.With(auth.RequireScope(auth.ScopeProjectsRead, auth.ScopeAdmin)).

View File

@ -29,13 +29,15 @@ func NewSDLCOrchestratorHandler(orchestrator *service.SDLCOrchestratorService, l
} }
// Mount registers orchestration routes under /projects/{id}/sdlc/. // Mount registers orchestration routes under /projects/{id}/sdlc/.
// Note: Uses direct routes to avoid conflict with /projects/{id}/sdlc in sdlc.go
func (h *SDLCOrchestratorHandler) Mount(r api.Router) { func (h *SDLCOrchestratorHandler) Mount(r api.Router) {
r.Route("/projects/{id}/sdlc", func(r chi.Router) {
// All orchestration operations are write operations // All orchestration operations are write operations
r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).Post("/execute", h.Execute) r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).
r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).Post("/resolve", h.Resolve) Post("/projects/{id}/sdlc/execute", h.Execute)
r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).Post("/commit", h.Commit) r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).
}) Post("/projects/{id}/sdlc/resolve", h.Resolve)
r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).
Post("/projects/{id}/sdlc/commit", h.Commit)
} }
// Execute runs the next classifier-recommended action. // Execute runs the next classifier-recommended action.