feat: 피드백 마크다운 리포트 저장·프록시·열람 (reportS3Key 구현) - #214
Merged
Conversation
- chain/feedback_report.py: LLM 미호출 결정론 렌더러 — 점수 표·패널·요약·
키워드·학습 플랜·하이라이트·답변별 코칭·음성 요약을 GFM 문서로 조립.
사용자 답변 원문은 미포함(사용자 입력은 마크다운으로 렌더하지 않는 규칙)
- FeedbackConsumer._save_report: feedback/{session_id}/report.md 저장 후
콜백에 키 동봉. 실패는 전부 삼키고 None 폴백 — 부가 산출물이 공용 가드를
타고 피드백 전체를 FAILED 로 승격시키지 않게 (키 조립도 try 안)
- 키 템플릿 SSOT 는 settings(FEEDBACK_REPORT_MD_KEY_TEMPLATE) — consumer
기본값 없음, storage 와 함께 주입될 때만 동작
- 종료 사유 라벨에 DURATION_EXCEEDED 추가, 직군 라벨은 _DOMAIN_KO 재사용,
다행 질문 헤딩 한 줄 접기, 질문 번호는 전사 내 질문 순서 기준(코칭 일부
실패에도 안정), 회사명(사용자 입력)은 개행 접기로 구조 주입 차단
- 테스트 +6 (렌더러 3, consumer 저장/실패 폴백/미주입 3)
- GET /api/sessions/{id}/feedback/report: AI 가 저장한 마크다운 리포트를
소유자 전용으로 중계 (분석 원문 /content 프록시와 동일 패턴 —
presigned 는 내부 MinIO 호스트라 브라우저 접근 불가)
- 키 부재(AI 저장 실패 폴백·구버전)는 422 FEEDBACK_REPORT_NOT_AVAILABLE 로
'생성 중'과 구분. 키만 남고 객체가 사라진 정합 붕괴도 같은 422 로 수렴 —
S3 클라이언트가 NoSuchKey 를 OBJECT_NOT_FOUND 로 분리해 503(인프라 장애)
오인을 방지
- FeedbackResponse.fromPublic 에서 reportFilePath 제거 — 내부 스토리지 키를
비인증 공유 응답에 노출하지 않는다 (shareToken 제거와 같은 원칙)
- report_file_path 는 V1 부터 존재 — 마이그레이션 없음. 테스트 +5
- FeedbackAiReport: reportFilePath 가 있을 때만 노출되는 열람 토글 — Core 프록시(GET /feedback/report)로 마크다운을 받아 shared/ui/Markdown (lazy+sanitize)으로 렌더, .md 다운로드 제공. 신규 의존성 0 - 열람 요청 시에만 fetch(분석 원문 보기와 동일), PDF 캡처 영역 바깥 — 리포트 파일은 자체 산출물이라 중복 캡처하지 않는다 - 쿼리키를 feedbackKeys.detail 하위로 — 재생성 resetQueries(prefix)가 리포트 캐시도 함께 비운다. 부모 상태 변화마다 재파싱하지 않게 memo - openapi 재생성(getSessionFeedbackReport). 테스트 +3
- messaging.md §5.11: reportS3Key 정의 — GFM 리포트 키, null 허용(저장 실패 폴백), FAILED 콜백에서는 항상 null, Core 저장·프록시 경로 - api-conventions.md: GET /feedback/report 엔드포인트 + 422 FEEDBACK_REPORT_NOT_AVAILABLE 에러 카탈로그 - storage.md §2: feedback report 키 주석(구현됨), environment.md: FEEDBACK_REPORT_MD_KEY_TEMPLATE, frontend-types.md §6.5: GFM 필드에 리포트 본문 추가
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
개요
callback.feedback.reportS3Key가 계약(예시 JSON·storage.md 키 예약·Core 저장 컬럼·응답 노출)만 있고 AI 가 무조건None을 보내던 gap 을 풀스택으로 닫는다.chain/feedback_report.py— LLM 미호출 결정론 렌더러(점수 표·패널·요약·키워드·학습 플랜·하이라이트·답변별 코칭·음성 요약 → GFM 문서).FeedbackConsumer._save_report가feedback/{session_id}/report.md에 저장 후 키 동봉. 실패는 전부 삼키고 None 폴백 — 부가 산출물이 공용 실패 가드를 타고 피드백 전체를 FAILED 로 승격시키지 않게. 사용자 답변 원문은 리포트에 싣지 않는다.GET /api/sessions/{id}/feedback/report(text/markdown — presigned 는 내부 MinIO 호스트라 Core 중계, 분석 원문 프록시와 동일 패턴). 키 부재·객체 소실은 422FEEDBACK_REPORT_NOT_AVAILABLE(S3 NoSuchKey 를OBJECT_NOT_FOUND로 분리해 503 오인 방지). 공개 공유 응답(fromPublic)에서 reportFilePath 제거 — 내부 키 비인증 노출 차단. 마이그레이션 없음(report_file_path는 V1 부터 존재).FeedbackAiReport— reportFilePath 있을 때만 노출되는 열람 토글 + Markdown(lazy+sanitize) 렌더 + .md 다운로드. 신규 의존성 0(A5 렌더러 재사용, 메인 청크 사실상 불변).검증
uv run pytest: 393 passed (+6) · black 클린./gradlew test: 251 passed (+5) — 로컬 Docker 부재 Testcontainers 4건 외 실패 0리뷰 반영
frontend-reviewer W1/S1 반영(재생성 시 리포트 캐시 무효화 — 쿼리키를 detail 계층 하위로, 다운로드 앵커 DOM append). 코드리뷰 10건 중 8건 반영: 키 조립 try 안으로(잘못된 템플릿이 피드백 FAILED 를 만들지 않게), 종료 사유 라벨 누락(DURATION_EXCEEDED), dangling key 503→422, 회사명(사용자 입력) 개행 접기, 다행 질문 헤딩, 키 템플릿 settings SSOT 화, 리포트 컴포넌트 memo, 질문 번호 안정화. 이관 2건(attempt 경합 파일-행 불일치 low, 프록시 소비 레시피 중복 N=2)은 후속 To-do 로 기록.