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) }