추천 시스템
이 문서로 해결할 질문
- 개인화 추천은 어떻게 생성·조회·갱신되나요?
- Producer·Consumer·Redis·PostgreSQL 각각의 역할은 무엇인가요?
- 추천이 느리거나 stale할 때 어디를 확인하나요?
전체 흐름
원본 테이블: UserRecipeRecommendation
PostgreSQL user_recipe_recommendations 테이블이 추천 결과의 단일 진실 공급원입니다.
- Consumer가 이벤트별 delta로
score를 누적합니다. - Top 10(
MAX_RECOMMENDATION_ROWS)을 rank 1..N으로 재작성합니다. - Producer API는 이 원본 테이블을 조회해 응답합니다(캐시 miss 시).
원본 테이블에 데이터가 없으면 인기 레시피(likeCount DESC) 로 fallback합니다.
패키지별 책임
| 패키지 | 역할 | 상세 문서 |
|---|---|---|
| client | /recipe CSR 섹션에서 추천 API 호출 | 캐시 |
| producer | GET /recipes/recommended, Redis Cache-Aside | 추천 API |
| consumer | 이벤트→점수 갱신→캐시 무효화 | 추천 파이프라인 |
| shared | recommendation:{userId} 키·Top N 상한 | Redis 키/캐시 계약 |
주요 이벤트 가중치 (요약)
상세 표와 처리 조건은 Consumer 추천 파이프라인 — 이벤트별 가중치 문서를 참고하세요.
user-events는 관심 레시피·재료함 변경 등 강한 선호 신호입니다.
| 이벤트 | delta |
|---|---|
recipe.favorites_add | +1.8 |
recipe.favorites_remove | -1.8 |
ingredient.favorites_add | +0.8 |
ingredient.add | +0.25 |
activity-events는 조회·공유·검색 클릭 등 행동 보정용이며, 로그인 사용자와 recipeId가 필요합니다.
| 이벤트 | delta |
|---|---|
recipe.view | +0.1 |
recipe.share | +0.4 |
search.click | +0.25 |
캐시 정책
| 항목 | 값 |
|---|---|
| 키 | recommendation:{userId} |
| TTL | 3600초 (1시간) |
| 무효화 | Consumer cache-invalidation 토픽 → Redis 키 삭제 |
다음 조회 시 DB 폴백으로 최신 원본을 반영합니다.
운영·KPI
- E2E 지연 KPI
kpi_recommendation_e2e_latency는 EventLogrecipe.favorites_add의occurredAt부터processedAt까지 p95를 측정합니다. - 지연 알림은 Observability와 Consumer 운영 문서를 참고하세요.
변경 시 체크리스트
- 가중치를 변경할 때는 Consumer 추천 파이프라인과 score service를 함께 갱신합니다.
- Top N 상한을 변경할 때는
recommendation.policy.ts와 Producerlimit쿼리를 함께 갱신합니다. - API 응답을 변경할 때는 OpenAPI와 추천 API를 함께 갱신합니다.
- 캐시 키나 TTL을 변경할 때는 producer 캐시와 consumer 캐시 무효화를 함께 갱신합니다.