Merge branch 'main' of https://github.com/hwanny1128/HGZero into feat/meeting-confirmed

This commit is contained in:
djeon 2025-10-25 12:59:21 +09:00
commit 0da631b8e7
3 changed files with 344 additions and 390 deletions

View File

@ -13,6 +13,32 @@
padding-bottom: 80px;
}
/* 템플릿 그리드 */
.template-list {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--space-md);
}
/* 템플릿 카드 높이 균등 */
.template-list .card {
display: flex;
flex-direction: column;
height: 100%;
}
.template-list .card-body {
flex: 1;
}
/* 모바일: 작은 간격 */
@media (max-width: 767px) {
.template-list {
gap: var(--space-sm);
}
}
/* 데스크톱: 메인 콘텐츠 조정 */
@media (min-width: 768px) {
.main-content {
@ -41,18 +67,16 @@
<p class="text-muted">회의 유형에 맞는 템플릿을 선택하세요</p>
</div>
<!-- Template Cards -->
<div class="template-list" style="display: flex; flex-direction: column; gap: var(--space-md);">
<!-- Template Cards (2x2 grid) -->
<div class="template-list">
<!-- 일반 회의 템플릿 -->
<div class="card" style="cursor: pointer;" onclick="selectTemplate('general')">
<div class="card-header">
<div style="display: flex; align-items: center; gap: var(--space-md);">
<div style="font-size: 32px;">📋</div>
<div>
<h3 class="card-title">일반 회의</h3>
<p class="text-muted text-small">기본 회의록 형식</p>
</div>
<div class="card-header" style="display: block !important;">
<div style="margin-bottom: 4px;">
<span style="font-size: 20px;">📋</span>
<span style="font-size: 14px; font-weight: 600; margin-left: 4px;">일반 회의</span>
</div>
<div style="font-size: 11px; color: var(--text-muted);">기본 회의록 형식</div>
</div>
<div class="card-body">
<div class="text-small text-muted">
@ -63,21 +87,18 @@
</div>
</div>
<div class="card-footer">
<button class="btn btn-secondary btn-sm" onclick="previewTemplate(event, 'general')">미리보기</button>
<button class="btn btn-primary btn-sm" onclick="selectTemplate('general')">선택</button>
<button class="btn btn-primary btn-sm" onclick="selectTemplate('general')" style="width: 100%;">선택</button>
</div>
</div>
<!-- 스크럼 회의 템플릿 -->
<div class="card" style="cursor: pointer;" onclick="selectTemplate('scrum')">
<div class="card-header">
<div style="display: flex; align-items: center; gap: var(--space-md);">
<div style="font-size: 32px;">🏃</div>
<div>
<h3 class="card-title">스크럼 회의</h3>
<p class="text-muted text-small">데일리 스탠드업 형식</p>
</div>
<div class="card-header" style="display: block !important;">
<div style="margin-bottom: 4px;">
<span style="font-size: 20px;">🏃</span>
<span style="font-size: 14px; font-weight: 600; margin-left: 4px;">스크럼 회의</span>
</div>
<div style="font-size: 11px; color: var(--text-muted);">데일리 스탠드업 형식</div>
</div>
<div class="card-body">
<div class="text-small text-muted">
@ -87,21 +108,18 @@
</div>
</div>
<div class="card-footer">
<button class="btn btn-secondary btn-sm" onclick="previewTemplate(event, 'scrum')">미리보기</button>
<button class="btn btn-primary btn-sm" onclick="selectTemplate('scrum')">선택</button>
<button class="btn btn-primary btn-sm" onclick="selectTemplate('scrum')" style="width: 100%;">선택</button>
</div>
</div>
<!-- 킥오프 회의 템플릿 -->
<div class="card" style="cursor: pointer;" onclick="selectTemplate('kickoff')">
<div class="card-header">
<div style="display: flex; align-items: center; gap: var(--space-md);">
<div style="font-size: 32px;">🚀</div>
<div>
<h3 class="card-title">킥오프 회의</h3>
<p class="text-muted text-small">프로젝트 시작 회의</p>
</div>
<div class="card-header" style="display: block !important;">
<div style="margin-bottom: 4px;">
<span style="font-size: 20px;">🚀</span>
<span style="font-size: 14px; font-weight: 600; margin-left: 4px;">킥오프 회의</span>
</div>
<div style="font-size: 11px; color: var(--text-muted);">프로젝트 시작 회의</div>
</div>
<div class="card-body">
<div class="text-small text-muted">
@ -112,21 +130,18 @@
</div>
</div>
<div class="card-footer">
<button class="btn btn-secondary btn-sm" onclick="previewTemplate(event, 'kickoff')">미리보기</button>
<button class="btn btn-primary btn-sm" onclick="selectTemplate('kickoff')">선택</button>
<button class="btn btn-primary btn-sm" onclick="selectTemplate('kickoff')" style="width: 100%;">선택</button>
</div>
</div>
<!-- 주간 회의 템플릿 -->
<div class="card" style="cursor: pointer;" onclick="selectTemplate('weekly')">
<div class="card-header">
<div style="display: flex; align-items: center; gap: var(--space-md);">
<div style="font-size: 32px;">📅</div>
<div>
<h3 class="card-title">주간 회의</h3>
<p class="text-muted text-small">주간 리뷰 및 계획</p>
</div>
<div class="card-header" style="display: block !important;">
<div style="margin-bottom: 4px;">
<span style="font-size: 20px;">📅</span>
<span style="font-size: 14px; font-weight: 600; margin-left: 4px;">주간 회의</span>
</div>
<div style="font-size: 11px; color: var(--text-muted);">주간 리뷰 및 계획</div>
</div>
<div class="card-body">
<div class="text-small text-muted">
@ -137,72 +152,12 @@
</div>
</div>
<div class="card-footer">
<button class="btn btn-secondary btn-sm" onclick="previewTemplate(event, 'weekly')">미리보기</button>
<button class="btn btn-primary btn-sm" onclick="selectTemplate('weekly')">선택</button>
<button class="btn btn-primary btn-sm" onclick="selectTemplate('weekly')" style="width: 100%;">선택</button>
</div>
</div>
</div>
</main>
<!-- Template Preview Modal -->
<div id="previewModal" class="modal-overlay">
<div class="modal">
<div class="modal-header">
<h2 class="modal-title" id="previewTitle">템플릿 미리보기</h2>
<button class="modal-close" onclick="closeModal('previewModal')"></button>
</div>
<div class="modal-body">
<div id="previewContent" style="max-height: 400px; overflow-y: auto;">
<!-- 섹션 리스트가 여기에 표시됨 -->
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('previewModal')">닫기</button>
<button class="btn btn-primary" onclick="customizeTemplate()">커스터마이징</button>
</div>
</div>
</div>
<!-- Template Customization Modal -->
<div id="customizeModal" class="modal-overlay">
<div class="modal">
<div class="modal-header">
<h2 class="modal-title">템플릿 커스터마이징</h2>
<button class="modal-close" onclick="closeModal('customizeModal')"></button>
</div>
<div class="modal-body">
<p class="text-small text-muted mb-md">섹션을 드래그하여 순서를 변경하거나 삭제할 수 있습니다</p>
<div id="sectionList" style="display: flex; flex-direction: column; gap: var(--space-sm);">
<!-- 섹션 목록이 여기에 표시됨 -->
</div>
<button class="btn btn-ghost mt-md" onclick="addSection()" style="width: 100%;">+ 섹션 추가</button>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('customizeModal')">취소</button>
<button class="btn btn-primary" onclick="startMeeting()">이 템플릿으로 시작</button>
</div>
</div>
</div>
<!-- Add Section Modal -->
<div id="addSectionModal" class="modal-overlay">
<div class="modal">
<div class="modal-header">
<h2 class="modal-title">섹션 추가</h2>
<button class="modal-close" onclick="closeModal('addSectionModal')"></button>
</div>
<div class="modal-body">
<div class="form-group">
<label class="form-label">섹션 이름</label>
<input type="text" class="form-control" id="newSectionName" placeholder="예: 기술 검토">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('addSectionModal')">취소</button>
<button class="btn btn-primary" onclick="confirmAddSection()">추가</button>
</div>
</div>
</div>
<script src="common.js"></script>
<script>
@ -230,35 +185,13 @@
}
};
let selectedTemplate = null;
let customSections = [];
// 템플릿 미리보기
function previewTemplate(event, templateId) {
event.stopPropagation();
const template = templates[templateId];
$('#previewTitle').textContent = template.name + ' 미리보기';
const content = template.sections.map((section, index) => `
<div class="list-item">
<span class="text-muted text-small">${index + 1}.</span>
<span class="list-item-title">${section}</span>
</div>
`).join('');
$('#previewContent').innerHTML = content;
openModal('previewModal');
}
// 템플릿 선택
function selectTemplate(templateId) {
selectedTemplate = templateId;
customSections = [...templates[templateId].sections];
const templateSections = [...templates[templateId].sections];
// 회의 진행 화면으로 이동
saveToStorage('selectedTemplate', templateId);
saveToStorage('templateSections', customSections);
saveToStorage('templateSections', templateSections);
navigateTo('05-회의진행.html');
}
@ -276,114 +209,6 @@
$('#skip-btn')?.addEventListener('click', () => {
skipTemplate();
});
// 커스터마이징 모달 열기
function customizeTemplate() {
closeModal('previewModal');
renderSectionList();
openModal('customizeModal');
}
// 섹션 리스트 렌더링
function renderSectionList() {
const sectionList = $('#sectionList');
sectionList.innerHTML = customSections.map((section, index) => `
<div class="list-item" draggable="true" data-index="${index}">
<span class="text-muted"></span>
<span class="list-item-title" style="flex: 1;">${section}</span>
<button class="btn btn-ghost btn-sm" onclick="removeSection(${index})">
<span style="color: var(--error);"></span>
</button>
</div>
`).join('');
// 드래그 이벤트 설정
setupDragAndDrop();
}
// 드래그 앤 드롭 설정
function setupDragAndDrop() {
const items = $$('#sectionList .list-item');
let draggedItem = null;
items.forEach(item => {
item.addEventListener('dragstart', function() {
draggedItem = this;
this.style.opacity = '0.5';
});
item.addEventListener('dragend', function() {
this.style.opacity = '1';
});
item.addEventListener('dragover', function(e) {
e.preventDefault();
});
item.addEventListener('drop', function(e) {
e.preventDefault();
if (draggedItem !== this) {
const draggedIndex = parseInt(draggedItem.dataset.index);
const targetIndex = parseInt(this.dataset.index);
const temp = customSections[draggedIndex];
customSections.splice(draggedIndex, 1);
customSections.splice(targetIndex, 0, temp);
renderSectionList();
}
});
});
}
// 섹션 삭제
function removeSection(index) {
if (customSections.length <= 1) {
showToast('최소 1개의 섹션이 필요합니다', 'error');
return;
}
customSections.splice(index, 1);
renderSectionList();
}
// 섹션 추가 모달 열기
function addSection() {
openModal('addSectionModal');
$('#newSectionName').value = '';
$('#newSectionName').focus();
}
// 섹션 추가 확인
function confirmAddSection() {
const name = $('#newSectionName').value.trim();
if (!name) {
showToast('섹션 이름을 입력해주세요', 'error');
return;
}
customSections.push(name);
renderSectionList();
closeModal('addSectionModal');
showToast('섹션이 추가되었습니다', 'success');
}
// 회의 시작
function startMeeting() {
if (customSections.length === 0) {
showToast('최소 1개의 섹션이 필요합니다', 'error');
return;
}
saveToStorage('selectedTemplate', selectedTemplate);
saveToStorage('templateSections', customSections);
navigateTo('05-회의진행.html');
}
// Enter 키로 섹션 추가
$('#addSectionModal')?.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
confirmAddSection();
}
});
</script>
</body>
</html>

View File

@ -129,18 +129,23 @@
flex: 1;
overflow-y: auto;
background: var(--gray-100);
padding: 0 var(--space-md) 10px;
padding: var(--space-md);
padding-bottom: 88px; /* 하단 버튼 영역 확보 */
max-width: none !important; /* common.css의 max-width: 900px 오버라이드 */
margin: 0 !important; /* common.css의 auto margin 제거 */
}
@media (min-width: 768px) {
.main-content {
padding: 0 var(--space-lg) 88px;
padding: var(--space-lg);
padding-bottom: 88px;
}
}
@media (min-width: 1024px) {
.main-content {
padding: 0 var(--space-xl) 88px;
padding: var(--space-xl);
padding-bottom: 88px;
}
}
@ -151,6 +156,8 @@
padding: var(--space-md);
margin-bottom: var(--space-md);
box-shadow: var(--shadow-md);
width: 100%;
box-sizing: border-box;
}
.meeting-info-grid {
@ -192,6 +199,11 @@
border-radius: var(--radius-lg);
box-shadow: var(--shadow-md);
margin-bottom: var(--space-md);
width: 100%;
max-width: 100%;
min-width: 0;
box-sizing: border-box;
display: block;
}
.tabs-header {
@ -248,22 +260,19 @@
.tab-content {
display: none;
padding: var(--space-md);
width: 100%;
box-sizing: border-box;
}
.tab-content.active {
display: block;
}
@media (min-width: 768px) {
.tab-content {
padding: var(--space-lg);
}
}
@media (min-width: 1024px) {
.tab-content {
padding: var(--space-xl);
}
/* 모든 탭 콘텐츠 내부 요소 텍스트 줄바꿈 강제 */
.tab-content * {
max-width: 100%;
word-wrap: break-word;
overflow-wrap: break-word;
}
/* 참석자 탭 */
@ -437,6 +446,26 @@
line-height: 1.5;
}
/* 용어 검색 폼 */
.term-search-form {
display: flex;
gap: var(--space-xs);
margin-bottom: var(--space-sm);
}
.term-search-input {
flex: 1;
font-size: var(--font-small);
padding: var(--space-sm);
}
.term-search-btn {
padding: var(--space-sm) var(--space-md);
font-size: var(--font-small);
white-space: nowrap;
flex-shrink: 0;
}
/* 용어 사전 카드 */
.term-item {
background: #FAFAFA;
@ -708,7 +737,7 @@
</div>
<h4 class="ai-suggestion-list-title">
💬 AI가 실시간으로 분석한 제안사항
💬 AI가 실시간으로 분석한 주요 내용
</h4>
<div id="aiSuggestionList">
@ -757,8 +786,21 @@
<div class="tab-content" id="tab-terms">
<h3 class="text-small font-bold mb-md">용어 사전</h3>
<!-- 용어 검색 폼 -->
<div class="term-search-form">
<input
type="text"
class="form-control term-search-input"
id="termSearchInput"
placeholder="용어 검색..."
>
<button class="btn btn-primary btn-sm term-search-btn" onclick="searchTerm()">
검색
</button>
</div>
<div id="termsList">
<div class="term-item" onclick="showTermDetail('MVP')">
<div class="term-item highlight" onclick="showTermDetail('MVP')">
<div class="term-name">
MVP
<span class="term-badge">기획</span>
@ -769,7 +811,7 @@
<div class="term-context">신제품 기획 회의에서 언급</div>
</div>
<div class="term-item" onclick="showTermDetail('B2C')">
<div class="term-item highlight" onclick="showTermDetail('B2C')">
<div class="term-name">
B2C
<span class="term-badge">비즈니스</span>
@ -780,7 +822,7 @@
<div class="term-context">타겟 고객 분석 시 사용</div>
</div>
<div class="term-item" onclick="showTermDetail('PMF')">
<div class="term-item highlight" onclick="showTermDetail('PMF')">
<div class="term-name">
PMF
<span class="term-badge">전략</span>
@ -791,7 +833,7 @@
<div class="term-context">제품 전략 논의 중 언급</div>
</div>
<div class="term-item" onclick="showTermDetail('CAC')">
<div class="term-item highlight" onclick="showTermDetail('CAC')">
<div class="term-name">
CAC
<span class="term-badge">마케팅</span>
@ -801,6 +843,102 @@
</div>
<div class="term-context">마케팅 예산 논의에서 사용</div>
</div>
</div>
<div id="termList">
<div class="term-item" onclick="showTermDetail('Mobile First')">
<div class="term-name">
Mobile First
<span class="term-badge">설계 방법론</span>
<span class="term-mention-icon">💬</span>
</div>
<div class="term-definition">
모바일 환경을 우선적으로 고려하여 디자인하고, 이후 더 큰 화면으로 확장하는 설계 방법론입니다.
</div>
<div class="term-context">회의에서 언급됨 (14:23)</div>
</div>
<div class="term-item" onclick="showTermDetail('AI')">
<div class="term-name">
AI
<span class="term-badge">기술</span>
<span class="term-mention-icon">💬</span>
</div>
<div class="term-definition">
Artificial Intelligence의 약자로, 인공지능을 의미합니다. 이 프로젝트에서는 회의록 자동 작성에 활용됩니다.
</div>
<div class="term-context">회의에서 5회 언급됨</div>
</div>
<div class="term-item" onclick="showTermDetail('API')">
<div class="term-name">
API
<span class="term-badge">기술</span>
<span class="term-mention-icon">💬</span>
</div>
<div class="term-definition">
Application Programming Interface의 약자로, 소프트웨어 간 상호작용을 위한 인터페이스입니다.
</div>
<div class="term-context">회의에서 3회 언급됨</div>
</div>
<div class="term-item" onclick="showTermDetail('API Gateway')">
<div class="term-name">
API Gateway
<span class="term-badge">아키텍처</span>
<span class="term-mention-icon">💬</span>
</div>
<div class="term-definition">
클라이언트와 백엔드 마이크로서비스 사이의 단일 진입점 역할을 하는 서버. 요청 라우팅, 인증, 속도 제한, 로드 밸런싱 등을 처리합니다.
</div>
<div class="term-context">API 설계 리뷰 회의 (2024-09-28)에서 AWS API Gateway 채택 결정</div>
</div>
<div class="term-item" onclick="showTermDetail('마이크로서비스')">
<div class="term-name">
마이크로서비스
<span class="term-badge">아키텍처</span>
<span class="term-mention-icon">💬</span>
</div>
<div class="term-definition">
애플리케이션을 작고 독립적인 서비스들로 분리하여 개발하고 배포하는 아키텍처 패턴입니다.
</div>
<div class="term-context">회의에서 언급됨</div>
</div>
<div class="term-item " onclick="showTermDetail('MVP')">
<div class="term-name">
MVP
<span class="term-badge">방법론</span>
<span class="term-mention-icon">💬</span>
</div>
<div class="term-definition">
Minimum Viable Product의 약자. 최소한의 기능만 갖춘 제품으로, 시장 반응을 빠르게 확인하기 위해 개발합니다.
</div>
<div class="term-context">개발 일정 논의에서 언급</div>
</div>
<div class="term-item" onclick="showTermDetail('RESTful API')">
<div class="term-name">
RESTful API
<span class="term-badge">기술</span>
</div>
<div class="term-definition">
REST(Representational State Transfer) 아키텍처 스타일을 따르는 웹 서비스 API 설계 방식입니다.
</div>
<div class="term-context">API 설계 리뷰 회의 참조</div>
</div>
<div class="term-item" onclick="showTermDetail('JWT')">
<div class="term-name">
JWT
<span class="term-badge">보안</span>
</div>
<div class="term-definition">
JSON Web Token의 약자. 사용자 인증 정보를 안전하게 전송하기 위한 토큰 기반 인증 방식입니다.
</div>
<div class="term-context">API Gateway 보안 정책에서 채택</div>
</div>
</div>
</div>
@ -979,6 +1117,68 @@
// });
}
// 용어 검색
function searchTerm() {
const searchInput = document.getElementById('termSearchInput');
const searchText = searchInput.value.trim().toLowerCase();
if (!searchText) {
alert('검색할 용어를 입력해주세요');
return;
}
const termItems = document.querySelectorAll('.term-item');
let foundCount = 0;
termItems.forEach(item => {
const termName = item.querySelector('.term-name').textContent.toLowerCase();
const termDefinition = item.querySelector('.term-definition').textContent.toLowerCase();
// 용어명 또는 정의에 검색어가 포함되어 있는지 확인
if (termName.includes(searchText) || termDefinition.includes(searchText)) {
item.style.display = '';
item.classList.add('highlight');
foundCount++;
} else {
item.style.display = 'none';
item.classList.remove('highlight');
}
});
if (foundCount === 0) {
alert('검색 결과가 없습니다');
// 모든 항목 다시 표시
termItems.forEach(item => {
item.style.display = '';
item.classList.remove('highlight');
});
searchInput.value = '';
}
}
// Enter 키로 검색 실행
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('termSearchInput');
if (searchInput) {
searchInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
searchTerm();
}
});
// 입력값이 비워지면 전체 표시
searchInput.addEventListener('input', function() {
if (this.value.trim() === '') {
const termItems = document.querySelectorAll('.term-item');
termItems.forEach(item => {
item.style.display = '';
item.classList.remove('highlight');
});
}
});
}
});
// 녹음 일시정지
function pauseRecording() {
alert('녹음이 일시정지되었습니다');
@ -1022,6 +1222,20 @@
}, 1000);
}
// 관련 회의록 열기
function openRelatedDoc(docId) {
// 새 탭으로 회의록 상세조회 화면 열기
window.open('10-회의록상세조회.html', '_blank');
// 기본 동작(링크 이동) 방지
return false;
}
// 용어 상세 정보 보기
function showTermDetail(termName) {
alert(`"${termName}" 용어에 대한 상세 정보를 표시합니다.`);
}
// 페이지 로드 시 타이머 시작
document.addEventListener('DOMContentLoaded', function() {
updateTimer();

View File

@ -4,7 +4,7 @@
- **작성일**: 2025-10-21
- **최종 수정일**: 2025-10-24
- **작성자**: 이미준 (서비스 기획자)
- **버전**: 1.4.18
- **버전**: 1.4.19
- **설계 철학**: Mobile First Design
---
@ -633,46 +633,25 @@ graph TD
- **접근 경로**: 템플릿선택 → "이 템플릿으로 시작"
- **권한**:
- 회의 시작/종료: 회의 생성자 전용
- 회의록 편집: 모든 참석자
- 참석자 초대: 모든 참석자
#### 주요 기능
1. 음성 녹음 및 실시간 텍스트 변환 (STT)
2. AI 자동 회의록 작성 (구조화)
3. **AI 기반 회의 내용 요약 자동 생성** (섹션별)
4. 실시간 협업 (여러 참석자 동시 편집)
5. 전문용어 자동 감지 및 맥락 기반 설명
6. **참고자료 자동 연결** (이전 회의록, 관련 회의록)
7. 수동 편집 및 섹션별 작성
8. 회의 진행 시간 표시
3. **AI 기반 주요 메모 항목 실시간 제안** (UFR-MEET-030)
4. 전문용어 자동 감지 및 맥락 기반 설명
5. **참고자료 자동 연결** (이전 회의록, 관련 회의록)
6. 참석자 관리 및 초대 기능
7. 회의 진행 시간 표시
#### UI 구성요소
**전체 레이아웃 (2열 구조)**
**전체 레이아웃**
- **헤더** (Fixed, 상단)
- 좌측: "회의 진행 중" 제목 + 경과시간 배지 (빨강, 01:03)
- 우측: "회의 종료" 버튼 (민트 그린 테두리)
- **왼쪽 영역: 회의 내용 작성** (60-70% 너비)
- **텍스트 에디터 툴바**
- B (Bold), I (Italic), U (Underline)
- 색상 선택, 링크 추가
- **편집 영역** (contentEditable, 스크롤 가능)
- 실시간 입력 텍스트: "회의 내용을 작성하거나 AI가 자동으로 작성합니다..."
- 섹션 구조:
```
# 참석자
- 김민준
- 박서연
- 이준호
# 안건
1. 신규 기능 개발 일정 논의
2. 예산 편성 검토
```
- 자동 저장 (30초 간격)
- **오른쪽 영역: 정보 패널** (30-40% 너비, 탭 구조)
- **메인 콘텐츠 영역: 정보 패널** (탭 구조)
- **탭 네비게이션** (4개 탭)
- 참석자 (3명)
- AI 제안
@ -709,30 +688,6 @@ graph TD
- 본문 폰트: 14px, gray-700
- 구조: 헤더 + 본문 텍스트 + 액션 버튼
- **논의사항 제안 카드**
- 헤더: "💬 논의사항 제안" (아이콘 + 제목, 16px bold, 민트 그린)
- 내용: "AI 모델 정확도 향상 방안" (strong 태그, 14px)
- 현재 STT 정확도: 92% (14px 일반, gray-700)
- 목표 정확도: 95% 이상
- 도메인 특화 학습 데이터 확보 필요
- 액션 버튼: "논의사항에 적용" (btn-primary btn-sm) + "수정" (btn-ghost btn-sm)
- **결정사항 제안 카드**
- 헤더: "✅ 결정사항 제안" (아이콘 + 제목, 16px bold, 민트 그린)
- 내용: "개발 일정 최종 확정" (strong 태그, 14px)
- 설계: 2주 (11/1~11/14) (14px 일반, gray-700)
- 개발: 10주 (11/15~1/23)
- 테스트 및 배포: 2주 (1/24~2/6)
- 액션 버튼: "결정사항에 적용" (btn-primary btn-sm) + "수정" (btn-ghost btn-sm)
- **액션아이템 제안 카드**
- 헤더: "📋 액션 아이템(Todo) 자동 추출" (아이콘 + 제목, 16px bold, 민트 그린)
- 추출된 Todo 목록 (14px 일반, gray-700):
1. API 명세서 작성 (이준호, 10/23까지)
2. UI 프로토타입 디자인 (최유진, 10/28까지)
3. AI 모델 성능 테스트 (박서연, 10/25까지)
- 액션 버튼: "3개 Todo 생성" (btn-primary btn-sm) + "수정" (btn-ghost btn-sm)
- **용어 사전 탭**
- 제목: "용어 사전"
- 용어 검색 입력 필드 (placeholder: "용어 검색...")
@ -805,32 +760,22 @@ graph TD
- 카드 클릭 시: **새 탭으로 열기** (target="_blank")
**Mobile (320px~768px)**
- **2열 구조를 1열로 전환**
- 왼쪽 영역: 메인 콘텐츠 (전체 너비)
- 오른쪽 탭 패널: 하단 시트로 표시
- 탭 버튼 클릭 시 바텀시트 슬라이드업
- 오버레이 + 닫기 버튼
**반응형 디자인**
- **Mobile (320px~768px)**
- 헤더: 고정 상단, 좁은 너비
- 메인 콘텐츠: 전체 너비 사용
- 탭 콘텐츠: 세로 스크롤
- 하단 버튼 영역: 고정 하단
**Desktop (768px+)**
- 2열 고정 레이아웃
- 왼쪽: 편집 영역
- 오른쪽: 탭 패널 (고정)
- **Desktop (768px+)**
- 헤더: 고정 상단, 넓은 너비
- 메인 콘텐츠: 최대 너비 제한 없이 반응형
- 탭 콘텐츠: 더 넓은 영역 활용
- 하단 버튼 영역: 고정 하단
#### 인터랙션
1. **텍스트 편집 (왼쪽 영역)**
- **편집 모드**: contentEditable 영역 클릭하여 즉시 편집 시작
- **자동 저장**: 편집 중 30초 간격 자동 저장
- **툴바 사용**:
- B (Bold): 선택된 텍스트를 굵게
- I (Italic): 선택된 텍스트를 이탤릭체로
- U (Underline): 선택된 텍스트에 밑줄
- 색상 선택: 텍스트 강조 색상 변경
- 링크 추가: URL 입력 모달 표시
- **실시간 동기화**: WebSocket 통해 모든 참석자에게 편집 내용 동기화
- **충돌 감지**: 동시 편집 시 충돌 감지 및 병합 옵션 제공
2. **탭 전환 (오른쪽 영역)**
1. **탭 전환**
- **참석자 탭**: 현재 회의 참석자 목록 표시 (4명) 및 참석자 추가 기능
- **참석자 추가 폼** (상단):
- 이메일 입력 필드 (form-control 스타일, placeholder: "이메일 주소 입력")
@ -847,59 +792,28 @@ graph TD
- 상태 표시 없음 (발언 중/온라인 등 제거)
- 참석자 수 동적 업데이트 (초대 성공 시)
- **AI 제안 탭**: AI가 생성한 회의록 개선 제안
- **실시간 주요 메모 추천** (UFR-MEET-030):
- 음성→텍스트 변환 후 AI가 실시간 분석
- **중요한 내용으로 판단된 경우에만** 주요 메모 항목 추천
- **AI 제안 탭**: AI가 생성한 주요 메모 항목 제안 (UFR-MEET-030)
- **실시간 주요 메모 추천**:
- 음성→텍스트 변환 후 AI가 실시간으로 회의 내용 분석
- **중요한 내용으로 판단된 경우에만** 주요 메모 항목 제안
- 논의항목/결정사항 등의 구분 없이 중요 내용을 주요 메모로 제안
- 추천 빈도는 중요 내용 발생에 따라 가변적 (고정 간격 아님)
- 각 추천 항목에 "주요 메모에 추가" 버튼 제공
- 각 제안 항목에 "주요 메모에 추가" 버튼 제공
- 클릭 시 해당 안건의 주요 메모에 자동 저장
- 실시간 업데이트: 새로운 추천은 상단에 표시
- **논의사항 제안 카드**: 제안 내용 + "논의사항에 적용" 버튼
- 제안 구조:
- 제목: "AI 모델 정확도 향상 방안" (strong)
- 내용: 3-5개의 구체적인 논의 포인트 (bullet points)
- "논의사항에 적용" 클릭 시:
1. 논의사항 섹션(section-1)의 content-1 영역에 제안 내용 추가
2. 기존 내용 하단에 `<br>` 태그로 구분하여 추가
3. 제목은 `<strong>` 태그, 내용은 `<p>` 태그로 구조화
4. 성공 토스트 표시: "논의사항에 AI 제안이 추가되었습니다"
5. 자동으로 논의사항 탭(섹션 1)으로 전환 (switchSection(1))
6. 제안 카드 숨김 처리 (display: none)
- "수정" 버튼: 제안을 거부하고 카드 숨김
- **결정사항 제안 카드**: 제안 내용 + "결정사항에 적용" 버튼
- 제안 구조:
- 제목: "개발 일정 최종 확정" (strong)
- 내용: 확정된 결정사항 (bullet points)
- "결정사항에 적용" 클릭 시:
1. 결정사항 섹션(section-2)의 content-2 영역에 제안 내용 추가
2. 기존 내용 하단에 `<br>` 태그로 구분하여 추가
3. 제목은 `<strong>✓` 접두어 포함, 내용은 `<p>` 태그로 구조화
4. 성공 토스트 표시: "결정사항에 AI 제안이 추가되었습니다"
5. 자동으로 결정사항 탭(섹션 2)으로 전환 (switchSection(2))
6. 제안 카드 숨김 처리 (display: none)
- "수정" 버튼: 제안을 거부하고 카드 숨김
- **액션아이템 제안 카드**: 제안 내용 + "3개 Todo 생성" 버튼
- 제안 구조:
- 헤더: "📋 액션 아이템(Todo) 자동 추출"
- 내용: 3개의 Todo 항목 (제목, 담당자, 마감일)
- "3개 Todo 생성" 클릭 시:
1. 액션아이템 섹션(section-3)의 content-3 영역에 Todo 항목 추가
2. **중복 체크**: 기존 Todo 목록에서 동일한 제목이 있는지 확인
3. 중복되지 않은 Todo만 추가 (Set 자료구조 활용)
4. Todo HTML 구조: checkbox + 제목 + 담당자/마감일 + 우선순위 배지
5. 성공 토스트 표시: "N개의 액션아이템이 추가되었습니다 (중복 제외)"
6. 중복된 항목이 있으면: "모든 항목이 이미 존재합니다" (info 토스트)
7. 자동으로 액션아이템 탭(섹션 3)으로 전환 (switchSection(3))
8. 제안 카드 숨김 처리 (display: none)
- "수정" 버튼: 제안을 거부하고 카드 숨김
- 실시간 업데이트: 새로운 제안은 상단에 표시
- **용어 사전 탭**: 회의에서 언급된 전문용어 설명
- 용어 카드 (민트 그린 배경): 용어명 + 간단한 정의
- **용어 검색 기능**:
- 검색 입력창 (placeholder: "용어 검색...", form-control 스타일)
- 검색 버튼 (btn btn-primary btn-sm)
- Enter 키 지원
- 검색 동작:
1. 용어명과 정의 모두 검색
2. 일치하는 용어만 표시, 나머지는 숨김
3. 검색 결과에 하이라이트 효과 적용
4. 검색 결과 없으면 전체 목록 다시 표시
5. 입력창이 비어있으면 전체 목록 표시
- 용어 카드: 용어명 + 카테고리 배지 + 간단한 정의
- 카드 클릭 → 확장하여 상세 설명 표시
- 상세 설명: 이 회의에서의 의미, 관련 회의록 링크
@ -908,41 +822,42 @@ graph TD
- **녹음 중인 페이지 이탈 방지**: 모든 링크는 새 탭으로 열림
- 관련도 표시: 퍼센트 또는 별점으로 시각화
3. **회의 종료**
2. **회의 종료**
- 헤더의 "회의 종료" 버튼 클릭
- 확인 다이얼로그 표시: "회의를 종료하시겠습니까?"
- 확인 → 회의 종료 처리 및 07-회의종료.html로 이동
4. **실시간 업데이트**
3. **실시간 업데이트**
- STT 음성 인식 결과 실시간 반영 (3-5초 주기)
- 모든 참석자의 편집 내용 실시간 동기화
- 수정 사항 하이라이트 표시 (3초간)
- AI 제안 실시간 업데이트
- 용어 사전 자동 업데이트 (새로운 전문용어 감지 시)
- 관련 회의록 목록 동적 갱신
#### 데이터 요구사항
- **입력**:
- 회의 ID
- 오디오 스트림 (실시간 STT용)
- 사용자 편집 내용 (텍스트 입력)
- 참석자 초대 이메일
- **출력**:
- 실시간 텍스트 변환 결과 (STT)
- 편집된 회의록 내용
- **AI 제안 목록** (회의록 개선 제안)
- **AI 제안 목록** (주요 메모 항목 제안)
- **전문용어 및 설명** (용어 사전)
- **관련 회의록 목록** (32건, 관련도 포함)
- 참석자 목록 및 상태
- 참석자 목록
- **연동**:
- STT 서비스 (UFR-AI-010)
- AI 서비스 (AI 제안 생성, UFR-AI-040)
- RAG 서비스 (관련 회의록 검색)
- AI 서비스 (주요 메모 제안 생성, UFR-AI-040)
- RAG 서비스 (관련 회의록 검색, 전문용어 자동 감지)
- Collaboration 서비스 (실시간 동기화)
#### 에러 처리
- **마이크 권한 거부**: "마이크 권한이 필요합니다" 토스트 + 설정 안내 링크
- **STT 실패**: "음성 인식에 실패했습니다. 수동으로 입력해주세요" 토스트
- **AI 제안 생성 실패**: "AI 제안을 불러올 수 없습니다" 토스트 (편집은 계속 가능)
- **STT 실패**: "음성 인식에 실패했습니다" 토스트 + 재시도 안내
- **AI 제안 생성 실패**: "AI 제안을 불러올 수 없습니다" 토스트
- **용어 사전 로드 실패**: "용어 사전을 불러올 수 없습니다" 메시지 표시
- **관련 자료 검색 실패**: "관련 회의록을 찾을 수 없습니다" 메시지 표시
- **동기화 실패**: "네트워크 연결을 확인해주세요. 내용은 로컬에 저장됩니다" 토스트
- **편집 충돌**: "다른 참석자가 동일한 부분을 수정 중입니다" 다이얼로그 + 병합 옵션
- **참석자 초대 실패**: "초대 링크 전송에 실패했습니다" 토스트 + 재시도 버튼
- **동기화 실패**: "네트워크 연결을 확인해주세요" 토스트
- **회의 종료 실패**: "회의 종료 중 오류가 발생했습니다" 토스트 + 재시도 버튼
---
@ -2138,8 +2053,10 @@ graph TD
| 1.4.14 | 2025-10-24 | 이미준 | 12-회의록목록조회 화면 데이터 아키텍처 문서화<br>- **데이터 아키텍처 섹션 추가**: 데이터/뷰 레이어 분리 구조 설명<br> - 데이터 레이어: common.js → SAMPLE_MINUTES 배열 (30개 샘플)<br> - 뷰 레이어: 12-회의록목록조회.html → renderMeetings(), createMeetingCard() 함수<br> - 렌더링 방식: 동적 렌더링, 초기 10개 표시, "10개 더보기" 버튼으로 추가 로딩<br>- **정렬 옵션 레이블 변경**: "최신순" → "최근수정순", "회의일시순" → "최근회의순"<br>- **페이지네이션 기능 문서화**: 초기 10개 표시, "10개 더보기" 버튼 기능 설명<br>- **샘플 데이터 분포 명시**: 총 30개 (작성중 13개, 확정완료 17개)<br>- **프로토타입 파일 경로 추가**: design/uiux/prototype/12-회의록목록조회.html<br>- **스타일 가이드 버전 동기화**: v1.2.4 |
| 1.4.15 | 2025-10-24 | 이미준 | 06-검증완료 화면 삭제 (유저스토리 v2.1.2 변경사항 반영)<br>- **화면 삭제**: 06-검증완료 화면 전체 삭제<br> - 안건별 검증 기능이 11-회의록수정 화면으로 통합됨<br> - 섹션별 검증 방식에서 안건별 검증 방식으로 변경 (유저스토리 UFR-COLLAB-030 → 안건 기반 구조로 전환)<br>- **유저스토리 매핑 업데이트**:<br> - Collaboration 서비스: UFR-COLLAB-010 ~ UFR-COLLAB-030 → UFR-COLLAB-010 ~ UFR-COLLAB-020로 변경<br> - 프로토타입 화면 목록 테이블에서 06-검증완료 행 제거<br>- **화면 번호 유지**: 다른 화면 번호는 변경하지 않음 (프로토타입 파일명 유지)<br> - 07-회의종료, 09-Todo관리, 10-회의록상세조회, 11-회의록수정, 12-회의록목록조회 번호 유지<br>- **변경 이력**: 과거 버전의 UFR-COLLAB-030 언급은 역사적 맥락으로 유지 |
| 1.4.16 | 2025-10-24 | 이미준 | 사용자 역할 용어 통일 (유저스토리 v2.1.2 반영)<br>- **용어 정의 명확화**: "회의 생성자"와 "회의 참석자" 용어로 통일<br> - 설계 목표: "회의록 작성자" → "회의 참석자"로 수정<br>- **화면별 권한 정보 추가**:<br> - 03-회의예약: 모든 사용자 (예약 생성 시 자동으로 회의 생성자가 됨)<br> - 04-템플릿선택: 회의 생성자 전용<br> - 05-회의진행: 회의 시작/종료는 회의 생성자 전용, 회의록 편집은 모든 참석자<br> - 07-회의종료: 회의 생성자 전용<br> - 09-Todo관리: 모든 회의 참석자 (본인이 담당자인 Todo만 조회/수정 가능)<br> - 10-회의록상세조회: 모든 회의 참석자 (조회 전용)<br> - 11-회의록수정: 검증완료 전(모든 참석자), 검증완료 후(회의 생성자만) - 기존 권한 제어 유지<br> - 12-회의록목록조회: 모든 회의 참석자 (본인이 참석한 회의록만 조회)<br>- **스타일 가이드 동기화**: design/uiux/style-guide.md v1.2.5 (용어 정의 섹션 추가)<br>- **통일성 달성**: 유저스토리, 화면설계서, 스타일 가이드 간 용어 완전 통일 |
| 1.4.17 | 2025-10-24 | 강지수 | 10-회의록상세조회 화면 용어 통일 (섹션 → 안건)<br>- **용어 변경 (요구사항설계검토-report-V1.2.md 반영)**:<br> - 모든 "섹션별" → "안건별"로 용어 통일<br> - 주요 기능, UI 구성요소, 인터랙션, 데이터 요구사항, 에러 처리 섹션 전체 업데이트<br>- **CSS 클래스명 변경 (공통 스타일 + 프로토타입)**:<br> - common.css: `.section``.agenda`, `.section-header``.agenda-header`, `.section-title``.agenda-title`, `.section-content``.agenda-content`<br> - 10-회의록상세조회.html: 모든 section 클래스를 agenda 클래스로 일괄 변경<br>- **HTML 주석 업데이트**: "회의록 섹션" → "회의록 안건", "섹션 내용" → "안건 내용"<br>- **일관성 달성**: 유저스토리 v2.1.2의 안건 기반 구조와 완전히 일치 |
| 1.4.18 | 2025-10-24 | 강지수 | 12-회의록목록조회 화면 생성자 표시 기능 추가 (유저스토리 v2.1.3 반영)<br>- **목록 표시 정보 추가**: 회의 생성자 표시 (👑 아이콘)<br> - 현재 사용자가 회의 생성자인 경우 회의록 카드 헤더에 👑 아이콘 표시<br> - 위치: 상태 배지와 회의 제목 사이<br> - 스타일: font-size 16px, title="생성자" 툴팁 제공<br>- **UI 구성요소 업데이트**: 회의록 목록 섹션 명세 수정<br> - 좌측 영역에 "생성자 표시" 항목 추가<br> - 검증완료율 표시 조건 명시 (작성중 상태일 때만)<br>- **프로토타입 수정**: design/uiux/prototype/12-회의록목록조회.html<br> - createMeetingCard() 함수: crownEmoji 변수를 creatorBadge로 변경 및 .creator-badge 클래스 적용<br> - common.css: .creator-badge 스타일 추가 (inline-flex, 16px, margin-left 4px, cursor help)<br>- **스타일 가이드 업데이트**: design/uiux/style-guide.md v1.2.6<br> - 생성자 배지 섹션 추가 (배지 시스템 내 우선순위 배지 다음)<br> - 사용 예시 및 사용 위치 명시 (12-회의록목록조회, 02-대시보드, 10-회의록상세조회) |
|| 1.4.17 | 2025-10-24 | 강지수 | 07-회의종료 화면 STT 한계 반영 (유저스토리 v2.1.2)<br>- **STT 화자 식별 불가 반영**: STT는 화자를 식별할 수 없으므로 화자 관련 기능 제거<br> - 발언 통계 섹션 삭제<br> - 안건별 "발언자별 의견" 섹션 삭제<br>- **통계 영역 디자인 개선**: 정보성 디자인으로 명확화<br> - 배경색: var(--white) → var(--gray-50)<br> - 숫자 색상: var(--primary) → var(--gray-900)<br> - 라벨 색상: var(--gray-500) → var(--gray-600)<br> - 정보 표시 전용으로 시각적 구분 명확화<br>- **안건 섹션 구분 개선**:<br> - 안건 간 하단 보더 추가 (1px solid var(--gray-200))<br> - 섹션 제목에 primary 색상 세로 바 추가 (::before pseudo-element)<br> - 콘텐츠 영역 좌측 패딩 추가로 계층 구조 명확화<br>- **연관 문서 업데이트**:<br> - 유저스토리 UFR-MEET-040: "발언 횟수 (화자별)" 항목 제거<br> - UI/UX 설계서 07-회의종료: 발언 통계 및 발언자별 의견 항목 제거 |
| 1.4.18 | 2025-10-24 | 강지수 | 05-회의진행 실시간 주요 메모 추천 기능 명확화 (유저스토리 v2.1.1)<br>- **AI 제안 탭 기능 상세화**: 실시간 주요 메모 추천 기능 명시 추가<br> - UFR-MEET-030: 실시간 AI 주요 메모 추천<br> - 음성→텍스트 변환 후 AI가 실시간 분석<br> - **중요한 내용으로 판단된 경우에만** 주요 메모 항목 추천<br> - 추천 빈도는 중요 내용 발생에 따라 가변적 (3-5초 고정 간격 아님)<br> - 각 추천 항목에 "주요 메모에 추가" 버튼 제공<br> - 실시간 업데이트: 새로운 추천은 상단에 표시<br>- **프로토타입 확인**: 05-회의진행.html의 AI 제안 탭이 실시간 주요 메모 추천 기능을 포함하고 있음을 확인<br>- **참조**: design/uiux/요구사항설계검토-report-V1.2.md (실시간 주요 메모 추천 명시 부족 개선) |
| 1.4.19 | 2025-10-24 | 강지수 | 05-회의진행 화면 설계서 프로토타입 기준 전면 수정<br>- **레이아웃 구조 변경**: "2열 구조" 표현 제거, "메인 콘텐츠 영역: 정보 패널 (탭 구조)"로 단순화<br> - 텍스트 편집 영역 관련 내용 모두 제거 (왼쪽 영역, 에디터 툴바, contentEditable 등)<br> - 현재 프로토타입은 헤더 + 탭 콘텐츠 구조만 보유<br>- **반응형 디자인 명확화**: Mobile/Desktop 모두 동일한 구조에 너비만 반응형<br> - "2열 구조를 1열로 전환", "바텀시트" 표현 제거<br> - Mobile: 전체 너비 사용, Desktop: 최대 너비 제한 없이 반응형<br>- **AI 제안 탭 기능 명확화**: 논의항목/결정사항 구분 제거<br> - "논의항목/결정사항 등의 구분 없이 중요 내용을 주요 메모로 제안" 명시<br> - AI는 단순히 중요한 내용을 주요 메모 항목으로 제안하는 역할만 수행<br>- **용어 사전 검색 기능 추가**: 검색 입력창 + 검색 버튼<br> - Enter 키 지원, 용어명과 정의 모두 검색<br> - 검색 동작 상세 설명: 일치하는 용어만 표시, 하이라이트 효과, 결과 없으면 전체 목록 표시<br>- **인터랙션 섹션 정리**: 텍스트 편집, 툴바 사용, 충돌 감지 등 편집 관련 내용 모두 제거<br> - 탭 전환, 회의 종료, 실시간 업데이트만 유지<br> - 실시간 업데이트 항목을 현재 화면에 맞게 수정 (AI 제안, 용어 사전, 관련 회의록)<br>- **데이터 요구사항 업데이트**: 사용자 편집 내용 제거, 참석자 초대 이메일 추가<br> - AI 제안을 "주요 메모 항목 제안"으로 명확히 표현<br>- **에러 처리 업데이트**: 편집 충돌 에러 제거, 용어 사전 로드 실패/참석자 초대 실패 추가<br>- **주요 기능 목록 정리**: 실시간 협업/수동 편집 제거, AI 주요 메모 제안/참석자 관리 추가<br>- **권한 항목 수정**: "회의록 편집: 모든 참석자" → "참석자 초대: 모든 참석자"<br>- **프로토타입 기준 반영**: 05-회의진행.html 실제 구현 상태 100% 반영 |
---
@ -2155,5 +2072,3 @@ graph TD
- 타이포그래피
- 컴포넌트 라이브러리
- 아이콘 세트
| 1.4.17 | 2025-10-24 | 강지수 | 07-회의종료 화면 STT 한계 반영 (유저스토리 v2.1.2)<br>- **STT 화자 식별 불가 반영**: STT는 화자를 식별할 수 없으므로 화자 관련 기능 제거<br> - 발언 통계 섹션 삭제<br> - 안건별 "발언자별 의견" 섹션 삭제<br>- **통계 영역 디자인 개선**: 정보성 디자인으로 명확화<br> - 배경색: var(--white) → var(--gray-50)<br> - 숫자 색상: var(--primary) → var(--gray-900)<br> - 라벨 색상: var(--gray-500) → var(--gray-600)<br> - 정보 표시 전용으로 시각적 구분 명확화<br>- **안건 섹션 구분 개선**:<br> - 안건 간 하단 보더 추가 (1px solid var(--gray-200))<br> - 섹션 제목에 primary 색상 세로 바 추가 (::before pseudo-element)<br> - 콘텐츠 영역 좌측 패딩 추가로 계층 구조 명확화<br>- **연관 문서 업데이트**:<br> - 유저스토리 UFR-MEET-040: "발언 횟수 (화자별)" 항목 제거<br> - UI/UX 설계서 07-회의종료: 발언 통계 및 발언자별 의견 항목 제거 |
| 1.4.18 | 2025-10-24 | 강지수 | 05-회의진행 실시간 주요 메모 추천 기능 명확화 (유저스토리 v2.1.1)<br>- **AI 제안 탭 기능 상세화**: 실시간 주요 메모 추천 기능 명시 추가<br> - UFR-MEET-030: 실시간 AI 주요 메모 추천<br> - 음성→텍스트 변환 후 AI가 실시간 분석<br> - **중요한 내용으로 판단된 경우에만** 주요 메모 항목 추천<br> - 추천 빈도는 중요 내용 발생에 따라 가변적 (3-5초 고정 간격 아님)<br> - 각 추천 항목에 "주요 메모에 추가" 버튼 제공<br> - 실시간 업데이트: 새로운 추천은 상단에 표시<br>- **프로토타입 확인**: 05-회의진행.html의 AI 제안 탭이 실시간 주요 메모 추천 기능을 포함하고 있음을 확인<br>- **참조**: design/uiux/요구사항설계검토-report-V1.2.md (실시간 주요 메모 추천 명시 부족 개선) |