Two distinct fixes: 1. Database terminology: Make it crystal clear that generated projects use CockroachDB in production and PostgreSQL for local dev, while the rdev platform itself uses PostgreSQL. Updated 15 files across skeleton agents, component templates, cookbook trees, and platform docs. 2. Video storage: VideoHandler was ignoring vid.Data bytes (already downloaded by the Gemini adapter with auth) and re-downloading from the provider URL with a plain GET — which fails because Gemini URLs require API key auth. Now uses vid.Data first, falls back to downloadURL only for public URLs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
149 lines
4.6 KiB
YAML
149 lines
4.6 KiB
YAML
name: authenticated-service
|
|
description: "Slack Path 1: Identity Layer. Implements User Auth, JWT generation, and Protected Middleware."
|
|
version: 1
|
|
|
|
vars:
|
|
project_name: ""
|
|
service_name: "auth-api"
|
|
feature_slug: "auth-system"
|
|
|
|
steps:
|
|
# --- Infrastructure ---
|
|
create-project:
|
|
action: api
|
|
method: POST
|
|
endpoint: /project
|
|
body:
|
|
name: "{{ .vars.project_name }}"
|
|
description: "Slack Path 1: Authentication"
|
|
outputs:
|
|
- project_id: .data.name
|
|
- domain: .data.domain
|
|
|
|
add-db:
|
|
description: Add CockroachDB for user storage
|
|
depends_on: [create-project]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/components"
|
|
body:
|
|
type: postgres
|
|
name: "main-db"
|
|
outputs:
|
|
- db_url: .data.connection_string
|
|
|
|
add-service:
|
|
description: Add API service
|
|
depends_on: [add-db]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/components"
|
|
body:
|
|
type: service
|
|
name: "{{ .vars.service_name }}"
|
|
template: service
|
|
|
|
wait-init:
|
|
depends_on: [add-service]
|
|
action: wait_pipeline
|
|
project_id: "{{ .outputs.create-project.project_id }}"
|
|
|
|
# --- SDLC: Build Auth ---
|
|
create-feature:
|
|
depends_on: [wait-init]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/sdlc/features"
|
|
body:
|
|
slug: "{{ .vars.feature_slug }}"
|
|
title: "Authentication System"
|
|
|
|
implement-auth:
|
|
description: "Agent implements Login, Register, and JWT Middleware"
|
|
depends_on: [create-feature]
|
|
action: api
|
|
method: POST
|
|
endpoint: "/projects/{{ .outputs.create-project.project_id }}/builds"
|
|
body:
|
|
prompt: "/implement-feature {{ .vars.feature_slug }} --requirements 'User model with email/password. POST /register, POST /login (returns JWT). Middleware that checks Authorization header. GET /me returns user profile.'"
|
|
auto_commit: true
|
|
auto_push: true
|
|
git_clone_url: "https://git.threesix.ai/jordan/{{ .outputs.create-project.project_id }}.git"
|
|
outputs:
|
|
- build_id: .data.task_id
|
|
|
|
wait-build:
|
|
description: Wait for agent code generation
|
|
depends_on: [implement-auth]
|
|
action: wait_build
|
|
build_id: "{{ .outputs.implement-auth.build_id }}"
|
|
max_attempts: 120
|
|
poll_interval: 5
|
|
|
|
wait-deploy:
|
|
depends_on: [wait-build]
|
|
action: wait_pipeline
|
|
project_id: "{{ .outputs.create-project.project_id }}"
|
|
|
|
# --- Verification ---
|
|
verify-service-running:
|
|
description: "Verify the auth service is running and reachable"
|
|
depends_on: [wait-deploy]
|
|
action: shell
|
|
command: |
|
|
DOMAIN="{{ .outputs.create-project.domain }}"
|
|
SERVICE_NAME="{{ .vars.service_name }}"
|
|
|
|
# Check health endpoint
|
|
HEALTH=$(curl -s "https://$DOMAIN/api/$SERVICE_NAME/health" | jq -r '.data.status // empty')
|
|
if [ "$HEALTH" == "healthy" ]; then
|
|
echo "Service healthy: /api/$SERVICE_NAME/health returned healthy"
|
|
exit 0
|
|
else
|
|
echo "Fail: service not healthy"
|
|
exit 1
|
|
fi
|
|
|
|
verify-login-flow:
|
|
description: "Register -> Login -> Access Protected Route (optional - depends on agent implementation)"
|
|
depends_on: [verify-service-running]
|
|
on_error: continue
|
|
action: shell
|
|
command: |
|
|
DOMAIN="{{ .outputs.create-project.domain }}"
|
|
SERVICE_NAME="{{ .vars.service_name }}"
|
|
PROJECT_ID="{{ .outputs.create-project.project_id }}"
|
|
EMAIL="test-${PROJECT_ID}@example.com"
|
|
BASE_URL="https://$DOMAIN/api/$SERVICE_NAME"
|
|
|
|
# 1. Register
|
|
echo "Registering $EMAIL..."
|
|
REGISTER_RESP=$(curl -s -X POST "$BASE_URL/register" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"email\":\"$EMAIL\",\"password\":\"hunter2\"}")
|
|
echo "Register response: $REGISTER_RESP"
|
|
|
|
# 2. Login
|
|
echo "Logging in..."
|
|
LOGIN_RESP=$(curl -s -X POST "$BASE_URL/login" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"email\":\"$EMAIL\",\"password\":\"hunter2\"}")
|
|
echo "Login response: $LOGIN_RESP"
|
|
TOKEN=$(echo "$LOGIN_RESP" | jq -r .token)
|
|
|
|
if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then
|
|
echo "Failed: Could not get token from login response"
|
|
exit 1
|
|
fi
|
|
|
|
# 3. Access Protected
|
|
echo "Accessing protected route..."
|
|
RESP=$(curl -s -H "Authorization: Bearer $TOKEN" "$BASE_URL/me")
|
|
echo "Protected response: $RESP"
|
|
if echo "$RESP" | grep -q "$EMAIL"; then echo "Login flow OK"; exit 0; else echo "Failed: Email not found in response"; exit 1; fi
|
|
|
|
teardown:
|
|
- action: api
|
|
method: DELETE
|
|
endpoint: "/project/{{ .outputs.create-project.project_id }}"
|