Skip to content

feat: vocab 도메인 Kafka Consumer 연동 #40

Description

@zzuhannn

배경

Phase 1 (PR #32) — vocab 도메인 자체 구현 (HTTP 동기 흐름).
PR #36 — Kafka Producer 인프라 구축 (fairytale_generate).
PR #38 — SSE 페이지 스트리밍.

Phase 2: vocab 추출 결과 통신을 동기 HTTP에서 Kafka 메시지 기반 비동기로 전환.

합의 완료 사항 (2026-05-10)

  • 토픽명: vocab_extracted
  • 추출 lane: fairytale_paragraph 컨슈밍 워커가 추출 후 vocab_extracted 발행 (AI = Producer, Spring = Consumer)
  • 메시지 스키마: { messageId, fairytaleId, pageNo, word, meaning, userId? } (snake_case)
  • 페이지당 메시지 1건 정책 (word=null/blank는 "어려운 단어 없음" 표현)
  • Kafka URL: 52.78.205.133:8080

작업 범위 (Plan: .omc/plans/vocab-kafka-phase2.md)

Step 1 — Consumer-only DTO

  • VocabExtractedMessage (MessageInterface 미구현, @JsonIgnoreProperties(ignoreUnknown=true))

Step 2 — Consumer 인프라

  • KafkaConsumerConfig (@Profile("!dev"))
  • ErrorHandlingDeserializer 래핑
  • DefaultErrorHandler + DLT recoverer (DLT publish 직전 markVocabDone 호출)

Step 3 — Listener + Service 어댑터

  • VocabExtractedListener
  • VocabService.processExtractedWord(VocabExtractedMessage) 추가
  • FairytaleCheckServiceImpl.markImageDone inline fallback (~15 LoC)

Step 4 — dev/prod 분리

  • KafkaProducerConfig, EventService@Profile(\"!dev\")
  • application-dev.properties 추가 (단, spring.profiles.active=dev 작성 금지)
  • dev 프로필은 동화 생성 API 미지원 — 프론트는 dev에서 vocab만 시연

Step 5 — 테스트

  • EmbeddedKafka 통합 테스트
  • processExtractedWord 단위 테스트 (SAVED / DUPLICATE / NO_DIFFICULT_WORD / RACE_SKIPPED)
  • KafkaProducerTest@EnabledIfEnvironmentVariable(named=\"KAFKA_URL\") 추가
  • build.gradle awaitility 의존성 추가

핵심 가드레일

  • SSE 흐름 무중단 — markVocabDone이 모든 종착 분기에서 호출됨 (DLT 포함)
  • MessageInterface 변경 금지 (Consumer-only DTO 별도)
  • @Profile(\"!dev\") 일관 (@ConditionalOnProperty 사용 금지)
  • 페이지당 WordEntry 2개 이상 저장 금지

참고

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions