mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 12:36:23 +00:00
- AI 서비스 CORS 설정 업데이트 - 회의 진행 프로토타입 수정 - 빌드 리포트 및 로그 파일 업데이트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
10 KiB
10 KiB
AI 샘플 데이터 통합 가이드
개요
AI 서비스 개발이 완료되지 않은 상황에서 프론트엔드 개발을 병행하기 위해 샘플 데이터 자동 발행 기능을 구현했습니다.
목적
- 프론트엔드 개발자가 AI 기능 완성을 기다리지 않고 화면 개발 가능
- 실시간 SSE(Server-Sent Events) 스트리밍 동작 테스트
- 회의 진행 중 AI 제안사항 표시 기능 검증
주요 기능
- 백엔드: AI Service에서 5초마다 샘플 제안사항 3개 자동 발행
- 프론트엔드: EventSource API를 통한 실시간 데이터 수신 및 화면 표시
1. 백엔드 구현
1.1 수정 파일
- 파일:
ai/src/main/java/com/unicorn/hgzero/ai/biz/service/SuggestionService.java - 수정 내용:
startMockDataEmission()메서드 추가
1.2 구현 내용
Mock 데이터 자동 발행 메서드
/**
* TODO: AI 개발 완료 후 제거
* Mock 데이터 자동 발행 (프론트엔드 개발용)
* 5초마다 샘플 제안사항을 발행합니다.
*/
private void startMockDataEmission(String meetingId, Sinks.Many<RealtimeSuggestionsDto> sink) {
// 프론트엔드 HTML에 맞춘 샘플 데이터 (3개)
List<SimpleSuggestionDto> mockSuggestions = List.of(
SimpleSuggestionDto.builder()
.id("suggestion-1")
.content("신제품의 타겟 고객층을 20-30대로 설정하고, 모바일 우선 전략을 취하기로 논의 중입니다.")
.timestamp("00:05:23")
.confidence(0.92)
.build(),
// ... 3개의 샘플 데이터
);
// 5초마다 하나씩 발행 (총 3개)
Flux.interval(Duration.ofSeconds(5))
.take(3)
.map(index -> {
SimpleSuggestionDto suggestion = mockSuggestions.get(index.intValue());
return RealtimeSuggestionsDto.builder()
.suggestions(List.of(suggestion))
.build();
})
.subscribe(
suggestions -> {
sink.tryEmitNext(suggestions);
log.info("Mock 제안사항 발행 완료");
}
);
}
SSE 스트리밍 메서드 수정
@Override
public Flux<RealtimeSuggestionsDto> streamRealtimeSuggestions(String meetingId) {
// Sink 생성
Sinks.Many<RealtimeSuggestionsDto> sink = Sinks.many()
.multicast()
.onBackpressureBuffer();
meetingSinks.put(meetingId, sink);
// TODO: AI 개발 완료 후 제거 - Mock 데이터 자동 발행
startMockDataEmission(meetingId, sink);
return sink.asFlux()
.doOnCancel(() -> {
meetingSinks.remove(meetingId);
cleanupMeetingData(meetingId);
});
}
1.3 샘플 데이터 구조
{
"suggestions": [
{
"id": "suggestion-1",
"content": "신제품의 타겟 고객층을 20-30대로 설정하고, 모바일 우선 전략을 취하기로 논의 중입니다.",
"timestamp": "00:05:23",
"confidence": 0.92
}
]
}
2. 프론트엔드 구현
2.1 수정 파일
- 파일:
design/uiux/prototype/05-회의진행.html - 수정 내용: SSE 연결 및 실시간 데이터 수신 코드 추가
2.2 구현 내용
SSE 연결 함수
function connectAiSuggestionStream() {
const apiUrl = `http://localhost:8082/api/suggestions/meetings/${meetingId}/stream`;
eventSource = new EventSource(apiUrl);
eventSource.addEventListener('ai-suggestion', function(event) {
const data = JSON.parse(event.data);
const suggestions = data.suggestions;
if (suggestions && suggestions.length > 0) {
suggestions.forEach(suggestion => {
addAiSuggestionToUI(suggestion);
});
}
});
eventSource.onerror = function(error) {
console.error('SSE 연결 오류:', error);
eventSource.close();
};
}
UI 추가 함수
function addAiSuggestionToUI(suggestion) {
const listContainer = document.getElementById('aiSuggestionList');
const cardId = `suggestion-${suggestion.id}`;
// 중복 방지
if (document.getElementById(cardId)) {
return;
}
// AI 제안 카드 HTML 생성
const cardHtml = `
<div class="ai-suggestion-card" id="${cardId}">
<div class="ai-suggestion-header">
<span class="ai-suggestion-time">${suggestion.timestamp}</span>
<button class="ai-suggestion-add-btn"
onclick="addToMemo('${escapeHtml(suggestion.content)}', document.getElementById('${cardId}'))"
title="메모에 추가">
➕
</button>
</div>
<div class="ai-suggestion-text">
${escapeHtml(suggestion.content)}
</div>
</div>
`;
listContainer.insertAdjacentHTML('beforeend', cardHtml);
}
XSS 방지
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}
3. 테스트 방법
3.1 서비스 실행
1단계: AI 서비스 실행
# IntelliJ 실행 프로파일 사용
python3 tools/run-intellij-service-profile.py ai
# 또는 직접 실행
cd ai
./gradlew bootRun
실행 확인:
- 포트:
8082 - 로그 확인:
ai/logs/ai-service.log
2단계: 프론트엔드 HTML 열기
# 브라우저에서 직접 열기
open design/uiux/prototype/05-회의진행.html
# 또는 HTTP 서버 실행
cd design/uiux/prototype
python3 -m http.server 8000
# 브라우저: http://localhost:8000/05-회의진행.html
3.2 동작 확인
브라우저 콘솔 확인
- 개발자 도구 열기 (F12)
- Console 탭 확인
예상 로그:
AI 제안사항 SSE 스트림 연결됨: http://localhost:8082/api/suggestions/meetings/550e8400-e29b-41d4-a716-446655440000/stream
AI 제안사항 수신: {"suggestions":[{"id":"suggestion-1", ...}]}
AI 제안사항 추가됨: 신제품의 타겟 고객층을 20-30대로 설정하고...
화면 동작 확인
- 페이지 로드: 회의진행.html 열기
- AI 제안 탭 클릭: "AI 제안" 탭으로 이동
- 5초 대기: 첫 번째 제안사항 표시
- 10초 대기: 두 번째 제안사항 표시
- 15초 대기: 세 번째 제안사항 표시
백엔드 로그 확인
tail -f ai/logs/ai-service.log
예상 로그:
실시간 AI 제안사항 스트리밍 시작 - meetingId: 550e8400-e29b-41d4-a716-446655440000
Mock 데이터 자동 발행 시작 - meetingId: 550e8400-e29b-41d4-a716-446655440000
Mock 제안사항 발행 - meetingId: 550e8400-e29b-41d4-a716-446655440000, 제안: 신제품의 타겟 고객층...
3.3 API 직접 테스트 (curl)
# SSE 스트림 연결
curl -N http://localhost:8082/api/suggestions/meetings/550e8400-e29b-41d4-a716-446655440000/stream
예상 응답:
event: ai-suggestion
id: 123456789
data: {"suggestions":[{"id":"suggestion-1","content":"신제품의 타겟 고객층...","timestamp":"00:05:23","confidence":0.92}]}
event: ai-suggestion
id: 987654321
data: {"suggestions":[{"id":"suggestion-2","content":"개발 일정...","timestamp":"00:08:45","confidence":0.88}]}
4. CORS 설정 (필요 시)
프론트엔드를 다른 포트에서 실행할 경우 CORS 설정이 필요합니다.
4.1 application.yml 확인
# ai/src/main/resources/application.yml
spring:
web:
cors:
allowed-origins:
- http://localhost:8000
- http://localhost:3000
allowed-methods:
- GET
- POST
- PUT
- DELETE
allowed-headers:
- "*"
allow-credentials: true
5. 주의사항
5.1 Mock 데이터 제거 시점
⚠️ AI 개발 완료 후 반드시 제거해야 할 코드:
백엔드 (SuggestionService.java)
// TODO: AI 개발 완료 후 제거 - 이 줄 삭제
startMockDataEmission(meetingId, sink);
// TODO: AI 개발 완료 후 제거 - 이 메서드 전체 삭제
private void startMockDataEmission(...) { ... }
프론트엔드 (회의진행.html)
- SSE 연결 코드는 그대로 유지
- API URL만 실제 환경에 맞게 수정:
// 개발 환경
const apiUrl = `http://localhost:8082/api/suggestions/meetings/${meetingId}/stream`;
// 운영 환경 (예시)
const apiUrl = `/api/suggestions/meetings/${meetingId}/stream`;
5.2 제한사항
-
회의 ID 고정
- 현재 테스트용 회의 ID가 하드코딩됨
- 실제 환경에서는 회의 생성 API 응답에서 받아야 함
-
샘플 데이터 개수
- 현재 3개로 제한
- 실제 AI는 회의 진행에 따라 동적으로 생성
-
재연결 처리 없음
- SSE 연결이 끊어지면 재연결하지 않음
- 실제 환경에서는 재연결 로직 필요
-
인증/인가 없음
- 현재 JWT 토큰 검증 없이 테스트
- 실제 환경에서는 인증 헤더 추가 필요
6. 트러블슈팅
문제 1: SSE 연결 안 됨
증상: 브라우저 콘솔에 "SSE 연결 오류" 표시
해결 방법:
- AI 서비스가 실행 중인지 확인
curl http://localhost:8082/actuator/health - CORS 설정 확인
- 방화벽/포트 확인
문제 2: 제안사항이 표시되지 않음
증상: SSE는 연결되지만 화면에 아무것도 표시되지 않음
해결 방법:
- 브라우저 콘솔에서 에러 확인
- Network 탭에서 SSE 이벤트 확인
- 백엔드 로그 확인
문제 3: 중복 제안사항 표시
증상: 같은 제안이 여러 번 표시됨
해결 방법:
- 페이지 새로고침 (SSE 연결 재시작)
- 브라우저 캐시 삭제
7. 다음 단계
AI 개발 완료 후 작업
-
Mock 코드 제거
startMockDataEmission()메서드 삭제- 관련 TODO 주석 제거
-
실제 AI 로직 연결
- Claude API 연동
- Event Hub 메시지 수신
- Redis 텍스트 축적 및 분석
-
프론트엔드 개선
- 재연결 로직 추가
- 에러 핸들링 강화
- 로딩 상태 표시
-
성능 최적화
- SSE 연결 풀 관리
- 메모리 누수 방지
- 네트워크 재시도 전략
8. 관련 문서
문서 이력
| 버전 | 작성일 | 작성자 | 변경 내용 |
|---|---|---|---|
| 1.0 | 2025-10-27 | 준호 (Backend Developer) | 초안 작성 |