diff --git a/src/main/java/com/devpick/domain/content/entity/Content.java b/src/main/java/com/devpick/domain/content/entity/Content.java index 9512563..ab4ccb2 100644 --- a/src/main/java/com/devpick/domain/content/entity/Content.java +++ b/src/main/java/com/devpick/domain/content/entity/Content.java @@ -106,6 +106,10 @@ public class Content extends BaseTimeEntity { @Convert(converter = StackOverflowAnswerListConverter.class) private List topAnswers; + // YouTube 전용 필드 저장 (JSON 문자열: videoId, channelName, duration, viewCount) + @Column(name = "extra", columnDefinition = "jsonb") + private String extra; + @OneToMany(mappedBy = "content", cascade = CascadeType.ALL, orphanRemoval = true) @Builder.Default private List contentTags = new ArrayList<>(); diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 74cec45..25c0798 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -75,3 +75,8 @@ WHERE NOT EXISTS (SELECT 1 FROM content_sources WHERE name = 'Medium_watcha'); INSERT INTO content_sources (id, name, url, collect_method, is_active, created_at) SELECT gen_random_uuid(), 'Kakao_Tech', 'https://tech.kakao.com/feed/', 'rss_crawl', true, NOW() WHERE NOT EXISTS (SELECT 1 FROM content_sources WHERE name = 'Kakao_Tech'); + +-- DP-413: YouTube 수집 소스 추가 (AI 레포가 YouTube Data API로 수집 후 POST /internal/contents 전달) +INSERT INTO content_sources (id, name, url, collect_method, is_active, created_at) +SELECT gen_random_uuid(), 'YouTube', 'https://www.youtube.com', 'api', true, NOW() +WHERE NOT EXISTS (SELECT 1 FROM content_sources WHERE name = 'YouTube'); diff --git a/src/test/java/com/devpick/domain/content/entity/ContentTest.java b/src/test/java/com/devpick/domain/content/entity/ContentTest.java index 1dc7440..f5b6bf0 100644 --- a/src/test/java/com/devpick/domain/content/entity/ContentTest.java +++ b/src/test/java/com/devpick/domain/content/entity/ContentTest.java @@ -58,4 +58,38 @@ void builder_withFields() { assertThat(content.getIsOriginalVisible()).isTrue(); assertThat(content.getLicenseType()).isEqualTo("CC BY-SA 4.0"); } + + @Test + @DisplayName("extra 필드 미설정 시 null — 기존 콘텐츠 조회에 영향 없음") + void builder_extraDefaultsToNull() { + ContentSource source = ContentSource.builder() + .name("Velog").url("https://v2.velog.io/graphql").collectMethod("graphql").build(); + + Content content = Content.builder() + .source(source) + .title("Kotlin 코루틴") + .canonicalUrl("https://velog.io/@user/kotlin") + .build(); + + assertThat(content.getExtra()).isNull(); + } + + @Test + @DisplayName("extra 필드에 YouTube JSON 문자열을 저장할 수 있다") + void builder_extraWithYouTubeJson() { + ContentSource source = ContentSource.builder() + .name("YouTube").url("https://www.youtube.com").collectMethod("api").build(); + String youtubeExtra = "{\"videoId\":\"dQw4w9WgXcQ\",\"channelName\":\"우아한Tech\",\"duration\":312,\"viewCount\":15000}"; + + Content content = Content.builder() + .source(source) + .title("우아한Tech 스프링 강의") + .canonicalUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ") + .extra(youtubeExtra) + .build(); + + assertThat(content.getExtra()).isEqualTo(youtubeExtra); + assertThat(content.getExtra()).contains("videoId"); + assertThat(content.getExtra()).contains("channelName"); + } }