Session WebUI:
- Add `web_ui` flag to session create — launches claude-code-ui in pod on port 3001
- Install @siteboon/claude-code-ui in claudebox Dockerfile, expose port 3001
- Migration 027: add web_ui column to sessions table
- startWebUI/stopWebUI fire-and-forget helpers in SessionsHandler
- Service selects preview port 3001 (web UI) vs 8080 (sidecar) based on flag
Aeries Daeya cookbook:
- Add cookbooks/trees/aeries-daeya.yaml: privacy-first avatar social platform
(infra → avatar data model → AI generation pipeline → studio UI)
- Add cookbooks/scripts/aeries-daeya-test.sh: run/status/diagnose/teardown harness
- Fix race condition in common.sh wait_for_pipeline: detect already-running pipelines
at startup and track directly instead of waiting for a newer one
Docs/tooling:
- Add SDK Update Workflow section to CLAUDE.md
- Add `make sdk` and `make sdk-check` targets for OpenAPI spec management
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace per-project notify host provisioning (7-9 API calls + DNS + async
Resend verification) with a shared platform host for all *.threesix.ai projects.
Under the new model:
- CreateProjectNotify: 3 calls only (account + send key + host grant)
- No per-project Resend domain, DNS records, or async verification
- All *.threesix.ai projects share `threesix.ai` as the platform host
- Custom domains still get a dedicated host via ReprovisionNotifyHost
Changes:
- domain/notify.go: slim NotifyCredentials (no Host/From/ResendDomainID);
add NotifyHostCredentials for reprovision return path
- port/notify_provisioner.go: update interface signatures and docs
- adapter/notify/provisioner.go: rewrite CreateProjectNotify (3 steps);
rewrite DeleteProjectNotify (account-only vs full cleanup)
- adapter/notify/provisioner_reprovision.go: return *NotifyHostCredentials
- adapter/notify/provisioner_test.go: update tests for new model
- service/project_infra_crud.go: store only NOTIFY_API_KEY on provision
- domain/credential.go: add CredKeyNotifySharedHost/CredKeyNotifySharedFrom
- cmd/rdev-api/config.go: add NotifySharedHost/NotifySharedFrom to InfraConfig
- service/component.go: add notifySharedHost/notifySharedFrom + WithNotifyDefaults
- service/component_deploy.go: inject shared host defaults when no custom host stored
- handlers/notify.go: handle shared-host projects in Reprovision guard;
add WithSharedNotifyHost builder
- cmd/rdev-api/main.go: wire SharedHost to provisioner, component service,
and notify handler
Bootstrap: NOTIFY_SHARED_HOST=threesix.ai and NOTIFY_SHARED_FROM=noreply@threesix.ai
stored in credential store (host id=1 already provisioned with Resend provider).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Changes
### port.Deployer interface
- Add PatchProjectSecrets(ctx, projectName, patch) to merge key-value pairs
into all K8s secrets labeled project={projectName}
- Add RestartAll(ctx, projectName) to trigger rolling restart of all deployments
for a project, picking up fresh secrets without waiting for CI
### deployer adapter
- Implement PatchProjectSecrets: lists secrets by label, merges patch into Data,
writes each secret back
- Implement RestartAll: lists deployments by label, sets restartedAt annotation
### domain/credential.go
- Add CredentialCategoryCache = "cache" constant
- Use constant in component_infra.go (was raw string "cache")
### handlers/cache.go (new)
- POST /projects/{projectID}/cache/reprovision
- Calls CreateProjectCache (which handles delete+recreate with new password)
- Updates credential store (REDIS_URL, REDIS_URL_STAGING, REDIS_PREFIX)
- Patches all K8s secrets for the project immediately
- Triggers RestartAll so pods pick up new credentials without waiting for deploy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add claude_id field to sessions (migration 026) for tracking Claude
process IDs across pod restarts
- Extend session repository with UpdateClaudeID and session lookup methods
- Improve kubernetes executor with better error handling and exec streaming
- Add claudebox client/server improvements for session lifecycle
- Expand sessions handler with exec streaming endpoint
- Add comprehensive tests for sessions and kubernetes executor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add verifyWithRetry to provisioner: 60s initial DNS propagation delay,
5 retries with 30s backoff before marking verification as failed
- Add GetNotifyDomainStatus: polls Resend API for domain verification status,
returns "not_configured" when Resend not set up
- Add VerifyProjectNotify: synchronous re-verification for handler use
- Add getDomainStatus to resendAPI interface + resendClient implementation
- Add NotifyDomainStatus domain struct (host, resend_domain_id, status)
- Guard NOTIFY_RESEND_DOMAIN_ID storage against empty string writes
- New handler: GET /projects/{id}/notify/status (returns verification state)
- New handler: POST /projects/{id}/notify/verify (triggers re-verification)
- Add verify-notify-domain cookbook step to persona-community,
slackpath-1, and slackpath-4 trees (polls status for up to 6 min)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AddComponentBatch was missing the SERVICE_NAME injection that AddComponent
has. When an app-react component (e.g. creator-ui) was rendered via the
batch endpoint alongside a service component, {{SERVICE_NAME}} in App.tsx.tmpl
was never substituted — rendering the literal string into the repo.
Fix: scan the batch's own code requests for a service component first
(since the service isn't in the DB yet during batch processing), then
fall back to findFirstServiceComponent from DB.
This is the same AddComponent vs AddComponentBatch parity gap that caused
the JWT_SECRET issue (RC-2). The auth API URL in every app-react project
was broken when deployed via the batch endpoint.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs fixed:
1. redis.Nil not handled in GetProjectCache: When ACL GETUSER returns nil
(user doesn't exist), go-redis represents this as redis.Nil error. The
provisioner only checked for err.Contains("User") which didn't match,
causing spurious "get ACL user: redis: nil" errors on re-provision.
2. provisionRedis returns 409 even when REDIS_URL not in credential store:
If the Redis ACL user exists but REDIS_URL was never stored (e.g., due
to a failed previous run or lost state), the service would permanently
refuse to provision, leaving the project without usable Redis credentials.
Now checks the credential store: if REDIS_URL exists → true 409 duplicate;
if REDIS_URL missing → re-provision (CreateProjectCache resets the password).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AddComponent (single-component path) already calls ensureProjectJWTSecret,
but AddComponentBatch has its own parallel implementation that bypassed it.
Components added via the /batch endpoint never had JWT_SECRET provisioned,
causing CrashLoopBackOff on startup ("JWT_SECRET must be set").
Add the call before the createInitialComponentDeployment loop so the secret
is stored in the credential store before K8s Secrets are created.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
RC-1: Workers now get a Kubernetes Deployment on component creation.
NeedsPort() (port assignment) was incorrectly used to gate Deployment
creation - workers have no HTTP port but still need a Deployment so
CI `kubectl set image` can succeed. Added NeedsDeployment() returning
true for service/worker/app-react/app-astro/app-nextjs. AddIngressPath
is now guarded by port > 0 so workers don't attempt HTTP routing.
RC-2: JWT_SECRET is now auto-provisioned per-project when the first
code component is added. The skeleton service template fatally requires
JWT_SECRET at startup; previously fetchProjectCredentials() never fetched
it. ensureProjectJWTSecret() generates a cryptographically random 32-byte
secret, stores it as "{projectID}:JWT_SECRET", and JWT_SECRET is now
included in projectScopedKeys so it's injected into every deployment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix no-op RequireProjectAccess middleware to enforce project_ids
- Apply project access middleware to all project-scoped routes
- Filter GET /projects by allowed project IDs for restricted keys
- Add GET /me endpoint with key identity, scopes, and project access info
- Add PATCH /keys/{id} for partial key updates (name, scopes, project_ids, allowed_ips, expires_in)
- Add GET/POST/DELETE /projects/{id}/access for project-centric access management
- Auto-grant creating key access when using POST /project/create-and-build
- Accept grant_to_key_ids in create-and-build to grant multiple keys on project creation
- Move newProvisionerWithDeps test helper from production code to test file
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add NotifyProvisioner (port + adapter) using real notify admin API
- Create notify account + send key + host grant per project
- Inject NOTIFY_API_KEY/HOST/FROM into component deployments
- Store NOTIFY_URL, NOTIFY_ADMIN_KEY, RESEND_API_KEY in credential store
- Add setup-notify.sh for one-time host/provider/domain setup
- Add NOTIFY_ADMIN_KEY constant to domain/credential.go
- Wire provisioner in main.go with connection test guard
- Add .claude/guides/services/notify.md and CLAUDE.md entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds complete media storage pipeline with GCS presigned uploads, AI image/video/text generation
via queue-based workers, realtime SSE event streaming, and comprehensive skeleton packages
(storage, mediagen, textgen, generation, realtime, persona, routing, ai-client). Includes
security fixes for media delete authorization, nil pointer guards in handlers, video persistence
via download-then-upload, consistent signed URLs, and Image→ImageIcon rename to avoid DOM collision.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add TimeoutAgentExecution (22m) to handlers for synchronous SDLC
execution, and TimeoutAgent{Default,Medium,Heavy} (12/22/47m) to
workers for tiered agent task execution. Aligns with SDLC action
complexity tiers and prevents inline duration literals.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The architect API returned "failed to start conversation" because
projectRepo.Get() failed — the in-memory K8s repo watches the rdev
namespace but projects deploy to the projects namespace. Made project
lookup non-fatal with fallback to default pod. Added error logging to
all architect handler methods (were silently swallowing errors).
Also adds setup-hooks, commit-after-qa, and pre-merge-validate steps
to the foundary cookbook tree for git hooks and code quality gates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The architect service was missing pod_name/namespace in AgentRequest
metadata, causing Claude Code adapter to reject all requests. Added
ArchitectServiceConfig with pod resolution (project PodName → default
claudebox-0). Removed silent JSON fallback in extractSpecFromMessages
that masked errors.
Rewrote foundary cookbook from 90-step SDLC flow to focused 25-step
cookbook using natural language build prompts instead of /slash-commands
that claudebox cannot execute. Added "no fallbacks" rule to CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Components are scaffolded before CI builds their images. Previously deployments
started with 1 replica, causing ImagePullBackOff until the first build completed.
Now deployments start at 0 replicas; CI deploy steps scale to 1 after verifying
the image exists in the registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add --connect-timeout 10 and --max-time 15 to all verify step curl
calls to prevent hanging on registry health checks
- Fix cli template: depends_on [deps] -> [preflight] for consistency
- Add cross-reference comment to service template about verify logic
being replicated across all 5 component templates
- Document component CI step rules in composable-monorepo.md
- Compile regexes at package level instead of per-call in
component_updates.go
- Add component_updates_test.go
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add UndeployAll() using label selectors to clean up monorepo components
on project deletion (replaces name-based Undeploy in DeleteProject and
the direct undeploy handler)
- Add ResourceGC background worker that periodically finds K8s resources
whose project label has no matching DB record, deletes after 1h safety
window
- Widen deployer client type from *kubernetes.Clientset to
kubernetes.Interface for testability
- UndeployAll accumulates errors via errors.Join instead of failing fast
- Add checkout/checkin sidecar dev flow: temporary git tokens, branch
checkout, review on checkin with cleanup workers
- Add interactive sessions: pod binding, command execution, SSE streaming,
ephemeral preview URLs with session cleanup workers
- Add GET /workers/pool endpoint for aggregate capacity and queue depth
- Add sessions:read and sessions:execute auth scopes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements all 5 phases of Foundary Studio backend:
Phase 1: Chat Persistence (8 API endpoints)
- Conversations and messages with proper cascading deletes
- PostgreSQL schema with auto-update triggers
- Full CRUD operations with structured logging
Phase 2: Blueprint Entity (5 API endpoints)
- JSONB spec storage with GIN indexes
- Flexible structured data for project specifications
- Version-controlled blueprint management
Phase 3: Architect Service (3 API endpoints)
- Conversational AI orchestration with Claude
- Multi-turn dialogue with context building
- Blueprint spec extraction from conversations
Phase 4: Work Queue Integration
- Verified existing endpoint compatibility
Phase 5: Structured Questions (6 API endpoints)
- Four question types: text, choice, multichoice, yesno
- Answer validation with proper constraints
- Conversation-linked Q&A flow
Architecture:
- Textbook hexagonal architecture (domain → port → adapter → service → handler)
- Zero external dependencies in domain layer
- Consistent error handling with proper wrapping
- Auth scopes on all routes (projects:read, projects:execute)
- Structured logging with operation context and duration tracking
- NULL-safe DTO converters throughout
Database:
- 3 new migrations (019, 020, 021)
- UUIDs for all primary keys
- Proper foreign key constraints with ON DELETE CASCADE
- Optimized indexes including partial index for unanswered questions
- Auto-update triggers for timestamps
OpenAPI Documentation:
- Complete API documentation under 'Foundary' tag
- 22 new endpoints documented with examples
- Request/response schemas for all operations
Logging Improvements:
- Added operation field to all service logs
- Added duration_ms tracking for performance monitoring
- Log response_length instead of full response content
- Consistent use of logging field constants
- Execute-then-log pattern for delete operations
Files: 32 changed, 2800+ lines added
- 7 domain models
- 3 database migrations
- 3 port interfaces
- 3 postgres adapters
- 4 services (conversation, blueprint, question, architect)
- 4 handlers with DTOs
- OpenAPI documentation
- Integration in main.go
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Root cause of DIGEST_INVALID errors was registry disk exhaustion.
Project teardown wasn't cleaning up container images, causing the
registry PVC to fill up over time.
Changes:
- Add RegistryProvider port interface for registry operations
- Extend zot.Client with DeleteProjectRepositories method
- Wire registry provider into ProjectInfraService
- Delete images during DeleteProject cleanup (step 4)
The zot client uses the OCI distribution API:
- Lists all repos, filters by project prefix
- Gets manifest digests via HEAD request
- Deletes manifests by digest to trigger GC
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
When req.Template is empty, it defaults to 'skeleton' but the check
in createInitialDeployment only matched 'skeleton' explicitly, not
empty string. This caused a broken deployment to be created for
monorepo projects with a non-existent image.
Root cause: slackpath-5 creates project with empty template, which
defaults to skeleton, but createInitialDeployment was still creating
a root deployment that references registry.threesix.ai/{project}:latest
which never gets built (skeleton has no root Dockerfile).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds complete Slate documentation infrastructure to generated projects:
- docs/ directory with Gemfile, config.rb, and source templates
- Dockerfile for building docs site
- Dockerfile.nginx for serving static docs
- generate-docs.sh script for CI integration
- Claude command for AI-assisted docs generation
- OpenAPI → Slate markdown conversion via widdershins
Also includes:
- --export-openapi flag for service binaries
- DNS provisioning for docs.{domain} subdomain
- Updated project_infra for docs DNS records
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Critical fix: WorkersHandler was missing workService dependency, causing
500 errors when workers tried to fail tasks. This caused tasks to get
stuck in "running" state permanently.
Also adds:
- /work/tasks endpoint for debugging all tasks across projects
- List method to WorkQueue interface for admin views
- HTTP client tests for api_client.go and claudebox/client.go (48 tests)
- Split work.go DTOs into work_dto.go to stay under 500 lines
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Three coordinated fixes for CI pipeline race conditions:
1. Woodpecker step dependencies: Added depends_on: [deps] to all 6 component
templates (service, worker, cli, app-astro, app-react, app-nextjs) so build
steps wait for go work sync to complete.
2. Idempotent resource provisioning: Modified provisionResources() to check
for existing database/cache before creating, preventing "already exists"
errors on component re-adds.
3. Batch component endpoint: POST /projects/{id}/components/batch enables
atomic multi-component additions in a single git commit. Validates all
components upfront, provisions infra sequentially, commits code components
atomically.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Components now automatically receive DATABASE_URL, REDIS_URL, and other
infrastructure credentials when deployed. Previously, credentials were
provisioned and stored but never injected into K8s deployments.
Changes:
- Add fetchProjectCredentials() to component_deploy.go
- Populate spec.Secrets before calling deployer.Deploy()
- Fix slackpath-4 to provision postgres + redis before services
- Add terminology docs to clarify platform vs skeleton code
This completes the infrastructure provisioning flow:
1. add-db → provisions CockroachDB, stores DATABASE_URL
2. add-service → deploys with DATABASE_URL in environment
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Worker template fixes:
- Replace panic() with logger.Error() + os.Exit(1) for config errors
- Remove double-timeout application (context + middleware)
- Add error message truncation to prevent log bloat
- Use named constants for shutdown grace period and stale check interval
Skeleton pkg/auth fixes:
- Fix error wrapping to use %w consistently in jwt.go
- Add GetUserOrError() as safe alternative to MustGetUser() panic
Skeleton pkg/queue fixes:
- Check RowsAffected() errors instead of ignoring them
- Add input validation to EnqueueWithOptions (require job type, cap retries)
- Add log truncation for error messages
- Fix inaccurate doc comment claiming exponential backoff
Worker timeout consolidation:
- Add internal/worker/timeouts.go with named constants
- Migrate all workers to use timeout constants
Cleanup:
- Remove obsolete slack-preparation-thoughts.md files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major changes:
- Add internal/logging package with field constants, context propagation,
sensitive data auto-redaction, and per-component log levels
- Add worker timeout constants (TimeoutQuickOp, TimeoutHealthCheck, etc.)
- Extend SDLC with callback handlers, generate endpoints, and executor
- Add new cookbook trees for aeries and slackpath progression
- Add skeleton templates for queue, realtime, and microservices
- Add worker component template with async job processing
- Refactor services and handlers to use new logging infrastructure
- Split component.go into component_infra.go and component_listing.go
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds AddIngressPath and RemoveIngressPath to the Deployer interface
for managing per-component ingress rules in monorepo projects.
- Implement conflict retry logic for concurrent ingress updates
- Add K8s client interface for testability
- Add comprehensive unit tests for ingress path operations
- Add component deployment and teardown methods to ComponentService
- Update service templates with OpenAPI spec improvements
- Add evolving-app cookbook tree for reference
- Split resources.go into resources_ingress.go for path-based routing
- Split component.go into component_deploy.go for deployment helpers
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add REST API endpoints for submitting visual verification tasks,
tracking progress via SSE, and retrieving screenshot/video artifacts.
Changes:
- Add ScopeVerifyRead/ScopeVerifyWrite auth scopes
- Create VerifyService for task submission and lifecycle management
- Create VerifyHandler with POST/GET/DELETE/SSE endpoints:
- POST /verify - Submit capture task
- GET /verify/{taskId} - Get task status and artifacts
- GET /verify/{taskId}/stream - SSE progress stream
- DELETE /verify/{taskId} - Cancel pending task
- GET /projects/{id}/verify - List verify tasks
- Wire VerifyExecutor in main.go for Playwright pod execution
- Fix work.go validation to include "verify" task type
- Add comprehensive handler tests
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add /diagnostics endpoint for system health overview
- Add external health worker for monitoring Gitea, Woodpecker, Registry
- Add health check methods to Gitea and Woodpecker clients
- Remove hardcoded fallback projects (pantheon, aeries)
- Add diagnostics domain types and service layer
- Add comprehensive tests for diagnostics handler and service
- Fix tests to use registered test project instead of hardcoded one
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add WorkErrorCode type with RATE_LIMITED, AUTH_FAILED, TIMEOUT, STALE_WORKER, AGENT_ERROR, INVALID_SPEC
- Add ClassifyAgentError function to detect error patterns from stderr
- Add error_code column to work_queue table (migration 016)
- Add FailWithCode method to WorkQueue interface and implementations
- Update RequeueStaleWithIDs to mark permanently failed tasks with STALE_WORKER
- Add ErrorCode to BuildResult for API responses
- Update work executor to classify errors before failing tasks
This enables users to see actual failure reasons (e.g., "RATE_LIMITED") instead of
builds stuck in "running" state forever when Claude hits rate limits.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add pass/fail/needs-fix CLI commands to cmd/sdlc/cmd_artifact.go
- Add 3 new methods to SDLCExecutor interface in internal/port
- Implement methods in kubernetes adapter
- Add service methods to SDLCService
- Add HTTP handlers for POST .../artifacts/{type}/pass|fail|needs-fix
- Update 6 skeleton commands to evaluate and set artifact status
- Update test mocks
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add AUTO_TEARDOWN env var and --auto-teardown flag to cookbook scripts
- Scripts automatically delete created projects on exit (including Ctrl+C)
- Add DELETE /projects/cleanup API endpoint for bulk cleanup
- Supports shell-style glob patterns (e.g., "tree-test-*")
- Includes dry_run mode and older_than_hours filter for safety
- Requires admin scope for actual deletion
- Update cookbook scripts: landing-test, composable-test, template-validation,
feature-test, tree-runner
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add branch lifecycle commands (branch, merge, archive) to the SDLC CLI.
Introduce orchestrator handler and service for multi-step SDLC workflows.
Expand skeleton template with 15 Claude commands covering the full feature
lifecycle. Extend classifier rules, error types, and executor port for
branch operations. Split rules.go and classifier_test.go to stay within
500-line limit.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add deploy-{name} CI steps to all component templates (app-astro,
app-react, service, worker) so each component deploys independently
via kubectl set image on merge to main. Replace the skeleton's
generic deploy step with a verify step that confirms deployments.
Add GET /templates/components endpoint for listing available component
templates with optional type filter. Simplify component API by merging
type+template into a single type field (e.g., "app-react" instead of
type="app" template="app-react").
Include ESLint configs and pnpm-workspace.yaml in app templates.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
When a worker dies mid-build, queue maintenance now updates both
work_queue and build_audit tables when requeuing stale tasks.
This prevents builds from showing "running" forever in the API.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Root cause: WorkerService.ClaimTask() was modifying the audit entry
in memory but never persisting it to the database. This caused build
tasks to remain stuck at "pending" status even after being claimed.
Changes:
- Add UpdateStatus method to port.BuildAudit interface
- Implement UpdateStatus in postgres.BuildAuditRepository
- Fix ClaimTask to call audit.UpdateStatus() to persist status
- Add test coverage for audit update during task claim
- Update all mock implementations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Initial K8s deployment auto-creation during project creation
- DNS record upsert support (create or update existing records)
- Ingress host management for domain aliases (AddIngressHost/RemoveIngressHost)
- Woodpecker deployer RBAC manifest for CI deploy steps
- Single-commit template seeding via Gitea bulk file API
Closes automation gaps exposed during www.threesix.ai launch:
- Projects now auto-create K8s Deployment/Service/Ingress on creation
- Domain aliases automatically update both DNS and K8s ingress
- CI deploy steps work without manual RBAC setup
- Template seeding triggers only one CI pipeline (not per-file)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>