diff --git a/.run/DistributionServiceApplication.run.xml b/.run/DistributionServiceApplication.run.xml
index b023d5b..628989f 100644
--- a/.run/DistributionServiceApplication.run.xml
+++ b/.run/DistributionServiceApplication.run.xml
@@ -23,6 +23,11 @@
+
+
+
+
+
diff --git a/distribution-service/.run/distribution-service.run.xml b/distribution-service/.run/distribution-service.run.xml
index 2736380..bc785a7 100644
--- a/distribution-service/.run/distribution-service.run.xml
+++ b/distribution-service/.run/distribution-service.run.xml
@@ -11,6 +11,11 @@
+
+
+
+
+
diff --git a/distribution-service/NAVER_BLOG_SETUP.md b/distribution-service/NAVER_BLOG_SETUP.md
new file mode 100644
index 0000000..e6cdcb8
--- /dev/null
+++ b/distribution-service/NAVER_BLOG_SETUP.md
@@ -0,0 +1,248 @@
+# 네이버 블로그 포스팅 설정 가이드
+
+## 개요
+Distribution Service는 Playwright를 사용하여 네이버 블로그에 자동으로 포스팅합니다.
+
+## 사전 준비
+
+### 1. Playwright 설치
+처음 실행 시 Playwright 브라우저가 자동으로 다운로드됩니다. 수동으로 설치하려면:
+
+```bash
+# Windows (PowerShell)
+mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install chromium"
+
+# Linux/Mac
+mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install chromium"
+```
+
+### 2. 네이버 계정 준비
+- 네이버 계정 (아이디/비밀번호)
+- 네이버 블로그 개설 (blog.naver.com에서 블로그 만들기)
+- 블로그 ID 확인 (예: blog.naver.com/YOUR_BLOG_ID)
+
+## 환경 변수 설정
+
+### IntelliJ 실행 프로파일 설정
+`.run/DistributionServiceApplication.run.xml` 파일에서 다음 환경 변수를 설정:
+
+```xml
+
+
+
+
+
+```
+
+### 환경 변수 설명
+
+| 환경 변수 | 설명 | 기본값 | 필수 |
+|----------|------|--------|------|
+| `NAVER_BLOG_USERNAME` | 네이버 아이디 | - | ✅ |
+| `NAVER_BLOG_PASSWORD` | 네이버 비밀번호 | - | ✅ |
+| `NAVER_BLOG_BLOG_ID` | 네이버 블로그 ID | - | ✅ |
+| `NAVER_BLOG_HEADLESS` | Headless 모드 (true/false) | true | ❌ |
+| `NAVER_BLOG_SESSION_PATH` | 세션 저장 경로 | playwright-sessions | ❌ |
+
+### Headless 모드
+- **false**: 브라우저 창이 표시되어 디버깅에 유용 (개발 환경 권장)
+- **true**: 백그라운드 실행, 서버 환경에 적합 (운영 환경 권장)
+
+## 사용 방법
+
+### API 호출 예시
+
+```bash
+# 배포 요청
+curl -X POST http://localhost:8085/distribution/api/v1/distributions \
+ -H "Content-Type: application/json" \
+ -d '{
+ "eventId": "EVT001",
+ "title": "신규 이벤트 안내",
+ "content": "이벤트 상세 내용입니다.",
+ "imageUrl": "https://example.com/event.jpg",
+ "channels": ["NAVER"]
+ }'
+```
+
+### 응답 예시
+
+```json
+{
+ "eventId": "EVT001",
+ "status": "SUCCESS",
+ "totalChannels": 1,
+ "successCount": 1,
+ "failureCount": 0,
+ "channels": [
+ {
+ "channel": "NAVER",
+ "success": true,
+ "distributionId": "NAVER-abc123",
+ "distributionUrl": "https://blog.naver.com/your_blog_id/222999999999",
+ "estimatedReach": 2000,
+ "executionTimeMs": 5234
+ }
+ ],
+ "distributedAt": "2025-10-29T10:30:00"
+}
+```
+
+## 세션 관리
+
+### 자동 로그인
+- 최초 실행 시 네이버에 로그인하고 세션이 저장됩니다
+- 이후 요청은 저장된 세션을 사용하여 로그인 없이 진행됩니다
+- 세션 파일 위치: `playwright-sessions/naver-blog-session.json`
+
+### 세션 만료 시
+세션이 만료되면 자동으로 재로그인을 시도합니다.
+
+### 수동 세션 초기화
+```bash
+# 세션 파일 삭제
+rm -rf playwright-sessions/naver-blog-session.json
+```
+
+## 문제 해결
+
+### 1. 로그인 실패
+**증상**: "Login failed" 에러 발생
+
+**해결 방법**:
+- 네이버 아이디/비밀번호 확인
+- 네이버 로그인 보안 설정 확인 (캡차, 2단계 인증 등)
+- Headless 모드를 false로 설정하여 브라우저 동작 확인
+- 세션 파일 삭제 후 재시도
+
+### 2. 브라우저 실행 실패
+**증상**: "Failed to initialize Playwright" 에러
+
+**해결 방법**:
+```bash
+# Playwright 브라우저 재설치
+mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install chromium"
+```
+
+### 3. 포스팅 실패
+**증상**: 포스팅 URL이 반환되지 않음
+
+**해결 방법**:
+- Headless 모드를 false로 설정하여 UI 확인
+- 네이버 블로그 에디터 구조 변경 여부 확인
+- 로그 확인: `logs/distribution-service.log`
+
+### 4. 성능 이슈
+브라우저 자동화는 리소스를 많이 사용하므로:
+- Resilience4j Bulkhead 설정으로 동시 실행 제한 (현재 10개)
+- Circuit Breaker로 반복 실패 방지
+- 실패 시 자동 재시도 (최대 3회)
+
+## 보안 고려사항
+
+### 1. 비밀번호 관리
+- **절대로** 소스 코드에 비밀번호를 하드코딩하지 마세요
+- 환경 변수 또는 시크릿 관리 서비스 사용
+- Git에 `.run/*.xml` 파일을 커밋하지 마세요 (`.gitignore` 추가)
+
+### 2. 세션 파일 보안
+- `playwright-sessions/` 디렉토리를 `.gitignore`에 추가
+- 서버 환경에서 파일 권한 설정 (chmod 600)
+
+### 3. 네트워크 보안
+- HTTPS만 사용
+- 프록시 사용 시 안전한 프록시 설정
+
+## 운영 환경 배포
+
+### Docker 환경
+```dockerfile
+# Dockerfile에 Playwright 설치 추가
+RUN apt-get update && apt-get install -y \
+ libnss3 \
+ libatk-bridge2.0-0 \
+ libdrm2 \
+ libxkbcommon0 \
+ libgbm1 \
+ libasound2
+
+# Playwright 브라우저 설치
+RUN mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install chromium"
+```
+
+### Kubernetes 환경
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: naver-blog-credentials
+type: Opaque
+stringData:
+ username: your_naver_id
+ password: your_password
+ blog-id: your_blog_id
+---
+apiVersion: apps/v1
+kind: Deployment
+spec:
+ template:
+ spec:
+ containers:
+ - name: distribution-service
+ env:
+ - name: NAVER_BLOG_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: naver-blog-credentials
+ key: username
+ - name: NAVER_BLOG_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: naver-blog-credentials
+ key: password
+ - name: NAVER_BLOG_BLOG_ID
+ valueFrom:
+ secretKeyRef:
+ name: naver-blog-credentials
+ key: blog-id
+ - name: NAVER_BLOG_HEADLESS
+ value: "true"
+```
+
+## 제약사항
+
+1. **동시 실행 제한**: Bulkhead 설정으로 최대 10개 동시 실행
+2. **실행 시간**: 브라우저 자동화는 API 호출보다 느림 (평균 5-10초)
+3. **네이버 정책**: 네이버 블로그 정책 변경 시 업데이트 필요
+4. **UI 변경**: 네이버 블로그 UI 변경 시 코드 수정 필요
+
+## 모니터링
+
+### 로그 확인
+```bash
+# 실시간 로그
+tail -f logs/distribution-service.log
+
+# 에러만 필터
+grep ERROR logs/distribution-service.log
+```
+
+### 주요 로그 메시지
+- `Initializing Playwright for Naver Blog`: Playwright 초기화
+- `Starting Naver login process`: 로그인 시작
+- `Naver login successful`: 로그인 성공
+- `Post published successfully`: 포스팅 성공
+- `Failed to post to Naver blog`: 포스팅 실패
+
+## 참고 자료
+
+- [Playwright for Java](https://playwright.dev/java/)
+- [네이버 블로그 고객센터](https://help.naver.com/service/5614/)
+- [Resilience4j 문서](https://resilience4j.readme.io/)
+
+## 지원
+
+문제 발생 시:
+1. 로그 파일 확인: `logs/distribution-service.log`
+2. Headless 모드를 false로 설정하여 브라우저 동작 확인
+3. GitHub Issue 등록 (로그 첨부)
diff --git a/distribution-service/build.gradle b/distribution-service/build.gradle
index 9e25a30..f20225a 100644
--- a/distribution-service/build.gradle
+++ b/distribution-service/build.gradle
@@ -15,6 +15,9 @@ dependencies {
implementation "io.github.resilience4j:resilience4j-retry:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-bulkhead:${resilience4jVersion}"
+ // Playwright for browser automation
+ implementation 'com.microsoft.playwright:playwright:1.41.0'
+
// Jackson for JSON
implementation 'com.fasterxml.jackson.core:jackson-databind'
}
diff --git a/distribution-service/src/main/java/com/kt/distribution/adapter/NaverAdapter.java b/distribution-service/src/main/java/com/kt/distribution/adapter/NaverAdapter.java
index 0d7f44e..5c4b42f 100644
--- a/distribution-service/src/main/java/com/kt/distribution/adapter/NaverAdapter.java
+++ b/distribution-service/src/main/java/com/kt/distribution/adapter/NaverAdapter.java
@@ -1,27 +1,28 @@
package com.kt.distribution.adapter;
+import com.kt.distribution.client.NaverBlogClient;
import com.kt.distribution.dto.ChannelDistributionResult;
import com.kt.distribution.dto.ChannelType;
import com.kt.distribution.dto.DistributionRequest;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.UUID;
/**
* Naver Blog Adapter
- * Naver Blog 포스팅 API 호출
+ * Naver Blog 포스팅 (Playwright 기반)
*
- * @author System Architect
- * @since 2025-10-23
+ * @author Backend Developer
+ * @since 2025-10-29
*/
@Slf4j
@Component
+@RequiredArgsConstructor
public class NaverAdapter extends AbstractChannelAdapter {
- @Value("${channel.apis.naver.url}")
- private String apiUrl;
+ private final NaverBlogClient naverBlogClient;
@Override
public ChannelType getChannelType() {
@@ -30,16 +31,35 @@ public class NaverAdapter extends AbstractChannelAdapter {
@Override
protected ChannelDistributionResult executeDistribution(DistributionRequest request) {
- log.debug("Calling Naver API: url={}, eventId={}", apiUrl, request.getEventId());
+ log.debug("Posting to Naver Blog: eventId={}, title={}",
+ request.getEventId(), request.getTitle());
- // TODO: 실제 API 호출 (현재는 Mock)
- String distributionId = "NAVER-" + UUID.randomUUID().toString();
+ try {
+ // 네이버 블로그에 포스팅
+ String postUrl = naverBlogClient.postToBlog(request);
+ String distributionId = "NAVER-" + UUID.randomUUID().toString();
- return ChannelDistributionResult.builder()
- .channel(ChannelType.NAVER)
- .success(true)
- .distributionId(distributionId)
- .estimatedReach(2000) // 블로그 방문자 수 기반
- .build();
+ log.info("Naver blog post created successfully: eventId={}, postUrl={}",
+ request.getEventId(), postUrl);
+
+ return ChannelDistributionResult.builder()
+ .channel(ChannelType.NAVER)
+ .success(true)
+ .distributionId(distributionId)
+ .postUrl(postUrl)
+ .estimatedReach(2000) // 블로그 방문자 수 기반
+ .build();
+
+ } catch (Exception e) {
+ log.error("Failed to post to Naver blog: eventId={}, error={}",
+ request.getEventId(), e.getMessage(), e);
+
+ return ChannelDistributionResult.builder()
+ .channel(ChannelType.NAVER)
+ .success(false)
+ .errorMessage("Naver blog posting failed: " + e.getMessage())
+ .estimatedReach(0)
+ .build();
+ }
}
}
diff --git a/distribution-service/src/main/java/com/kt/distribution/client/NaverBlogClient.java b/distribution-service/src/main/java/com/kt/distribution/client/NaverBlogClient.java
new file mode 100644
index 0000000..cdf210b
--- /dev/null
+++ b/distribution-service/src/main/java/com/kt/distribution/client/NaverBlogClient.java
@@ -0,0 +1,317 @@
+package com.kt.distribution.client;
+
+import com.kt.distribution.dto.DistributionRequest;
+import com.microsoft.playwright.*;
+import com.microsoft.playwright.options.LoadState;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Naver Blog Client using Playwright
+ * 네이버 블로그 포스팅 자동화 클라이언트
+ *
+ * @author Backend Developer
+ * @since 2025-10-29
+ */
+@Slf4j
+@Component
+public class NaverBlogClient {
+
+ @Value("${naver.blog.username:}")
+ private String username;
+
+ @Value("${naver.blog.password:}")
+ private String password;
+
+ @Value("${naver.blog.blog-id:}")
+ private String blogId;
+
+ @Value("${naver.blog.headless:false}")
+ private boolean headless;
+
+ @Value("${naver.blog.session-path:playwright-sessions}")
+ private String sessionPath;
+
+ private Playwright playwright;
+ private Browser browser;
+ private BrowserContext context;
+
+ /**
+ * Playwright 초기화
+ */
+ @PostConstruct
+ public void init() {
+ try {
+ log.info("Initializing Playwright for Naver Blog");
+ playwright = Playwright.create();
+
+ browser = playwright.chromium().launch(new BrowserType.LaunchOptions()
+ .setHeadless(headless)
+ .setSlowMo(100)); // 안정성을 위한 느린 실행
+
+ // 세션 디렉토리 생성
+ File sessionDir = new File(sessionPath);
+ if (!sessionDir.exists()) {
+ sessionDir.mkdirs();
+ log.info("Created session directory: {}", sessionPath);
+ }
+
+ // 세션 파일 경로
+ Path sessionFilePath = Paths.get(sessionPath, "naver-blog-session.json");
+
+ // 세션 파일이 있으면 로드, 없으면 새로운 컨텍스트 생성
+ if (Files.exists(sessionFilePath)) {
+ log.info("Loading existing session from: {}", sessionFilePath);
+ context = browser.newContext(new Browser.NewContextOptions()
+ .setStorageStatePath(sessionFilePath));
+ } else {
+ log.info("No existing session found, creating new context");
+ context = browser.newContext();
+ }
+
+ log.info("Playwright initialized successfully");
+ } catch (Exception e) {
+ log.error("Failed to initialize Playwright", e);
+ throw new RuntimeException("Playwright initialization failed", e);
+ }
+ }
+
+ /**
+ * 네이버 블로그에 포스팅
+ *
+ * @param request DistributionRequest
+ * @return 포스팅 URL
+ * @throws Exception 포스팅 실패 시
+ */
+ public String postToBlog(DistributionRequest request) throws Exception {
+ Page page = null;
+ try {
+ page = context.newPage();
+ // 타임아웃을 5분(300000ms)으로 설정
+ page.setDefaultTimeout(300000);
+
+ // 로그인 확인 및 처리
+ if (!isLoggedIn(page)) {
+ login(page);
+ }
+
+ // 블로그 글쓰기 페이지로 이동
+ String writeUrl = String.format("https://blog.naver.com/%s/postwrite", blogId);
+ page.navigate(writeUrl);
+ page.waitForLoadState(LoadState.NETWORKIDLE);
+
+
+ // 도움말 팝업이 있으면 닫기
+ try {
+ page.waitForTimeout(5000); // 충분히 대기 필요
+
+ Locator helpPanel = page.locator("[class*='help-panel']");
+
+ if (helpPanel.isVisible(new Locator.IsVisibleOptions().setTimeout(2000))) {
+ log.debug("Help dialog detected, closing it");
+
+ // 팝업 안의 닫기 버튼 찾기
+ Locator closeBtn = page.locator("button[class*='se-help-panel-close-button']");
+ closeBtn.click();
+ Thread.sleep(500);
+ log.debug("Help dialog closed");
+ } else{
+ log.debug("--------------------- 도움말 없음");
+ }
+ } catch (Exception e) {
+ log.debug("No help dialog found or already closed");
+ }
+
+ // 제목 입력
+ Locator titleInput = page.locator(".se-text-paragraph").first();
+ titleInput.click();
+ titleInput.pressSequentially(request.getTitle(), new Locator.PressSequentiallyOptions().setDelay(50));
+ log.debug("Title entered: {}", request.getTitle());
+
+ // 본문 입력
+ Locator editorInput = page.locator(".se-text-paragraph").nth(1);
+ editorInput.click();
+ titleInput.pressSequentially(request.getDescription(), new Locator.PressSequentiallyOptions().setDelay(50));
+ log.debug("Content entered");
+
+ // 이미지가 있으면 업로드
+ if (request.getImageUrl() != null && !request.getImageUrl().isEmpty()) {
+ uploadImage(page, request.getImageUrl());
+ }
+
+ // 발행 버튼 클릭
+ page.locator("button[class*='publish_btn']").click();
+ page.waitForLoadState(LoadState.NETWORKIDLE);
+ page.locator("button[class*='confirm_btn']").click();
+ page.waitForLoadState(LoadState.NETWORKIDLE);
+
+ page.waitForTimeout(5000); // 충분히 대기 필요
+
+ // 포스팅 URL 가져오기
+ String postUrl = page.url();
+ log.info("Post published successfully: {}", postUrl);
+
+ return postUrl;
+
+ } catch (Exception e) {
+ log.error("Failed to post to Naver blog: eventId={}, error={}",
+ request.getEventId(), e.getMessage(), e);
+ throw e;
+ } finally {
+ if (page != null) {
+ page.close();
+ }
+ }
+ }
+
+ /**
+ * 로그인 상태 확인
+ *
+ * @param page Page
+ * @return 로그인 여부
+ */
+ private boolean isLoggedIn(Page page) {
+ try {
+ page.navigate("https://blog.naver.com");
+ page.waitForLoadState(LoadState.NETWORKIDLE);
+
+ // 로그인 버튼이 보이지 않으면 로그인된 상태
+ // ID 기반 선택자 사용으로 strict mode violation 방지
+ return !page.locator("#gnb_login_button").isVisible();
+ } catch (Exception e) {
+ log.warn("Failed to check login status", e);
+ return false;
+ }
+ }
+
+ /**
+ * 네이버 로그인 (수동 로그인 대기 방식)
+ *
+ * @param page Page
+ * @throws Exception 로그인 실패 시
+ */
+ private void login(Page page) throws Exception {
+ try {
+ log.info("Starting Naver manual login process");
+ log.info("=================================================");
+ log.info("Please login manually in the browser window");
+ log.info("브라우저 창에서 수동으로 로그인해주세요");
+ log.info("=================================================");
+
+ // 네이버 로그인 페이지로 이동
+ page.navigate("https://nid.naver.com/nidlogin.login");
+ page.waitForLoadState(LoadState.NETWORKIDLE);
+
+ // 사용자가 수동으로 로그인할 때까지 대기 (URL이 변경될 때까지)
+ // 로그인 성공 시 URL이 nid.naver.com에서 벗어남
+ log.info("Waiting for manual login... (Timeout: 30 seconds)");
+
+ try {
+ // 30초 동안 URL이 nid.naver.com을 벗어날 때까지 대기
+ page.waitForURL(url -> !url.contains("nid.naver.com"),
+ new Page.WaitForURLOptions().setTimeout(30000));
+
+ log.info("Login URL changed, assuming login successful");
+
+ } catch (Exception e) {
+ log.error("Login timeout or failed", e);
+ throw new Exception("Manual login timeout or failed after 30 seconds");
+ }
+
+ // 추가 안정화 대기
+ page.waitForLoadState(LoadState.NETWORKIDLE);
+ Thread.sleep(2000); // 2초 추가 대기
+
+ // 세션 저장
+ context.storageState(new BrowserContext.StorageStateOptions()
+ .setPath(Paths.get(sessionPath, "naver-blog-session.json")));
+
+ log.info("Naver manual login successful, session saved");
+ log.info("Current URL: {}", page.url());
+
+ } catch (Exception e) {
+ log.error("Naver manual login process failed", e);
+ throw new Exception("Naver manual login failed: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * 이미지 업로드
+ *
+ * @param page Page
+ * @param imageUrl 이미지 URL
+ */
+ private void uploadImage(Page page, String imageUrl) {
+ try {
+ log.debug("Uploading image: {}", imageUrl);
+
+ // 이미지 업로드 버튼 클릭
+ page.locator("button[aria-label='사진']").click();
+
+ // URL로 이미지 추가 (실제 구현은 네이버 블로그 UI에 따라 조정 필요)
+ // 여기서는 간단히 로그만 남김
+ log.info("Image upload placeholder - URL: {}", imageUrl);
+
+ } catch (Exception e) {
+ log.warn("Failed to upload image: {}", e.getMessage());
+ }
+ }
+
+ /**
+ * Playwright 리소스 정리
+ */
+ @PreDestroy
+ public void cleanup() {
+ try {
+ if (context != null) {
+ context.close();
+ }
+ if (browser != null) {
+ browser.close();
+ }
+ if (playwright != null) {
+ playwright.close();
+ }
+ log.info("Playwright resources cleaned up");
+ } catch (Exception e) {
+ log.error("Failed to cleanup Playwright resources", e);
+ }
+ }
+
+ /**
+ * 수동으로 브라우저 컨텍스트 새로고침
+ * 장시간 사용 시 세션 만료 방지용
+ */
+ public void refreshContext() {
+ try {
+ if (context != null) {
+ context.close();
+ }
+
+ // 세션 파일 경로
+ Path sessionFilePath = Paths.get(sessionPath, "naver-blog-session.json");
+
+ // 세션 파일이 있으면 로드, 없으면 새로운 컨텍스트 생성
+ if (Files.exists(sessionFilePath)) {
+ log.info("Refreshing context with existing session");
+ context = browser.newContext(new Browser.NewContextOptions()
+ .setStorageStatePath(sessionFilePath));
+ } else {
+ log.info("Refreshing context without session");
+ context = browser.newContext();
+ }
+
+ log.info("Browser context refreshed");
+ } catch (Exception e) {
+ log.error("Failed to refresh context", e);
+ }
+ }
+}
diff --git a/distribution-service/src/main/java/com/kt/distribution/dto/ChannelDistributionResult.java b/distribution-service/src/main/java/com/kt/distribution/dto/ChannelDistributionResult.java
index 915cfa1..9371880 100644
--- a/distribution-service/src/main/java/com/kt/distribution/dto/ChannelDistributionResult.java
+++ b/distribution-service/src/main/java/com/kt/distribution/dto/ChannelDistributionResult.java
@@ -32,6 +32,11 @@ public class ChannelDistributionResult {
*/
private String distributionId;
+ /**
+ * 배포 URL (성공 시) - 실제 포스팅된 URL
+ */
+ private String postUrl;
+
/**
* 예상 노출 수 (성공 시)
*/
diff --git a/distribution-service/src/main/java/com/kt/distribution/service/DistributionService.java b/distribution-service/src/main/java/com/kt/distribution/service/DistributionService.java
index 9b05107..1c743a4 100644
--- a/distribution-service/src/main/java/com/kt/distribution/service/DistributionService.java
+++ b/distribution-service/src/main/java/com/kt/distribution/service/DistributionService.java
@@ -225,6 +225,7 @@ public class DistributionService {
.channel(result.getChannel())
.status(result.isSuccess() ? "COMPLETED" : "FAILED")
.distributionId(result.getDistributionId())
+ .postUrl(result.getPostUrl())
.estimatedViews(result.getEstimatedReach())
.eventId(eventId)
.completedAt(completedAt)
diff --git a/distribution-service/src/main/resources/application.yml b/distribution-service/src/main/resources/application.yml
index 1059d92..490285d 100644
--- a/distribution-service/src/main/resources/application.yml
+++ b/distribution-service/src/main/resources/application.yml
@@ -129,7 +129,7 @@ naver:
username: ${NAVER_BLOG_USERNAME:}
password: ${NAVER_BLOG_PASSWORD:}
blog-id: ${NAVER_BLOG_ID:}
- headless: ${NAVER_BLOG_HEADLESS:true}
+ headless: ${NAVER_BLOG_HEADLESS:false}
session-path: ${NAVER_BLOG_SESSION_PATH:playwright-sessions}
# Springdoc OpenAPI (Swagger)