package httpapi import ( "errors" "net/http" "strings" "github.com/descrybe/descrybe-v2/apps/api/internal/seo" "github.com/google/uuid" ) func (s *Server) handleSEORecommendations(w http.ResponseWriter, r *http.Request) { cid, ok := CompanyIDFromContext(r.Context()) if !ok || cid == uuid.Nil { Error(w, http.StatusUnauthorized, "unauthorized") return } if s.SEO == nil { Error(w, http.StatusServiceUnavailable, "seo service unavailable") return } report, err := s.SEO.Recommendations(r.Context(), cid) if err != nil { Error(w, http.StatusInternalServerError, "seo analysis failed") return } JSON(w, http.StatusOK, report) } func (s *Server) handleSEOApply(w http.ResponseWriter, r *http.Request) { cid, ok := CompanyIDFromContext(r.Context()) if !ok || cid == uuid.Nil { Error(w, http.StatusUnauthorized, "unauthorized") return } if s.SEO == nil { Error(w, http.StatusServiceUnavailable, "seo service unavailable") return } var body seo.ApplyRequest if err := DecodeJSON(r, &body); err != nil { Error(w, http.StatusBadRequest, "invalid json") return } productID, err := uuid.Parse(strings.TrimSpace(body.ProductID)) if err != nil { Error(w, http.StatusBadRequest, "invalid product_id") return } result, err := s.SEO.Apply(r.Context(), cid, productID, body.Mode) if err != nil { switch { case writePlanGate(w, err): return case errors.Is(err, seo.ErrNotFound): Error(w, http.StatusNotFound, "not found") return default: ClientOrLog(w, http.StatusBadRequest, "seo apply failed", err, seo.ClientError) return } } JSON(w, http.StatusOK, result) }