rdev/internal/handlers/sdlc_orchestrator.go
jordan d69da6d627 feat: add structured logging infrastructure and SDLC extensions
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>
2026-02-04 22:56:04 -07:00

120 lines
3.2 KiB
Go

package handlers
import (
"context"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/orchard9/rdev/internal/auth"
"github.com/orchard9/rdev/internal/service"
"github.com/orchard9/rdev/pkg/api"
)
// SDLCOrchestratorHandler handles SDLC orchestration endpoints.
type SDLCOrchestratorHandler struct {
orchestrator *service.SDLCOrchestratorService
}
// NewSDLCOrchestratorHandler creates a new orchestrator handler.
func NewSDLCOrchestratorHandler(orchestrator *service.SDLCOrchestratorService) *SDLCOrchestratorHandler {
return &SDLCOrchestratorHandler{
orchestrator: orchestrator,
}
}
// 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) {
// All orchestration operations are write operations
r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).
Post("/projects/{id}/sdlc/execute", h.Execute)
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.
// POST /projects/{id}/sdlc/execute
func (h *SDLCOrchestratorHandler) Execute(w http.ResponseWriter, r *http.Request) {
projectID := chi.URLParam(r, "id")
var req service.ExecuteRequest
if err := api.DecodeJSON(r, &req); err != nil {
api.WriteBadRequest(w, r, "invalid request body")
return
}
if req.Feature == "" {
api.WriteBadRequest(w, r, "feature is required")
return
}
ctx, cancel := context.WithTimeout(r.Context(), TimeoutLongRunning)
defer cancel()
result, err := h.orchestrator.ExecuteAction(ctx, projectID, &req)
if err != nil {
writeSDLCError(w, r, err)
return
}
api.WriteSuccess(w, r, result)
}
// Resolve unblocks a feature and re-classifies.
// POST /projects/{id}/sdlc/resolve
func (h *SDLCOrchestratorHandler) Resolve(w http.ResponseWriter, r *http.Request) {
projectID := chi.URLParam(r, "id")
var req service.ResolveRequest
if err := api.DecodeJSON(r, &req); err != nil {
api.WriteBadRequest(w, r, "invalid request body")
return
}
if req.Feature == "" {
api.WriteBadRequest(w, r, "feature is required")
return
}
ctx, cancel := context.WithTimeout(r.Context(), TimeoutStandard)
defer cancel()
result, err := h.orchestrator.ResolveBlocker(ctx, projectID, &req)
if err != nil {
writeSDLCError(w, r, err)
return
}
api.WriteSuccess(w, r, result)
}
// Commit commits changes in the project pod.
// POST /projects/{id}/sdlc/commit
func (h *SDLCOrchestratorHandler) Commit(w http.ResponseWriter, r *http.Request) {
projectID := chi.URLParam(r, "id")
var req service.CommitRequest
if err := api.DecodeJSON(r, &req); err != nil {
api.WriteBadRequest(w, r, "invalid request body")
return
}
if req.Message == "" {
api.WriteBadRequest(w, r, "message is required")
return
}
ctx, cancel := context.WithTimeout(r.Context(), TimeoutHeavyWrite)
defer cancel()
result, err := h.orchestrator.CommitChanges(ctx, projectID, &req)
if err != nil {
writeSDLCError(w, r, err)
return
}
api.WriteSuccess(w, r, result)
}