hgzero/.backup/prototype/05-회의진행.html
hiondal bb921e10eb 작업 파일 정리 및 실시간 회의록 플로우 추가
- 가파팀 프로토타입 파일 삭제
- 가파팀 유저스토리 삭제
- 실시간 회의록 작성 플로우 설계서 추가 (Mermaid, Markdown)
- 백업 및 데이터 디렉토리 추가
- AI 데이터 샘플 생성 도구 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 14:16:10 +09:00

648 lines
22 KiB
HTML

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>회의 진행 - 회의록 서비스</title>
<link rel="stylesheet" href="common.css">
<style>
body {
background-color: var(--color-gray-50);
margin: 0;
overflow: hidden;
}
.meeting-container {
display: flex;
flex-direction: column;
height: 100vh;
}
.meeting-header {
background: var(--color-white);
border-bottom: 1px solid var(--color-gray-200);
padding: var(--spacing-4) var(--spacing-6);
display: flex;
justify-content: space-between;
align-items: center;
}
.meeting-info {
display: flex;
align-items: center;
gap: var(--spacing-4);
}
.meeting-title {
font-size: var(--font-size-h4);
font-weight: var(--font-weight-semibold);
color: var(--color-gray-900);
}
.recording-indicator {
display: flex;
align-items: center;
gap: var(--spacing-2);
padding: var(--spacing-2) var(--spacing-3);
background-color: var(--color-error-light);
color: var(--color-error-dark);
border-radius: var(--radius-md);
font-size: var(--font-size-body-small);
font-weight: var(--font-weight-medium);
}
.recording-dot {
width: 8px;
height: 8px;
background-color: var(--color-error-main);
border-radius: var(--radius-full);
animation: blink 1.5s ease-in-out infinite;
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
.meeting-body {
display: flex;
flex: 1;
overflow: hidden;
}
.editor-panel {
flex: 1;
display: flex;
flex-direction: column;
background: var(--color-white);
border-right: 1px solid var(--color-gray-200);
}
.editor-toolbar {
padding: var(--spacing-3) var(--spacing-4);
border-bottom: 1px solid var(--color-gray-200);
display: flex;
gap: var(--spacing-2);
}
.editor-content {
flex: 1;
overflow-y: auto;
padding: var(--spacing-6);
}
.editor-textarea {
width: 100%;
min-height: 300px;
border: none;
font-family: inherit;
font-size: var(--font-size-body);
line-height: var(--line-height-relaxed);
resize: none;
outline: none;
}
.side-panel {
width: 400px;
background: var(--color-white);
display: flex;
flex-direction: column;
border-left: 1px solid var(--color-gray-200);
}
.side-panel-tabs {
display: flex;
border-bottom: 1px solid var(--color-gray-200);
}
.side-tab {
flex: 1;
padding: var(--spacing-3) var(--spacing-4);
background: transparent;
border: none;
border-bottom: 3px solid transparent;
font-size: var(--font-size-body-small);
font-weight: var(--font-weight-medium);
color: var(--color-gray-600);
cursor: pointer;
transition: all var(--transition-fast);
}
.side-tab.active {
color: var(--color-primary-main);
border-bottom-color: var(--color-primary-main);
}
.side-panel-content {
flex: 1;
overflow-y: auto;
padding: var(--spacing-4);
}
.attendee-item {
display: flex;
align-items: center;
gap: var(--spacing-3);
padding: var(--spacing-3);
margin-bottom: var(--spacing-2);
background: var(--color-gray-50);
border-radius: var(--radius-md);
}
.attendee-avatar {
width: 40px;
height: 40px;
border-radius: var(--radius-full);
background-color: var(--color-primary-main);
color: var(--color-white);
display: flex;
align-items: center;
justify-content: center;
font-weight: var(--font-weight-semibold);
}
.attendee-info {
flex: 1;
}
.attendee-name {
font-weight: var(--font-weight-medium);
color: var(--color-gray-900);
}
.attendee-status {
font-size: var(--font-size-caption);
color: var(--color-gray-500);
}
.ai-suggestion {
background-color: var(--color-gray-50);
border: 1px dashed var(--color-primary-main);
border-radius: var(--radius-md);
padding: var(--spacing-4);
margin-bottom: var(--spacing-4);
}
.ai-suggestion-header {
display: flex;
align-items: center;
gap: var(--spacing-2);
margin-bottom: var(--spacing-3);
font-weight: var(--font-weight-medium);
color: var(--color-primary-main);
}
.ai-suggestion-text {
font-size: var(--font-size-body-small);
color: var(--color-gray-600);
line-height: var(--line-height-relaxed);
margin-bottom: var(--spacing-3);
}
.ai-actions {
display: flex;
gap: var(--spacing-2);
}
/* 용어 사전 탭 스타일 */
.term-search-box {
margin-bottom: var(--spacing-4);
}
.term-search-input {
width: 100%;
padding: var(--spacing-3);
border: 1px solid var(--color-gray-300);
border-radius: var(--radius-md);
font-size: var(--font-size-body);
outline: none;
transition: all var(--transition-fast);
}
.term-search-input:focus {
border-color: var(--color-primary-main);
box-shadow: 0 0 0 3px rgba(0, 217, 177, 0.1);
}
.term-list {
display: flex;
flex-direction: column;
gap: var(--spacing-3);
}
.term-item {
background: var(--color-white);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-md);
padding: var(--spacing-4);
cursor: pointer;
transition: all var(--transition-fast);
}
.term-item:hover {
border-color: var(--color-primary-main);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.term-item.highlight {
background-color: var(--color-primary-light);
border-color: var(--color-primary-main);
}
.term-name {
font-size: var(--font-size-body);
font-weight: var(--font-weight-semibold);
color: var(--color-gray-900);
margin-bottom: var(--spacing-2);
display: flex;
align-items: center;
gap: var(--spacing-2);
}
.term-badge {
font-size: var(--font-size-caption);
padding: 2px var(--spacing-2);
background-color: var(--color-primary-light);
color: var(--color-primary-dark);
border-radius: var(--radius-sm);
font-weight: var(--font-weight-medium);
}
.term-definition {
font-size: var(--font-size-body-small);
color: var(--color-gray-600);
line-height: var(--line-height-relaxed);
margin-bottom: var(--spacing-2);
}
.term-context {
font-size: var(--font-size-caption);
color: var(--color-gray-500);
padding-top: var(--spacing-2);
border-top: 1px solid var(--color-gray-100);
}
.no-results {
text-align: center;
padding: var(--spacing-8);
color: var(--color-gray-500);
}
@media (max-width: 1023px) {
.side-panel {
position: fixed;
right: -400px;
top: 0;
height: 100vh;
z-index: var(--z-sticky);
box-shadow: var(--shadow-lg);
transition: right var(--transition-base);
}
.side-panel.open {
right: 0;
}
}
</style>
</head>
<body>
<div class="meeting-container">
<!-- 헤더 -->
<div class="meeting-header">
<div class="meeting-info">
<h1 class="meeting-title" id="meetingTitle">회의 진행 중</h1>
<div class="recording-indicator">
<div class="recording-dot"></div>
<span id="recordingTime">00:00</span>
</div>
</div>
<div style="display: flex; gap: var(--spacing-3);">
<button class="btn btn-text btn-icon hide-desktop" id="toggleSidePanel"></button>
<button class="btn btn-secondary" onclick="if(confirm('회의를 종료하시겠습니까?')) window.location.href='06-검증완료.html'">
회의 종료
</button>
</div>
</div>
<!-- 본문 -->
<div class="meeting-body">
<!-- 에디터 패널 -->
<div class="editor-panel">
<div class="editor-toolbar">
<button class="btn btn-text btn-icon-sm">B</button>
<button class="btn btn-text btn-icon-sm">I</button>
<button class="btn btn-text btn-icon-sm">U</button>
<button class="btn btn-text btn-icon-sm">📝</button>
<button class="btn btn-text btn-icon-sm">🔗</button>
</div>
<div class="editor-content">
<textarea class="editor-textarea" id="meetingContent" placeholder="회의 내용을 작성하거나 AI가 자동으로 작성합니다...
# 참석자
- 김민준
- 박서연
- 이준호
# 안건
1. 신규 기능 개발 일정 논의
2. 예산 편성 검토
# 논의 내용
Mobile First 설계 방침으로 진행하기로 결정
AI 기반 회의록 자동 작성 기능을 핵심으로 개발
API Gateway 구축 및 마이크로서비스 아키텍처 적용
"></textarea>
</div>
</div>
<!-- 사이드 패널 -->
<div class="side-panel" id="sidePanel">
<div class="side-panel-tabs">
<button class="side-tab active" data-tab="attendees">참석자</button>
<button class="side-tab" data-tab="ai">AI 제안</button>
<button class="side-tab" data-tab="terms">용어 사전</button>
<button class="side-tab" data-tab="related">관련 자료</button>
</div>
<div class="side-panel-content">
<!-- 참석자 탭 -->
<div class="tab-content" data-content="attendees">
<h3 style="margin-bottom: var(--spacing-4); font-size: var(--font-size-h4);">참석자 (3명)</h3>
<div class="attendee-item">
<div class="attendee-avatar"></div>
<div class="attendee-info">
<div class="attendee-name">김민준</div>
<div class="attendee-status">발언 중 ✍️</div>
</div>
</div>
<div class="attendee-item">
<div class="attendee-avatar" style="background-color: var(--color-secondary-main);"></div>
<div class="attendee-info">
<div class="attendee-name">박서연</div>
<div class="attendee-status">온라인</div>
</div>
</div>
<div class="attendee-item">
<div class="attendee-avatar" style="background-color: var(--color-info-main);"></div>
<div class="attendee-info">
<div class="attendee-name">이준호</div>
<div class="attendee-status">온라인</div>
</div>
</div>
</div>
<!-- AI 제안 탭 -->
<div class="tab-content" data-content="ai" style="display: none;">
<h3 style="margin-bottom: var(--spacing-4); font-size: var(--font-size-h4);">AI 제안</h3>
<div class="ai-suggestion">
<div class="ai-suggestion-header">
✨ 회의록 요약 제안
</div>
<div class="ai-suggestion-text">
Mobile First 설계 방침 확정 및 AI 기반 자동 작성 기능 개발 착수 결정. 마이크로서비스 아키텍처와 API Gateway 구축 계획 수립.
</div>
<div class="ai-actions">
<button class="btn btn-primary btn-sm">회의록에 적용</button>
<button class="btn btn-text btn-sm">수정</button>
</div>
</div>
<div class="ai-suggestion">
<div class="ai-suggestion-header">
📋 액션 아이템(Todo) 자동 추출
</div>
<div class="ai-suggestion-text">
1. API 명세서 작성 (이준호, 3/25까지)<br>
2. UI 프로토타입 완성 (최유진, 3/15까지)<br>
3. 예산 편성안 최종 검토 (박서연, 3/20까지)
</div>
<div class="ai-actions">
<button class="btn btn-primary btn-sm">3개 Todo 생성</button>
<button class="btn btn-text btn-sm">수정</button>
</div>
</div>
</div>
<!-- 용어 사전 탭 (NEW) -->
<div class="tab-content" data-content="terms" style="display: none;">
<h3 style="margin-bottom: var(--spacing-4); font-size: var(--font-size-h4);">용어 사전</h3>
<!-- 검색 입력 -->
<div class="term-search-box">
<input
type="text"
class="term-search-input"
id="termSearchInput"
placeholder="용어를 검색하세요 (예: API, Mobile First)"
/>
</div>
<!-- 용어 목록 -->
<div class="term-list" id="termList">
<!-- JavaScript로 동적 생성 -->
</div>
<!-- 검색 결과 없음 -->
<div class="no-results" id="noResults" style="display: none;">
<div style="font-size: 48px; opacity: 0.3; margin-bottom: var(--spacing-3);">🔍</div>
<div>검색 결과가 없습니다</div>
</div>
</div>
<!-- 관련 자료 탭 -->
<div class="tab-content" data-content="related" style="display: none;">
<h3 style="margin-bottom: var(--spacing-4); font-size: var(--font-size-h4);">관련 자료</h3>
<div style="margin-bottom: var(--spacing-6);">
<h4 style="font-size: var(--font-size-body); font-weight: var(--font-weight-semibold); color: var(--color-gray-700); margin-bottom: var(--spacing-3);">
📄 관련 회의록 (3건)
</h4>
<div class="ai-suggestion" style="cursor: pointer;">
<div class="ai-suggestion-header" style="color: var(--color-gray-900);">
2024년 4분기 제품 기획 회의
</div>
<div class="ai-suggestion-text">
<div style="display: flex; gap: var(--spacing-2); margin-bottom: var(--spacing-2); font-size: var(--font-size-caption);">
<span>2024-10-15</span> | <span style="color: var(--color-success-main);">관련도 92%</span>
</div>
<div>신규 회의록 서비스 MVP 개발 일정 논의. AI 기능 우선순위와 예산 확정.</div>
</div>
</div>
<div class="ai-suggestion" style="cursor: pointer;">
<div class="ai-suggestion-header" style="color: var(--color-gray-900);">
API 설계 리뷰 회의
</div>
<div class="ai-suggestion-text">
<div style="display: flex; gap: var(--spacing-2); margin-bottom: var(--spacing-2); font-size: var(--font-size-caption);">
<span>2024-09-28</span> | <span style="color: var(--color-warning-main);">관련도 78%</span>
</div>
<div>RESTful API 설계 원칙과 보안 정책 확정. 담당자별 역할 분담.</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="common.js"></script>
<script>
// 용어 사전 데이터
const TERMINOLOGY = [
{
id: 'mobile-first',
name: 'Mobile First',
category: '설계 방법론',
definition: '모바일 환경을 우선적으로 고려하여 디자인하고, 이후 더 큰 화면으로 확장하는 설계 방법론입니다.',
context: '회의에서 언급됨 (14:23)',
usedInMeeting: true
},
{
id: 'ai',
name: 'AI',
category: '기술',
definition: 'Artificial Intelligence의 약자로, 인공지능을 의미합니다. 이 프로젝트에서는 회의록 자동 작성에 활용됩니다.',
context: '회의에서 5회 언급됨',
usedInMeeting: true
},
{
id: 'api',
name: 'API',
category: '기술',
definition: 'Application Programming Interface의 약자로, 소프트웨어 간 상호작용을 위한 인터페이스입니다.',
context: '회의에서 3회 언급됨',
usedInMeeting: true
},
{
id: 'api-gateway',
name: 'API Gateway',
category: '아키텍처',
definition: '클라이언트와 백엔드 마이크로서비스 사이의 단일 진입점 역할을 하는 서버. 요청 라우팅, 인증, 속도 제한, 로드 밸런싱 등을 처리합니다.',
context: 'API 설계 리뷰 회의 (2024-09-28)에서 AWS API Gateway 채택 결정',
usedInMeeting: true
},
{
id: 'microservice',
name: '마이크로서비스',
category: '아키텍처',
definition: '애플리케이션을 작고 독립적인 서비스들로 분리하여 개발하고 배포하는 아키텍처 패턴입니다.',
context: '회의에서 언급됨',
usedInMeeting: true
},
{
id: 'mvp',
name: 'MVP',
category: '방법론',
definition: 'Minimum Viable Product의 약자. 최소한의 기능만 갖춘 제품으로, 시장 반응을 빠르게 확인하기 위해 개발합니다.',
context: '개발 일정 논의에서 언급',
usedInMeeting: true
},
{
id: 'restful',
name: 'RESTful API',
category: '기술',
definition: 'REST(Representational State Transfer) 아키텍처 스타일을 따르는 웹 서비스 API 설계 방식입니다.',
context: 'API 설계 리뷰 회의 참조',
usedInMeeting: false
},
{
id: 'jwt',
name: 'JWT',
category: '보안',
definition: 'JSON Web Token의 약자. 사용자 인증 정보를 안전하게 전송하기 위한 토큰 기반 인증 방식입니다.',
context: 'API Gateway 보안 정책에서 채택',
usedInMeeting: false
}
];
// 용어 렌더링
function renderTerms(terms) {
const termList = document.getElementById('termList');
const noResults = document.getElementById('noResults');
if (terms.length === 0) {
termList.innerHTML = '';
noResults.style.display = 'block';
return;
}
noResults.style.display = 'none';
termList.innerHTML = terms.map(term => `
<div class="term-item ${term.usedInMeeting ? 'highlight' : ''}" onclick="showTermDetail('${term.id}')">
<div class="term-name">
${term.name}
<span class="term-badge">${term.category}</span>
${term.usedInMeeting ? '<span style="font-size: 16px;">💬</span>' : ''}
</div>
<div class="term-definition">${term.definition}</div>
<div class="term-context">${term.context}</div>
</div>
`).join('');
}
// 용어 검색
function searchTerms(query) {
if (!query || query.trim() === '') {
renderTerms(TERMINOLOGY);
return;
}
const lowerQuery = query.toLowerCase();
const filtered = TERMINOLOGY.filter(term =>
term.name.toLowerCase().includes(lowerQuery) ||
term.definition.toLowerCase().includes(lowerQuery) ||
term.category.toLowerCase().includes(lowerQuery)
);
renderTerms(filtered);
}
// 용어 상세 보기
function showTermDetail(termId) {
const term = TERMINOLOGY.find(t => t.id === termId);
if (!term) return;
window.MeetingApp.Toast.show(
`📚 ${term.name}\n\n${term.definition}\n\n${term.context}`,
'info',
5000
);
}
// 검색 입력 이벤트
const searchInput = document.getElementById('termSearchInput');
if (searchInput) {
searchInput.addEventListener('input', (e) => {
searchTerms(e.target.value);
});
}
// 탭 전환
const tabs = document.querySelectorAll('.side-tab');
const tabContents = document.querySelectorAll('.tab-content');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const targetTab = tab.getAttribute('data-tab');
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
tabContents.forEach(content => {
if (content.getAttribute('data-content') === targetTab) {
content.style.display = 'block';
// 용어 사전 탭 열 때 초기 렌더링
if (targetTab === 'terms' && !content.dataset.rendered) {
renderTerms(TERMINOLOGY);
content.dataset.rendered = 'true';
}
} else {
content.style.display = 'none';
}
});
});
});
// 사이드 패널 토글 (모바일)
const toggleBtn = document.getElementById('toggleSidePanel');
const sidePanel = document.getElementById('sidePanel');
if (toggleBtn) {
toggleBtn.addEventListener('click', () => {
sidePanel.classList.toggle('open');
});
}
// 녹음 시간 업데이트
let seconds = 0;
const recordingTimeEl = document.getElementById('recordingTime');
setInterval(() => {
seconds++;
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
recordingTimeEl.textContent = `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
}, 1000);
// 자동 저장 시뮬레이션
const editorTextarea = document.getElementById('meetingContent');
let saveTimeout;
editorTextarea.addEventListener('input', () => {
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
console.log('자동 저장됨');
}, 2000);
});
</script>
</body>
</html>