package com.zioinfo.esn.rag; import com.zioinfo.esn.common.ApiResponse; import lombok.RequiredArgsConstructor; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.*; import java.util.Map; /** * ESN 최신 AI 기법(중앙 guardia-rag) 배선 API — 별개 레이어, 테넌트 격리. * *

기존 {@code /api/ai/*}(AiController) 는 불변. 본 컨트롤러는 중앙 경유 신규 경로만 추가한다. * *

* *

테넌트는 {@code X-Tenant-Code} 헤더 또는 {@code tenantCode} 바디 필드로 식별(없으면 기본). */ @RestController @RequestMapping("/api/ai/rag") @RequiredArgsConstructor public class RagController { private final RagAiService service; @PostMapping("/analyze-alarm") public ApiResponse> analyzeAlarm( @RequestBody Map req, @RequestHeader(value = "X-Tenant-Code", required = false) String tenantHeader, Authentication auth) { return ApiResponse.ok(service.analyzeAlarm(tenant(tenantHeader, req), req, name(auth))); } @PostMapping("/classify-pos") public ApiResponse> classifyPos( @RequestBody Map req, @RequestHeader(value = "X-Tenant-Code", required = false) String tenantHeader, Authentication auth) { return ApiResponse.ok(service.classifyPos(tenant(tenantHeader, req), req, name(auth))); } @PostMapping("/feedback") public ApiResponse> feedback( @RequestBody Map req, @RequestHeader(value = "X-Tenant-Code", required = false) String tenantHeader, Authentication auth) { return ApiResponse.ok(service.feedback(tenant(tenantHeader, req), req, name(auth))); } @GetMapping("/toggles") public ApiResponse> toggles( @RequestHeader(value = "X-Tenant-Code", required = false) String tenantHeader, @RequestParam(value = "tenantCode", required = false) String tenantParam) { String tc = tenantHeader != null ? tenantHeader : tenantParam; return ApiResponse.ok(service.currentToggles(tc)); } /** * 토글 변경 — rag.* 화이트리스트 키만, 테넌트 격리. RBAC(MANAGER+)은 SecurityConfig 통제. */ @PutMapping("/toggles/{key}") public ApiResponse> updateToggle( @PathVariable String key, @RequestBody Map req, @RequestHeader(value = "X-Tenant-Code", required = false) String tenantHeader) { if (key == null || !key.startsWith("rag.")) { return ApiResponse.fail("ERR-RAG-400: rag.* 키만 변경 가능"); } String tc = tenantHeader != null ? tenantHeader : str(req.get("tenantCode")); Object v = req.get("value"); try { return ApiResponse.ok(service.updateToggle(tc, key, v == null ? "" : String.valueOf(v))); } catch (IllegalArgumentException e) { return ApiResponse.fail(e.getMessage()); } } // ── helpers ────────────────────────────────────────────────────────────── private String tenant(String header, Map req) { if (header != null && !header.isBlank()) return header; Object t = req == null ? null : req.get("tenantCode"); return t == null ? null : String.valueOf(t); } private String name(Authentication auth) { return auth == null ? "anon" : auth.getName(); } private String str(Object o) { return o == null ? null : String.valueOf(o); } }