BFF는 왜 chat_message / chat_feedback 테이블을 가지는가?

Layered architecture · BFF vs ai_engine 책임 분리
  1. 호진(Hojin)의 T4 프롬프트가 명시적으로 요구함message.txt 69~83줄에서 그대로 인용:

    "사용자 메시지와 에이전트 응답(반환된 UIAction[] 및 모든 tool-call trace 메타데이터 포함)을 새 Postgres 테이블 chat_message (session_id, role, content, ui_actions JSONB, created_at)에 영속화하라."
    "PATCH /api/chat/sessions/{sid}/messages/{mid}/feedback — thumbs up/down 을 chat_feedback 테이블에 영속화한다."
  2. ai_engine 은 stateless inference 레이어services/ai_engine/online/eval_chatbot/service.pychat() 은 요청마다 새 workflow 를 띄운다. conversation_history 는 매 턴 caller(BFF)가 전달해야 한다. ai_engine 자체에는 chat memory 가 없다. 누군가는 history 를 persist 해야 한다 → BFF.

  3. 프론트엔드는 과거 대화를 GET /api/chat/sessions/{sid}/messages 로 가져온다 — 페이지 리로드 시, 또는 다른 평가자가 같은 세션을 열 때. BFF 가 ai_engine 에 물어봐서 재구성할 수 없다 (ai_engine 도 모르니까).

  4. 어드민 화면은 BFF 의 chat_message / chat_feedback 을 직접 읽는다frontend/src/lib/api/client.tsapiGetAdminChatSessions(), apiGetAdminChatFeedbacks(), apiGetAdminChatSummariesByBidId() 가 있다. 평가자 사용 통계, 피드백 채택률, bid 별 대화 요약. LLM 호출이 아닌 DB 집계 — BFF 의 역할이다.

  5. "BFF 에 LLM SDK 금지" 규칙은 여전히 지켜진다chat_message 는 그저 Postgres row 일 뿐이다. BFF 는 services/ai_engine/online/eval-chatbot/chat 만 호출하며, apps/eval-system-premium/backend/ 어디에도 openai / anthropic / google.generativeai / groq import 가 없다. T4-c4 테스트(test_bff_does_not_import_llm_sdks)가 매 커밋마다 이를 정적으로 검증한다.

한 줄 요약

ai_engine = LLM 호출 (stateless). BFF = 대화 상태 + 피드백 + 어드민 집계 (stateful).

이 분리는 호진 / 박찬호의 layered architecture 정책을 정확히 따른다 — chat 호출만 ai_engine 을 경유하고, 모든 persistence 는 BFF 에 남는다.