Skip to content

feat: 큐레이션 feed_payload 컬럼 추가 및 쓰기 경로 저장 - #677

Merged
Whale0928 merged 9 commits into
mainfrom
Whale0928/feed-spec
Jul 28, 2026
Merged

feat: 큐레이션 feed_payload 컬럼 추가 및 쓰기 경로 저장#677
Whale0928 merged 9 commits into
mainfrom
Whale0928/feed-spec

Conversation

@Whale0928

@Whale0928 Whale0928 commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

배경

  • 이슈: [BE/ADR] 큐레이션 피드 Read Model 분리 workspace#322 (큐레이션 피드 Read Model 분리 ADR)
  • 원본 curation_extension.payload는 건당 최대 128KB로, 피드 조회 시 전체를 전송·투영하는 구조의 개선 기반이 필요
  • 이번 PR은 ADR의 쓰기 경로만 구현한다 (읽기 전환은 후속 과제)

변경 사항

스키마

  • 서브모듈(V4): curation_extension.feed_payload JSON nullable 컬럼 추가. 포인터는 6611431 (V4 b1eeffb 포함, 이후 2건은 개발 환경 이미지 태그 범프로 storage/ 변경 없음)
  • CurationExtension: feedPayload 필드 매핑, update 시그니처에 feedPayload 추가

추출 로직

  • CurationFeedProjector.extractFeedPayload: 원본 payload에서 x-feed.enabled 필드와, 피드 경로와 교차하는 x-graphqlargFrom 값(숨은 입력값, 예: alcoholId)만 추출. GraphQL 실행 없음, 통계값 미포함
    • 남길 스키마 경로를 먼저 모아 투영 재귀에 넘기는 단일 패스 방식이다. 투영 후 값을 덧붙이지 않으므로 배열 원소에서도 경로가 어긋나지 않는다
    • argFrompayloadPath로 내려간 노드(배열이면 그 원소) 기준 상대 경로로 해석한다. whisky_tasting_event가 이 조합(payloadPath: $.alcohols)을 쓴다
    • 남길 값이 없으면 null이 아니라 빈 컨테이너([]/{})를 저장한다. null은 backfill 이전 레거시 행의 표시로만 쓴다
  • CurationFeedPaths (신규): 피드 경로 해석 규칙(rootSchema / collect / intersectsFeed / normalize)을 한 곳에 모은다. CurationResponseMaterializer에 복제돼 있던 4종을 제거해, 저장 시 추출과 조회 시 보강이 같은 기준을 쓰도록 보장한다

쓰기 경로

  • AdminSpecBasedCurationService: 생성·수정 시 원본 검증 후 feed_payload를 같은 트랜잭션으로 저장·갱신
  • CurationFixtureFactory: 픽스처도 운영과 같은 추출 결과를 남긴다. 비워두면 후속 읽기 경로 테스트가 NULL fallback 분기만 타게 된다

검증

  • main 머지 이후 재검증 기준, 전부 실패 0
    • unit_test 460건 (mono 233 / product 206 / observability 21)
    • integration_test 267건, admin_integration_test 206건, admin default test 58건
    • check_rule_test 통과 (product-api 63건 포함), Spotless 통과
  • 추출 로직 단위 테스트 7건: 4개 스펙 리소스(RECOMMENDED_WHISKY, WHISKY_PAIRING, WHISKY_TASTING_EVENT, PROGRAM) + 숨은 입력값 + payloadPath 하위 배열 + 빈 컨테이너
    • 뒤 2건은 수정 전 코드에서 실패함을 직접 확인했다
  • 생성·수정 이중 쓰기: mono 단위 2건 + admin 통합 2건 (실제 DB JSON 라운드트립)
  • 회귀: 기존 피드·상세 API 응답 불변 (기존 통합 테스트 전 건 통과)

읽기 경로 전환 시 인계 사항

  • feed_payloadnull이면 backfill 이전 레거시 행이다. 빈 결과는 []/{}로 저장되므로 fallback 판정은 null만 보면 된다
  • 숨은 입력값은 정의상 x-feed가 아닌 필드다. feed_payload를 그대로 응답해서는 안 되고, 현행처럼 materializeFeedprojectPayload를 거쳐야 한다

제외 범위 (후속 과제)

  • Product 피드 읽기 경로의 feed_payload 전환 (+NULL fallback)
  • 기존 데이터 backfill — nullable이며 어드민 재저장 시 자연 반영
  • 스펙 버전 관리, x-feed 변경 시 Read Model 재생성 정책
  • Admin 피드 프리뷰 N+1, GraphQL 배치 보강

배포 참고

  • 서브모듈 main에 V4가 이미 머지되어 있어, 이 PR의 서브모듈 포인터가 정상 참조됨
  • Flyway가 기동 시 V4를 자동 적용 (ddl-auto=validate)
  • 컬럼이 nullable이고 backfill이 없어 롤링 배포·롤백 양방향 안전하다

Whale0928 and others added 8 commits July 27, 2026 00:29
- 서브모듈 V4 마이그레이션: curation_extension.feed_payload json nullable 컬럼 추가
- CurationExtension에 feedPayload 필드 매핑
- extractFeedPayload: x-feed 필드 투영 + 피드 교차 x-graphql의 숨은 입력값(argFrom) 병합
- GraphQL 실행 없이 원본 payload에서만 추출
- 4개 스펙 리소스 및 숨은 입력값 시나리오 단위 테스트 5건
- AdminSpecBasedCurationService create/update에서 추출 메서드로 feed_payload 저장·갱신
- CurationExtension.update 시그니처에 feedPayload 추가
- mono 단위 테스트 2건, admin 통합 테스트 2건 추가
argFrom은 payloadPath로 내려간 노드(배열이면 그 원소) 기준 상대 경로인데
루트 기준으로 탐색해 숨은 입력값이 조용히 누락됐다. 남길 스키마 경로를
미리 모아 투영 재귀에 넘기는 방식으로 바꿔 배열 원소에서도 경로가
어긋나지 않게 한다.

남길 값이 없을 때는 null 대신 빈 컨테이너를 저장해 backfill 이전 레거시
행과 구분한다. 피드 경로 해석 규칙은 CurationFeedPaths로 추출해 저장 시
추출과 조회 시 보강이 같은 기준을 쓰도록 한다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
픽스처가 feed_payload를 비워두면 후속 읽기 경로 테스트가 NULL fallback
분기만 타게 된다. 운영과 같은 추출 결과를 남긴다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
서브모듈 신규 커밋은 개발 환경 이미지 태그 범프 2건으로 storage/ 변경은
없다. Task 3의 "픽스처 갱신 불필요" 판단을 정정한 내용도 함께 남긴다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Whale0928
Whale0928 merged commit 0676c74 into main Jul 28, 2026
8 checks passed
@Whale0928
Whale0928 deleted the Whale0928/feed-spec branch July 28, 2026 02:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant