hgzero/develop/dev/dev-frontend-mock-guide.md
Minseo-Jo ab39e8d4ea ai-python 포트 8087 완전 통일 및 meeting-ai 테스트 완료
[포트 통일]
- ai-python 서비스 포트를 8087로 완전 통일
- 모든 문서에서 8086 참조 제거
- README.md, 개발 가이드 문서 전부 8087로 업데이트

변경 파일:
- ai-python/README.md
- develop/dev/ai-frontend-integration-guide.md
- develop/dev/dev-*.md (5개 파일)

[meeting-ai 테스트]
테스트 완료 항목:
✓ 회의록 통합 및 취합
✓ AI 한줄 요약/상세 요약 생성
✓ 회의 전체 결정사항 추출
✓ TODO 자동 추출 (9개)
✓ 통계 정보 생성
✓ 주요 키워드 추출 (10개)

테스트 파일:
- develop/test/meeting-ai-test-data.json (테스트 데이터)
- develop/test/consolidate-response.json (API 응답)
- develop/test/meeting-ai-test-result.md (상세 결과서)
2025-10-29 17:53:16 +09:00

9.3 KiB

프론트엔드 Mock 데이터 개발 가이드

작성일: 2025-10-27 대상: 프론트엔드 개발자 (유진) 작성자: AI팀 (서연), 백엔드팀 (준호)


📋 개요

현재 상황: STT 서비스 개발 완료 전까지는 실제 AI 제안사항이 생성되지 않습니다.

해결 방안: Mock 데이터를 사용하여 프론트엔드 UI를 독립적으로 개발할 수 있습니다.


🎯 왜 Mock 데이터가 필요한가?

실제 데이터 생성 흐름

회의 (음성)
    ↓
STT 서비스 (음성 → 텍스트) ← 아직 개발 중
    ↓
Redis (텍스트 축적)
    ↓
AI 서비스 (Claude API 분석)
    ↓
SSE 스트리밍
    ↓
프론트엔드

문제점: STT가 없으면 텍스트가 생성되지 않아 → Redis가 비어있음 → AI 분석이 실행되지 않음

해결: Mock 데이터로 STT 없이도 UI 개발 가능


💻 Mock 데이터 구현 방법

방법 1: 로컬 Mock 함수 (권장)

장점: 백엔드 없이 완전 독립 개발 가능

/**
 * Mock AI 제안사항 생성기
 * 실제 AI처럼 5초마다 하나씩 제안사항 발행
 */
function connectMockAISuggestions(meetingId) {
  const mockSuggestions = [
    {
      id: crypto.randomUUID(),
      content: "신제품의 타겟 고객층을 20-30대로 설정하고, 모바일 우선 전략을 취하기로 논의 중입니다.",
      timestamp: "00:05:23",
      confidence: 0.92
    },
    {
      id: crypto.randomUUID(),
      content: "개발 일정: 1차 프로토타입은 11월 15일까지 완성, 2차 베타는 12월 1일 론칭",
      timestamp: "00:08:45",
      confidence: 0.88
    },
    {
      id: crypto.randomUUID(),
      content: "마케팅 예산 배분에 대해 SNS 광고 60%, 인플루언서 마케팅 40%로 의견이 나왔으나 추가 검토 필요",
      timestamp: "00:12:18",
      confidence: 0.85
    },
    {
      id: crypto.randomUUID(),
      content: "보안 요구사항 검토가 필요하며, 데이터 암호화 방식에 대한 논의가 진행 중입니다.",
      timestamp: "00:15:30",
      confidence: 0.90
    },
    {
      id: crypto.randomUUID(),
      content: "React로 프론트엔드 개발하기로 결정되었으며, TypeScript 사용을 권장합니다.",
      timestamp: "00:18:42",
      confidence: 0.93
    }
  ];

  let index = 0;
  const interval = setInterval(() => {
    if (index < mockSuggestions.length) {
      // EventSource의 addEventListener('ai-suggestion', ...) 핸들러를 모방
      const event = {
        data: JSON.stringify({
          suggestions: [mockSuggestions[index]]
        })
      };

      // 실제 핸들러 호출
      handleAISuggestion(event);
      index++;
    } else {
      clearInterval(interval);
      console.log('[MOCK] 모든 Mock 제안사항 발행 완료');
    }
  }, 5000); // 5초마다 하나씩

  console.log('[MOCK] Mock AI 제안사항 연결 시작');

  // 정리 함수 반환
  return {
    close: () => {
      clearInterval(interval);
      console.log('[MOCK] Mock 연결 종료');
    }
  };
}

방법 2: 환경 변수로 전환

// 환경 변수로 Mock/Real 모드 전환
const USE_MOCK_AI = process.env.REACT_APP_USE_MOCK_AI === 'true';

function connectAISuggestions(meetingId) {
  if (USE_MOCK_AI) {
    console.log('[MOCK] Mock 모드로 실행');
    return connectMockAISuggestions(meetingId);
  } else {
    console.log('[REAL] 실제 AI 서비스 연결');
    return connectRealAISuggestions(meetingId);
  }
}

function connectRealAISuggestions(meetingId) {
  const url = `http://localhost:8087/api/v1/ai/suggestions/meetings/${meetingId}/stream`;
  const eventSource = new EventSource(url);

  eventSource.addEventListener('ai-suggestion', handleAISuggestion);

  eventSource.onerror = (error) => {
    console.error('[REAL] SSE 연결 오류:', error);
    eventSource.close();
  };

  return eventSource;
}

// 공통 핸들러
function handleAISuggestion(event) {
  const data = JSON.parse(event.data);

  data.suggestions.forEach(suggestion => {
    addSuggestionToUI(suggestion);
  });
}

🔧 개발 환경 설정

.env.local 파일

# Mock 모드 사용 (개발 중)
REACT_APP_USE_MOCK_AI=true

# 실제 AI 서비스 URL (STT 완료 후)
REACT_APP_AI_SERVICE_URL=http://localhost:8087

package.json 스크립트

{
  "scripts": {
    "start": "REACT_APP_USE_MOCK_AI=true react-scripts start",
    "start:real": "REACT_APP_USE_MOCK_AI=false react-scripts start",
    "build": "REACT_APP_USE_MOCK_AI=false react-scripts build"
  }
}

🎨 React 전체 예시

import { useEffect, useState, useRef } from 'react';

interface Suggestion {
  id: string;
  content: string;
  timestamp: string;
  confidence: number;
}

interface MockConnection {
  close: () => void;
}

function useMockAISuggestions(meetingId: string) {
  const [suggestions, setSuggestions] = useState<Suggestion[]>([]);
  const [connected, setConnected] = useState(false);
  const connectionRef = useRef<MockConnection | null>(null);

  useEffect(() => {
    const mockSuggestions: Suggestion[] = [
      {
        id: crypto.randomUUID(),
        content: "신제품의 타겟 고객층을 20-30대로 설정하고...",
        timestamp: "00:05:23",
        confidence: 0.92
      },
      // ... 더 많은 Mock 데이터
    ];

    let index = 0;
    setConnected(true);

    const interval = setInterval(() => {
      if (index < mockSuggestions.length) {
        setSuggestions(prev => [mockSuggestions[index], ...prev]);
        index++;
      } else {
        clearInterval(interval);
      }
    }, 5000);

    connectionRef.current = {
      close: () => {
        clearInterval(interval);
        setConnected(false);
      }
    };

    return () => {
      connectionRef.current?.close();
    };
  }, [meetingId]);

  return { suggestions, connected };
}

function AISuggestionsPanel({ meetingId }: { meetingId: string }) {
  const USE_MOCK = process.env.REACT_APP_USE_MOCK_AI === 'true';

  const mockData = useMockAISuggestions(meetingId);
  const realData = useRealAISuggestions(meetingId); // 실제 SSE 연결

  const { suggestions, connected } = USE_MOCK ? mockData : realData;

  return (
    <div className="ai-panel">
      <div className="header">
        <h3>AI 제안사항</h3>
        <span className={`badge ${connected ? 'connected' : 'disconnected'}`}>
          {connected ? (USE_MOCK ? 'Mock 모드' : '연결됨') : '연결 끊김'}
        </span>
      </div>

      <div className="suggestions">
        {suggestions.map(s => (
          <SuggestionCard key={s.id} suggestion={s} />
        ))}
      </div>
    </div>
  );
}

🧪 테스트 시나리오

1. Mock 모드 테스트

# Mock 모드로 실행
REACT_APP_USE_MOCK_AI=true npm start

확인 사항:

  • 5초마다 제안사항이 추가됨
  • 총 5개의 제안사항이 표시됨
  • 타임스탬프, 신뢰도가 정상 표시됨
  • "추가" 버튼 클릭 시 회의록에 추가됨
  • "무시" 버튼 클릭 시 제안사항이 제거됨

2. 실제 모드 테스트 (STT 완료 후)

# AI 서비스 시작
cd ai-python && ./start.sh

# 실제 모드로 실행
REACT_APP_USE_MOCK_AI=false npm start

확인 사항:

  • SSE 연결이 정상적으로 됨
  • 실제 AI 제안사항이 수신됨
  • 회의 진행에 따라 동적으로 제안사항 생성됨

📊 Mock vs Real 비교

항목 Mock 모드 Real 모드
백엔드 필요 불필요 필요 (AI 서비스)
제안 타이밍 5초 고정 간격 회의 진행에 따라 동적
제안 개수 5개 고정 무제한 (회의 종료까지)
데이터 품질 하드코딩 샘플 Claude AI 실제 분석
네트워크 필요 불필요 필요
개발 속도 빠름 느림 (백엔드 의존)

⚠️ 주의사항

1. Mock 데이터 관리

// ❌ 나쁜 예: 컴포넌트 내부에 하드코딩
function Component() {
  const mockData = [/* ... */];  // 재사용 불가
}

// ✅ 좋은 예: 별도 파일로 분리
// src/mocks/aiSuggestions.ts
export const MOCK_AI_SUGGESTIONS = [/* ... */];

2. 환경 변수 누락 방지

// ❌ 나쁜 예: 하드코딩
const USE_MOCK = true;

// ✅ 좋은 예: 환경 변수 + 기본값
const USE_MOCK = process.env.REACT_APP_USE_MOCK_AI !== 'false';

3. 프로덕션 빌드 시 Mock 제거

// ❌ 나쁜 예: 프로덕션에도 Mock 코드 포함
if (USE_MOCK) { /* mock logic */ }

// ✅ 좋은 예: Tree-shaking 가능하도록 작성
if (process.env.NODE_ENV !== 'production' && USE_MOCK) {
  /* mock logic */
}

🚀 다음 단계

Phase 1: Mock으로 UI 개발 (현재)

  • Mock 데이터 함수 구현
  • UI 컴포넌트 개발
  • 사용자 인터랙션 구현

Phase 2: STT 연동 대기 (진행 중)

  • 🔄 Backend에서 STT 개발 중
  • 🔄 Event Hub 연동 개발 중

Phase 3: 실제 연동 (STT 완료 후)

  • Mock → Real 모드 전환
  • 통합 테스트
  • 성능 최적화

📞 문의

Mock 데이터 관련: 프론트엔드팀 (유진) STT 개발 현황: 백엔드팀 (준호) AI 서비스: AI팀 (서연)


최종 업데이트: 2025-10-27