Merge branch 'main' into feature/stt-ai - 로그 파일 충돌 해결

This commit is contained in:
Minseo-Jo
2025-10-28 09:33:19 +09:00
295 changed files with 26295 additions and 26368 deletions
+41 -187
View File
@@ -150,6 +150,7 @@
}
/* 회의 카드 */
/* 최근 회의는 최대 3개만 표시하므로 3열로 제한 */
.meeting-grid {
display: grid;
gap: var(--space-md);
@@ -168,12 +169,6 @@
}
}
@media (min-width: 1440px) {
.meeting-grid {
grid-template-columns: repeat(4, 1fr);
}
}
.meeting-card {
background: var(--white);
border-radius: var(--radius-lg);
@@ -238,7 +233,7 @@
/* Todo 카드 스타일은 common.css에서 공통 관리 */
/* 통계 영역 - 정보 표시용 (클릭 불가) */
/* 통계 영역 - 정보 표시용 (클릭 불가) - UFR-USER-020: 2개 항목 표시 */
.stats-overview {
display: grid;
grid-template-columns: repeat(2, 1fr);
@@ -513,15 +508,12 @@
<div class="sidebar-logo-text">회의록 서비스</div>
</a>
<!-- MVP 스코프 축소: Todo 관리 메뉴 제거 -->
<nav class="sidebar-nav">
<a href="12-회의록목록조회.html" class="sidebar-nav-item">
<span class="sidebar-nav-icon"><img src="img/edit.png" width="32"></span>
<span>회의록</span>
</a>
<a href="09-Todo관리.html" class="sidebar-nav-item">
<span class="sidebar-nav-icon"><img src="img/list.png" width="32"></span>
<span>Todo 관리</span>
</a>
</nav>
<!-- 사용자 정보 영역 (Desktop) -->
@@ -559,7 +551,7 @@
<!-- 메인 콘텐츠 -->
<main class="main-content">
<!-- 통계 개요 -->
<!-- 통계 개요 (UFR-USER-020) -->
<div class="stats-overview">
<div class="stat-box stat-meeting">
<div class="stat-icon">📅</div>
@@ -567,9 +559,9 @@
<div class="stat-text">예정된 회의</div>
</div>
<div class="stat-box stat-todo">
<div class="stat-icon"></div>
<div class="stat-number" id="stat-todos">0</div>
<div class="stat-text">나의 Todo</div>
<div class="stat-icon">📝</div>
<div class="stat-number" id="stat-drafts">0</div>
<div class="stat-text">작성중 회의록</div>
</div>
</div>
@@ -583,16 +575,7 @@
</div>
</section>
<!-- 나의 Todo -->
<section>
<div class="section-header">
<h2 class="section-title">나의 Todo</h2>
<a href="09-Todo관리.html" class="section-link">전체 보기 →</a>
</div>
<div class="todo-list" id="my-todos">
<!-- 동적 생성 -->
</div>
</section>
<!-- MVP 스코프 축소: "나의 Todo" 섹션 제거 -->
<!-- 나의 회의록 -->
<section>
@@ -607,7 +590,7 @@
</main>
<!-- 하단 네비게이션 (모바일) -->
<!-- 하단 네비게이션 (모바일) - MVP 스코프 축소: Todo 관리 메뉴 제거 -->
<nav class="bottom-nav">
<a href="02-대시보드.html" class="nav-item active">
<img src="img/home.png" alt="홈" style="width: 45px;">
@@ -615,9 +598,6 @@
<a href="12-회의록목록조회.html" class="nav-item">
<img src="img/edit.png" alt="회의록" style="width: 45px;">
</a>
<a href="09-Todo관리.html" class="nav-item">
<img src="img/list.png" alt="Todo" style="width: 45px;">
</a>
</nav>
<!-- FAB 오버레이 -->
@@ -704,8 +684,17 @@
const statusInfo = getMeetingStatusInfo(meeting);
const isCreator = meeting.participants.some(p => p.id === currentUser.id && p.role === 'creator');
// 버튼 표시 규칙
// - ongoing: 참여하기 버튼 표시
// - scheduled: 버튼 없음 (카드 클릭으로 수정 화면 이동)
// - draft/complete: 버튼 없음 (카드 클릭으로 상세조회 이동)
let actionButton = '';
if (meeting.status === 'ongoing') {
actionButton = `<button class="btn btn-primary btn-sm" onclick="navigateTo('05-회의진행.html'); event.stopPropagation();">참여하기</button>`;
}
return `
<div class="meeting-card ${meeting.status === 'ongoing' ? 'ongoing' : ''}" data-id="${meeting.id}">
<div class="meeting-card ${meeting.status === 'ongoing' ? 'ongoing' : ''}" data-id="${meeting.id}" data-status="${meeting.status}">
<div class="meeting-card-header">
${createBadge(statusInfo.badgeText, statusInfo.badgeType)}
<h3 class="meeting-card-title">${meeting.title}${isCreator ? ' <span style="font-size: 16px;" title="생성자">👑</span>' : ''}</h3>
@@ -714,14 +703,7 @@
<div class="meeting-card-meta-item">📅 ${formatDate(meeting.date)} ${formatTime(meeting.time)} 👥 ${meeting.participants.length}명</div>
<div class="meeting-card-meta-item">📍 ${meeting.location}</div>
</div>
<div class="meeting-card-actions">
${meeting.status === 'ongoing'
? `<button class="btn btn-primary btn-sm" onclick="navigateTo('05-회의진행.html'); event.stopPropagation();">참여하기</button>`
: meeting.status === 'scheduled' && isCreator
? `<button class="btn btn-secondary btn-sm" onclick="navigateTo('03-회의예약.html'); event.stopPropagation();">수정</button>`
: `<button class="btn btn-ghost btn-sm" onclick="navigateTo('10-회의록상세조회.html'); event.stopPropagation();">보기</button>`
}
</div>
${actionButton ? `<div class="meeting-card-actions">${actionButton}</div>` : ''}
</div>
`;
}).join('');
@@ -731,12 +713,14 @@
card.addEventListener('click', (e) => {
if (e.target.tagName !== 'BUTTON') {
const meetingId = card.dataset.id;
const meeting = SAMPLE_MEETINGS.find(m => m.id === meetingId);
if (meeting.status === 'ongoing') {
const meetingStatus = card.dataset.status;
// 상태에 따른 이동 처리
if (meetingStatus === 'ongoing') {
navigateTo('05-회의진행.html');
} else if (meeting.status === 'completed') {
} else if (meetingStatus === 'draft' || meetingStatus === 'complete' || meetingStatus === 'completed') {
navigateTo('10-회의록상세조회.html');
} else {
} else if (meetingStatus === 'scheduled') {
navigateTo('03-회의예약.html');
}
}
@@ -745,104 +729,9 @@
}
/**
* 내 Todo 렌더링 (09-Todo관리.html과 동일한 정렬 기준)
* MVP 스코프 축소: renderMyTodos() 함수 제거됨
* 대시보드에서 Todo 위젯이 제거되어 더 이상 사용되지 않음
*/
function renderMyTodos() {
const container = $('#my-todos');
const myTodos = SAMPLE_TODOS
.filter(todo => todo.assignee.id === currentUser.id)
.sort((a, b) => {
// 09-Todo관리.html과 동일한 정렬: 완료되지 않은 것 우선, 마감일 순
if (a.status === 'completed' && b.status !== 'completed') return 1;
if (a.status !== 'completed' && b.status === 'completed') return -1;
return new Date(a.dueDate) - new Date(b.dueDate);
})
.slice(0, 3); // 상위 3개만 표시
if (myTodos.length === 0) {
container.innerHTML = '<div class="empty-state"><div class="empty-icon">✅</div><p>할당된 Todo가 없습니다</p></div>';
return;
}
container.innerHTML = myTodos.map(todo => {
const dday = calculateDday(todo.dueDate);
const isCompleted = todo.status === 'completed';
const isOverdue = dday < 0 && !isCompleted;
// D-day 배지
let ddayBadge = '';
let ddayClass = '';
if (isCompleted) {
ddayBadge = '완료';
ddayClass = 'badge-complete';
} else if (isOverdue) {
ddayBadge = `D+${Math.abs(dday)} (지연)`;
ddayClass = 'badge-overdue';
} else if (dday === 0) {
ddayBadge = 'D-DAY';
ddayClass = 'badge-warning';
} else if (dday <= 3) {
ddayBadge = `D-${dday}`;
ddayClass = 'badge-warning';
} else if (dday <= 7) {
ddayBadge = `D-${dday}`;
ddayClass = 'badge-primary';
} else {
ddayBadge = `D-${dday}`;
ddayClass = 'badge-secondary';
}
// 우선순위 배지
const priorityText = todo.priority === 'high' ? '높음' : todo.priority === 'medium' ? '보통' : '낮음';
const priorityClass = `badge-${todo.priority}`;
return `
<div class="todo-card ${isCompleted ? 'completed' : ''}" data-todo-id="${todo.id}" data-meeting-id="${todo.meetingId}">
<div class="todo-top">
<div class="todo-checkbox-wrapper">
<input type="checkbox" class="todo-checkbox" id="check-${todo.id}"
${isCompleted ? 'checked' : ''}
onchange="toggleTodoComplete('${todo.id}', this.checked)">
</div>
<div class="todo-content-wrapper">
<div class="todo-badges">
<span class="badge ${ddayClass}">${ddayBadge}</span>
<span class="badge ${priorityClass}">${priorityText}</span>
</div>
<div class="todo-title">${todo.title}</div>
<div class="todo-meta-row">
<a class="todo-meeting-link" onclick="navigateTo('10-회의록상세조회.html'); event.stopPropagation();">
🔗 ${todo.meetingTitle}
</a>
<span>${formatDate(todo.dueDate)}</span>
</div>
</div>
${!isCompleted ? `
<div class="todo-actions">
<button class="icon-btn" onclick="editTodo('${todo.id}')" title="편집">✏️</button>
</div>
` : ''}
</div>
</div>
`;
}).join('');
// Todo 카드 클릭 시 해당 회의록 상세로 이동 (체크박스와 버튼 제외)
$$('.todo-card').forEach(card => {
card.addEventListener('click', (e) => {
// 체크박스나 버튼 클릭은 무시
if (e.target.classList.contains('todo-checkbox') ||
e.target.classList.contains('icon-btn') ||
e.target.closest('.icon-btn')) {
return;
}
const meetingId = card.dataset.meetingId;
const todoId = card.dataset.todoId;
navigateTo(`10-회의록상세조회.html?meetingId=${meetingId}&todoId=${todoId}`);
});
});
}
/**
* 나의 회의록 렌더링 (참여자 또는 생성자로 등록된 회의록, 최신순 정렬)
@@ -887,31 +776,33 @@
}
/**
* 통계 업데이트
* 통계 업데이트 (UFR-USER-020)
*/
function updateStats() {
// 예정된 회의 개수 (예정 + 진행중)
const scheduled = SAMPLE_MEETINGS.filter(m => m.status === 'scheduled' || m.status === 'ongoing').length;
// 나의 Todo 개수 (전체)
const myTodos = SAMPLE_TODOS.filter(t => t.assignee.id === currentUser.id).length;
// 작성중 회의록 개수 (내가 참석한 회의 중 '작성중' 상태)
const drafts = SAMPLE_MINUTES.filter(m =>
m.status === 'draft' &&
m.participants.some(p => p.id === currentUser.id)
).length;
$('#stat-scheduled').textContent = scheduled;
$('#stat-todos').textContent = myTodos;
$('#stat-drafts').textContent = drafts;
}
/**
* 초기화
* 초기화 - MVP 스코프 축소: renderMyTodos() 제거
*/
function init() {
renderSidebarUser();
renderHeader();
updateStats();
renderRecentMeetings();
renderMyTodos();
renderMyMinutes();
console.log('대시보드 초기화 완료');
console.log('대시보드 초기화 완료 (MVP 스코프 축소)');
}
/**
@@ -1002,48 +893,11 @@
}
/**
* Todo 완료 토글
* @param {string} todoId - Todo ID
* @param {boolean} isChecked - 체크박스 상태
* MVP 스코프 축소: Todo 관련 함수 제거됨
* - toggleTodoComplete()
* - editTodo()
* 대시보드에서 Todo 위젯이 제거되어 더 이상 사용되지 않음
*/
function toggleTodoComplete(todoId, isChecked) {
if (isChecked) {
// 완료 처리
if (confirm('완료 처리하시겠습니까?')) {
const todo = SAMPLE_TODOS.find(t => t.id === todoId);
if (todo) {
todo.status = 'completed';
showToast('Todo가 완료되었습니다', 'success');
updateStats();
renderMyTodos();
}
} else {
event.target.checked = false;
}
} else {
// 미완료로 되돌리기
if (confirm('미완료로 변경하시겠습니까?')) {
const todo = SAMPLE_TODOS.find(t => t.id === todoId);
if (todo) {
todo.status = 'incomplete';
showToast('미완료로 변경되었습니다', 'info');
updateStats();
renderMyTodos();
}
} else {
event.target.checked = true;
}
}
}
/**
* Todo 편집 (간이 버전 - 09-Todo관리.html로 이동)
* @param {string} todoId - Todo ID
*/
function editTodo(todoId) {
// Todo 관리 화면으로 이동하여 편집
navigateTo(`09-Todo관리.html?todoId=${todoId}`);
}
init();
</script>
+50 -36
View File
@@ -60,7 +60,7 @@
}
.meeting-title {
font-size: var(--font-large);
font-size: var(--font-h2);
font-weight: var(--font-weight-bold);
color: var(--gray-800);
margin: 0;
@@ -100,7 +100,7 @@
}
.recording-time {
font-size: var(--font-small);
font-size: var(--font-body);
font-weight: var(--font-weight-medium);
}
@@ -173,9 +173,9 @@
.info-row {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--space-sm);
padding: var(--space-xs) 0;
align-items: flex-start;
gap: 0;
padding: var(--space-sm) 0;
border-bottom: 1px solid var(--gray-300);
}
@@ -186,14 +186,28 @@
.info-label {
font-weight: var(--font-weight-medium);
color: var(--gray-600);
font-size: var(--font-caption);
min-width: 60px;
font-size: var(--font-small);
width: 70px;
min-width: 70px;
max-width: 70px;
flex-shrink: 0;
padding-right: var(--space-sm);
border-right: 1px solid var(--gray-300);
margin-right: var(--space-sm);
}
/* 데스크톱에서 라벨 폭 확장 */
@media (min-width: 768px) {
.info-label {
width: 100px;
min-width: 100px;
max-width: 100px;
}
}
.info-value {
color: var(--gray-800);
font-size: var(--font-small);
font-size: var(--font-body);
line-height: 1.5;
flex: 1;
}
@@ -229,7 +243,7 @@
background: transparent;
border: none;
cursor: pointer;
font-size: var(--font-small);
font-size: var(--font-body);
font-weight: var(--font-weight-medium);
color: var(--gray-600);
transition: all var(--transition-fast);
@@ -289,13 +303,13 @@
}
.participant-section-title {
font-size: var(--font-small);
font-size: var(--font-body);
font-weight: var(--font-weight-bold);
margin: 0;
}
.participant-count {
font-size: var(--font-caption);
font-size: var(--font-small);
color: var(--gray-600);
}
@@ -307,13 +321,13 @@
.invite-input {
flex: 1;
font-size: var(--font-small);
font-size: var(--font-body);
padding: var(--space-sm);
}
.invite-btn {
padding: var(--space-sm) var(--space-md);
font-size: var(--font-small);
font-size: var(--font-body);
white-space: nowrap;
flex-shrink: 0;
}
@@ -337,13 +351,13 @@
}
.participant-name {
font-size: var(--font-small);
font-size: var(--font-body);
font-weight: var(--font-weight-medium);
color: var(--gray-800);
}
.participant-email {
font-size: var(--font-caption);
font-size: var(--font-small);
color: var(--gray-500);
margin-top: 2px;
overflow: hidden;
@@ -351,7 +365,7 @@
white-space: nowrap;
}
/* AI 제안 탭 */
/* AI 기반 메모 탭 - MVP 스코프 축소 v1.5.1 */
.memo-input-section {
background: var(--gray-50);
border-radius: var(--radius-md);
@@ -360,7 +374,7 @@
}
.memo-input-label {
font-size: var(--font-small);
font-size: var(--font-body);
font-weight: var(--font-weight-medium);
color: var(--gray-700);
margin-bottom: var(--space-xs);
@@ -373,7 +387,7 @@
padding: var(--space-sm);
border: 1px solid var(--gray-300);
border-radius: var(--radius-md);
font-size: var(--font-small);
font-size: var(--font-body);
font-family: inherit;
resize: vertical;
line-height: 1.5;
@@ -388,17 +402,17 @@
width: 100%;
margin-top: var(--space-xs);
padding: var(--space-sm);
font-size: var(--font-small);
font-size: var(--font-body);
}
.ai-suggestion-list-title {
font-size: var(--font-body);
font-size: var(--font-h3);
font-weight: var(--font-weight-bold);
color: var(--gray-900);
margin-bottom: var(--space-sm);
}
/* AI 제안 카드 */
/* AI 주요 내용 카드 */
.ai-suggestion-card {
background: #FAFAFA;
border: 1px dashed #D0D0D0;
@@ -416,7 +430,7 @@
}
.ai-suggestion-time {
font-size: var(--font-caption);
font-size: var(--font-small);
color: var(--gray-500);
font-weight: var(--font-weight-regular);
}
@@ -446,7 +460,7 @@
}
.ai-suggestion-text {
font-size: var(--font-small);
font-size: var(--font-body);
color: var(--gray-700);
line-height: 1.5;
}
@@ -460,13 +474,13 @@
.term-search-input {
flex: 1;
font-size: var(--font-small);
font-size: var(--font-body);
padding: var(--space-sm);
}
.term-search-btn {
padding: var(--space-sm) var(--space-md);
font-size: var(--font-small);
font-size: var(--font-body);
white-space: nowrap;
flex-shrink: 0;
}
@@ -493,7 +507,7 @@
}
.term-name {
font-size: var(--font-small);
font-size: var(--font-body);
font-weight: var(--font-weight-bold);
color: var(--primary);
display: flex;
@@ -512,14 +526,14 @@
}
.term-definition {
font-size: var(--font-small);
font-size: var(--font-body);
color: var(--gray-700);
line-height: 1.5;
margin-bottom: var(--space-xs);
}
.term-context {
font-size: 11px;
font-size: var(--font-small);
color: var(--gray-500);
padding-top: var(--space-xs);
border-top: 1px dashed #D0D0D0;
@@ -546,7 +560,7 @@
}
.related-doc-title {
font-size: var(--font-small);
font-size: var(--font-body);
font-weight: var(--font-weight-bold);
color: var(--primary);
margin-bottom: var(--space-xs);
@@ -555,7 +569,7 @@
.related-doc-meta {
display: flex;
gap: var(--space-xs);
font-size: var(--font-caption);
font-size: var(--font-small);
color: var(--gray-600);
margin-bottom: var(--space-xs);
}
@@ -566,7 +580,7 @@
}
.related-doc-text {
font-size: var(--font-small);
font-size: var(--font-body);
color: var(--gray-700);
line-height: 1.5;
}
@@ -668,7 +682,7 @@
참석자
</button>
<button class="tab-button" onclick="switchTab('ai-suggestions')">
AI 제안
AI 메모
</button>
<button class="tab-button" onclick="switchTab('terms')">
용어사전
@@ -732,7 +746,7 @@
</div>
</div>
<!-- AI 제안 탭 -->
<!-- AI 기반 메모 탭 (MVP 스코프 축소 v1.5.1) -->
<div class="tab-content" id="tab-ai-suggestions">
<div class="memo-input-section">
<label class="memo-input-label">📝 회의 메모</label>
@@ -1053,7 +1067,7 @@
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
// AI 제안을 메모에 추가
// AI가 감지한 주요 내용을 메모에 추가 (MVP 스코프 축소 v1.5.1)
function addToMemo(suggestionText, cardElement) {
const memoTextarea = document.getElementById('meetingMemo');
const currentMemo = memoTextarea.value;
@@ -1062,7 +1076,7 @@
const recordingTime = document.getElementById('recordingTime').textContent;
const timePrefix = '[' + recordingTime.substring(0, 5) + '] '; // HH:MM만 추출
// 시간 정보 + 제안 내용
// 시간 정보 + 주요 내용
const memoWithTime = timePrefix + suggestionText;
if (currentMemo) {
@@ -1071,7 +1085,7 @@
memoTextarea.value = memoWithTime;
}
// AI 제안 카드 삭제
// AI 주요 내용 카드 삭제 (선택 후 제거)
if (cardElement) {
cardElement.remove();
}
File diff suppressed because it is too large Load Diff
@@ -107,11 +107,41 @@
margin-bottom: var(--space-md);
}
/* 회의 제목 컨테이너 */
.meeting-title-container {
display: flex;
flex-direction: column;
gap: var(--space-sm);
margin-bottom: var(--space-md);
}
/* 배지 영역 (배지 + 크라운) */
.meeting-badges {
display: flex;
align-items: center;
gap: var(--space-xs);
}
/* 회의 제목 */
.meeting-basic-info h2 {
font-size: var(--font-h2);
font-weight: var(--font-weight-bold);
color: var(--gray-900);
margin-bottom: var(--space-sm);
margin: 0;
line-height: 1.3;
}
/* 데스크톱: 기존 가로 배치 유지 */
@media (min-width: 768px) {
.meeting-title-container {
flex-direction: row;
align-items: center;
gap: var(--space-sm);
}
.meeting-basic-info h2 {
margin: 0;
}
}
.info-row {
@@ -165,23 +195,6 @@
.participant {
width: calc(50% - var(--space-md) / 2);
}
/* 통계 그리드: 모바일에서도 4열 유지, gap만 축소 */
.stats-grid {
gap: var(--space-xs);
}
.stat-item {
padding: var(--space-sm);
}
.stat-value {
font-size: var(--font-base);
}
.stat-label {
font-size: var(--font-xs);
}
}
/* 회의록 섹션 */
@@ -279,22 +292,6 @@
margin-bottom: var(--space-md);
}
.reference-item {
background: var(--white);
border-radius: var(--radius-md);
padding: var(--space-sm);
margin-bottom: var(--space-sm);
cursor: pointer;
transition: all var(--transition-fast);
}
.reference-item:hover {
box-shadow: var(--shadow-sm);
}
.reference-item:last-child {
margin-bottom: 0;
}
.reference-header {
display: flex;
@@ -310,7 +307,7 @@
.reference-title {
flex: 1;
font-size: var(--font-small);
font-size: var(--font-body);
font-weight: var(--font-weight-medium);
color: var(--gray-900);
}
@@ -338,7 +335,7 @@
}
.reference-meta {
font-size: var(--font-caption);
font-size: var(--font-small);
color: var(--gray-500);
margin-bottom: var(--space-xs);
}
@@ -405,10 +402,11 @@
color: var(--white);
}
/* 통계 그리드 - 모바일 기본 (2x2) */
.stats-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--space-md);
grid-template-columns: repeat(2, 1fr);
gap: var(--space-sm);
margin-top: var(--space-md);
}
@@ -431,6 +429,14 @@
color: var(--gray-500);
}
/* 데스크톱: 1x4 그리드 */
@media (min-width: 768px) {
.stats-grid {
grid-template-columns: repeat(4, 1fr);
gap: var(--space-md);
}
}
/* 결정사항 카드 */
.decision-card {
background: var(--white);
@@ -462,7 +468,7 @@
border-top: 1px solid var(--gray-300);
}
/* Todo 진행상황 */
/* Todo 리스트 */
.todo-filters {
display: flex;
gap: var(--space-sm);
@@ -523,7 +529,64 @@
margin-bottom: var(--space-xs);
}
/* Todo 진행상황 - 09-Todo관리 스타일 적용 */
/* Todo 리스트 - 단순 조회 스타일 */
.simple-todo-list {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.simple-todo-item {
position: relative;
padding: var(--space-md);
background: var(--white);
border-radius: var(--radius-md);
border: 1px solid var(--gray-300);
}
.simple-todo-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: var(--space-sm);
margin-bottom: var(--space-xs);
}
.simple-todo-title {
flex: 1;
font-size: var(--font-body);
font-weight: var(--font-weight-medium);
color: var(--gray-900);
min-width: 0;
}
.simple-todo-edit-btn {
background: transparent;
border: none;
font-size: 20px;
cursor: pointer;
padding: 4px;
color: var(--gray-500);
transition: all var(--transition-fast);
flex-shrink: 0;
border-radius: 4px;
}
.simple-todo-edit-btn:hover {
color: var(--primary);
background: var(--primary-light);
transform: scale(1.1);
}
.simple-todo-meta {
font-size: var(--font-small);
color: var(--gray-600);
display: flex;
gap: var(--space-md);
align-items: center;
}
/* Todo 리스트 - 09-Todo관리 스타일 적용 */
.todo-filters {
display: flex;
gap: var(--space-sm);
@@ -688,6 +751,24 @@
display: block;
}
/* 대시보드 탭의 관련회의록 카드 스타일 강화 */
.card .reference-item {
border: 1px solid var(--gray-200) !important;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08) !important;
margin-bottom: var(--space-sm) !important;
}
.card .reference-item:hover {
border-color: var(--primary) !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12) !important;
transform: translateY(-1px) !important;
}
.card .reference-item:active {
transform: translateY(0) !important;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08) !important;
}
/* 모바일 화면에서 관련회의록 왼쪽 정렬 */
@media (max-width: 600px) {
.reference-item {
@@ -738,10 +819,14 @@
<!-- 기본 정보 카드 -->
<div class="info-card">
<div class="meeting-basic-info">
<div id="meeting-title-container" style="display: flex; align-items: center; gap: var(--space-sm); margin-bottom: var(--space-sm);">
<span class="badge badge-complete">확정완료</span>
<!-- 생성자일 경우 👑 아이콘이 JavaScript로 추가됨 -->
<h2 style="margin: 0;">2025년 1분기 제품 기획 회의</h2>
<div class="meeting-title-container">
<!-- 배지 + 크라운 영역 -->
<div class="meeting-badges" id="meeting-badges">
<span class="badge badge-complete">확정완료</span>
<!-- 생성자일 경우 👑 아이콘이 JavaScript로 추가됨 -->
</div>
<!-- 회의 제목 -->
<h2>2025년 1분기 제품 기획 회의</h2>
</div>
<div class="info-row">
<span class="info-icon">📅</span>
@@ -757,7 +842,7 @@
<div class="participant">
<div class="avatar avatar-green"></div>
<span class="participant-name">김민준</span>
<span class="role-badge">성자</span>
<span class="role-badge">성자</span>
</div>
<div class="participant">
<div class="avatar avatar-blue"></div>
@@ -1042,148 +1127,70 @@
</div>
</div>
<!-- Todo 진행상황 -->
<!-- Todo 단순 조회 (MVP 스코프 축소 v1.5.1) -->
<div class="card mb-lg">
<h3 class="card-title">📋 Todo 진행상황</h3>
<!-- 전체 진행률 -->
<div style="margin-bottom: var(--space-lg);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-xs);">
<span style="font-size: var(--font-body); font-weight: var(--font-weight-medium); color: var(--gray-900);">전체 진행률</span>
<span style="font-size: var(--font-body); font-weight: var(--font-weight-bold); color: var(--primary);">40%</span>
</div>
<div style="width: 100%; height: 8px; background: var(--gray-200); border: 1px solid var(--gray-300); border-radius: 4px; overflow: hidden;">
<div style="width: 40%; height: 100%; background: var(--primary); transition: width 0.3s ease;"></div>
</div>
<div style="font-size: var(--font-caption); color: var(--gray-600); margin-top: var(--space-xs);">
2 / 5 완료
</div>
<div class="section-header">
<h3 class="card-title">📋 Todo 리스트</h3>
<button class="btn btn-primary btn-sm" onclick="openModal('addTodoModal')">추가</button>
</div>
<p style="font-size: var(--font-small); color: var(--gray-600); margin-bottom: var(--space-md);">
Todo 항목은 조회만 가능합니다. 제목, 담당자, 마감일 정보만 표시됩니다.
</p>
<div class="todo-filters">
<button class="filter-btn active" data-filter="all" onclick="filterTodos('all')">
전체 (<span id="filterAllCount">5</span>)
</button>
<button class="filter-btn" data-filter="overdue" onclick="filterTodos('overdue')">
지연 (<span id="filterOverdueCount">1</span>)
</button>
<button class="filter-btn" data-filter="urgent" onclick="filterTodos('urgent')">
마감 임박 (<span id="filterUrgentCount">2</span>)
</button>
<button class="filter-btn" data-filter="completed" onclick="filterTodos('completed')">
완료 (<span id="filterCompletedCount">2</span>)
</button>
</div>
<!-- Todo 카드 리스트 -->
<div class="todo-card">
<div class="todo-top">
<div class="todo-checkbox-wrapper">
<input type="checkbox" class="todo-checkbox" id="check-todo-002"
onchange="toggleTodoComplete('todo-002', this.checked)">
<!-- Todo 단순 조회 리스트 (제목 + 담당자 + 마감일 + 수정 버튼) -->
<div class="simple-todo-list">
<div class="simple-todo-item">
<div class="simple-todo-header">
<div class="simple-todo-title">데이터베이스 스키마 설계</div>
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(1)" title="수정">✏️</button>
</div>
<div class="todo-content-wrapper">
<div class="todo-badges">
<span class="badge badge-overdue">D+1 (지연)</span>
<span class="badge badge-high">높음</span>
</div>
<div class="todo-title">데이터베이스 스키마 설계</div>
<div class="todo-meta-row">
<span>담당자: 이준호</span>
<span>2025-10-20 마감</span>
</div>
</div>
<div class="todo-actions">
<button class="icon-btn" onclick="editTodo('todo-002')" title="편집">✏️</button>
<div class="simple-todo-meta">
<span>👤 이준호</span>
<span>📅 2025-10-20</span>
</div>
</div>
</div>
<div class="todo-card">
<div class="todo-top">
<div class="todo-checkbox-wrapper">
<input type="checkbox" class="todo-checkbox" id="check-todo-001"
onchange="toggleTodoComplete('todo-001', this.checked)">
<div class="simple-todo-item">
<div class="simple-todo-header">
<div class="simple-todo-title">API 명세서 작성</div>
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(2)" title="수정">✏️</button>
</div>
<div class="todo-content-wrapper">
<div class="todo-badges">
<span class="badge badge-warning">D-2</span>
<span class="badge badge-high">높음</span>
</div>
<div class="todo-title">API 명세서 작성</div>
<div class="todo-meta-row">
<span>담당자: 이준호</span>
<span>2025-10-23 마감</span>
</div>
</div>
<div class="todo-actions">
<button class="icon-btn" onclick="editTodo('todo-001')" title="편집">✏️</button>
<div class="simple-todo-meta">
<span>👤 이준호</span>
<span>📅 2025-10-23</span>
</div>
</div>
</div>
<div class="todo-card">
<div class="todo-top">
<div class="todo-checkbox-wrapper">
<input type="checkbox" class="todo-checkbox" id="check-todo-005"
onchange="toggleTodoComplete('todo-005', this.checked)">
<div class="simple-todo-item">
<div class="simple-todo-header">
<div class="simple-todo-title">예산 편성안 검토</div>
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(3)" title="수정">✏️</button>
</div>
<div class="todo-content-wrapper">
<div class="todo-badges">
<span class="badge badge-warning">D-1</span>
<span class="badge badge-high">높음</span>
</div>
<div class="todo-title">예산 편성안 검토</div>
<div class="todo-meta-row">
<span>담당자: 김민준</span>
<span>2025-10-22 마감</span>
</div>
</div>
<div class="todo-actions">
<button class="icon-btn" onclick="editTodo('todo-005')" title="편집">✏️</button>
<div class="simple-todo-meta">
<span>👤 김민준</span>
<span>📅 2025-10-22</span>
</div>
</div>
</div>
<div class="todo-card">
<div class="todo-top">
<div class="todo-checkbox-wrapper">
<input type="checkbox" class="todo-checkbox" id="check-todo-003"
onchange="toggleTodoComplete('todo-003', this.checked)">
<div class="simple-todo-item">
<div class="simple-todo-header">
<div class="simple-todo-title">UI 프로토타입 디자인</div>
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(4)" title="수정">✏️</button>
</div>
<div class="todo-content-wrapper">
<div class="todo-badges">
<span class="badge badge-primary">D-7</span>
<span class="badge badge-medium">보통</span>
</div>
<div class="todo-title">UI 프로토타입 디자인</div>
<div class="todo-meta-row">
<span>담당자: 최유진</span>
<span>2025-10-28 마감</span>
</div>
</div>
<div class="todo-actions">
<button class="icon-btn" onclick="editTodo('todo-003')" title="편집">✏️</button>
<div class="simple-todo-meta">
<span>👤 최유진</span>
<span>📅 2025-10-28</span>
</div>
</div>
</div>
<div class="todo-card completed">
<div class="todo-top">
<div class="todo-checkbox-wrapper">
<input type="checkbox" class="todo-checkbox" id="check-todo-004" checked
onchange="toggleTodoComplete('todo-004', this.checked)">
<div class="simple-todo-item">
<div class="simple-todo-header">
<div class="simple-todo-title">사용자 피드백 분석</div>
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(5)" title="수정">✏️</button>
</div>
<div class="todo-content-wrapper">
<div class="todo-badges">
<span class="badge badge-complete">완료</span>
<span class="badge badge-medium">보통</span>
</div>
<div class="todo-title">사용자 피드백 분석</div>
<div class="todo-meta-row">
<span>담당자: 김민준</span>
<span>2025-10-19 마감</span>
</div>
<div class="simple-todo-meta">
<span>👤 김민준</span>
<span>📅 2025-10-19</span>
</div>
</div>
</div>
@@ -1199,7 +1206,7 @@
<span class="reference-title">AI 기능 개선 회의</span>
<span class="relevance-badge relevance-high">92%</span>
</div>
<div class="reference-meta">2025-10-23 15:00 · 이준호</div>
<div class="reference-meta">이준호 · 2025-10-23 15:00</div>
<div class="reference-summary">
AI 요약 정확도 개선 방안 논의. BERT 모델 도입 및 학습 데이터 확보 계획 수립.
</div>
@@ -1211,7 +1218,7 @@
<span class="reference-title">개발 리소스 계획 회의</span>
<span class="relevance-badge relevance-medium">88%</span>
</div>
<div class="reference-meta">2025-10-22 11:00 · 김민준</div>
<div class="reference-meta">김민준 · 2025-10-22 11:00</div>
<div class="reference-summary">
Q4 개발 리소스 현황 및 배분 계획. 신규 프로젝트 우선순위 협의.
</div>
@@ -1223,7 +1230,7 @@
<span class="reference-title">경쟁사 분석 회의</span>
<span class="relevance-badge relevance-medium">78%</span>
</div>
<div class="reference-meta">2025-10-20 10:00 · 박서연</div>
<div class="reference-meta">박서연 · 2025-10-20 10:00</div>
<div class="reference-summary">
경쟁사 A, B, C 분석 결과. 우리의 차별점은 실시간 협업 및 검증 기능.
</div>
@@ -1237,6 +1244,43 @@
<button class="btn btn-secondary" onclick="navigateTo('11-회의록수정.html')">수정</button>
</div>
<!-- Todo 추가 모달 -->
<div class="modal-overlay" id="addTodoModal">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">Todo 추가</h3>
<button class="modal-close" onclick="closeModal('addTodoModal')">×</button>
</div>
<div class="modal-body">
<div class="form-group">
<label class="form-label">Todo 내용 <span class="text-error">*</span></label>
<input type="text" id="addTodoTitle" class="form-control" placeholder="할 일을 입력하세요">
</div>
<div class="form-group">
<label class="form-label">담당자 <span class="text-error">*</span></label>
<select id="addTodoAssignee" class="form-control">
<option value="">담당자를 선택하세요</option>
<option value="김민준">김민준</option>
<option value="이준호">이준호</option>
<option value="박서연">박서연</option>
<option value="최유진">최유진</option>
</select>
</div>
<div class="form-group">
<label class="form-label">마감일 <span class="text-error">*</span></label>
<div class="date-input-wrapper">
<input type="date" id="addTodoDueDate" class="form-control">
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('addTodoModal')">취소</button>
<button class="btn btn-primary" onclick="addTodo()">추가</button>
</div>
</div>
</div>
<!-- Todo 편집 모달 -->
<div class="modal-overlay" id="editTodoModal">
<div class="modal">
@@ -1245,6 +1289,7 @@
<button class="modal-close" onclick="closeModal('editTodoModal')">×</button>
</div>
<div class="modal-body">
<input type="hidden" id="editTodoId">
<div class="form-group">
<label class="form-label">Todo 제목 <span class="text-error">*</span></label>
<input type="text" id="editTodoTitle" class="form-control" placeholder="할 일을 입력하세요">
@@ -1258,30 +1303,12 @@
<option value="박서연">박서연</option>
<option value="최유진">최유진</option>
</select>
<p class="form-hint">👤 담당자 변경 시 이전/새 담당자에게 알림이 전송됩니다</p>
</div>
<div class="form-group">
<label class="form-label">마감일 <span class="text-error">*</span></label>
<div class="date-input-wrapper">
<input type="date" id="editTodoDueDate" class="form-control">
</div>
<p class="form-hint">📅 마감일 변경 시 캘린더가 자동 업데이트됩니다</p>
</div>
<div class="form-group">
<label class="form-label">우선순위 <span class="text-error">*</span></label>
<select id="editTodoPriority" class="form-control">
<option value="high">높음</option>
<option value="medium">보통</option>
<option value="low">낮음</option>
</select>
</div>
<!-- 권한 안내 (동적 메시지) -->
<div class="alert alert-info" id="editTodoPermissionInfo">
<span class="material-icons" style="font-size: 20px;">info</span>
<div>
<strong>권한 안내</strong>
<p style="margin: 4px 0 0 0; font-size: 14px;" id="editTodoPermissionText">회의 생성자로서 모든 항목을 수정할 수 있습니다.</p>
</div>
</div>
</div>
<div class="modal-footer">
@@ -1323,95 +1350,39 @@
z-index: 2;
}
/* Todo 편집 모달 - 모바일 전체화면 */
/* Todo 추가/편집 모달 - 바텀시트 스타일 */
#addTodoModal .modal,
#editTodoModal .modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100vh;
max-width: none;
max-height: none;
margin: 0;
border-radius: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
#editTodoModal .modal-header {
flex-shrink: 0;
padding: var(--space-lg) var(--space-md);
border-bottom: 1px solid var(--gray-200);
display: flex;
align-items: center;
justify-content: space-between;
}
#editTodoModal .modal-title {
font-size: var(--font-h3);
font-weight: var(--font-weight-bold);
margin: 0;
}
#editTodoModal .modal-close {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
background: none;
border: none;
cursor: pointer;
color: var(--gray-600);
border-radius: var(--radius-md);
transition: all var(--transition-fast);
}
#editTodoModal .modal-close:hover {
background: var(--gray-100);
color: var(--gray-900);
}
#editTodoModal .modal-body {
flex: 1;
max-height: 90vh;
overflow-y: auto;
padding: var(--space-lg) var(--space-md);
-webkit-overflow-scrolling: touch;
}
#addTodoModal .modal-footer,
#editTodoModal .modal-footer {
flex-shrink: 0;
padding: var(--space-md);
border-top: 1px solid var(--gray-200);
display: flex;
gap: var(--space-sm);
background: var(--white);
justify-content: flex-end;
margin-top: var(--space-md);
}
#addTodoModal .modal-footer .btn,
#editTodoModal .modal-footer .btn {
flex: 1;
}
/* 데스크톱에서는 중앙 모달로 복원 */
/* 데스크톱에서는 중앙 모달 */
@media (min-width: 768px) {
#addTodoModal .modal,
#editTodoModal .modal {
position: relative;
top: auto;
left: auto;
right: auto;
bottom: auto;
width: 90%;
max-width: 600px;
height: auto;
max-height: 90vh;
margin: 0 auto;
border-radius: var(--radius-lg);
}
}
/* 회의 생성자 전용 요소 숨김 */
.creator-only.hidden {
display: none !important;
}
</style>
<script src="common.js"></script>
@@ -1460,24 +1431,17 @@
}
/**
* Todo 필터링 (09-Todo관리와 동일)
* MVP 스코프 축소 v1.5.1: Todo 필터링/편집 함수 제거됨
* Todo는 단순 조회만 가능하므로 더 이상 사용되지 않음
*/
/*
function filterTodos(filter) {
currentFilter = filter;
// 탭 활성화
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.classList.remove('active');
});
document.querySelector(`.filter-btn[data-filter="${filter}"]`).classList.add('active');
renderTodoList();
// 제거됨: Todo 필터링 기능
}
*/
/**
* Todo 편집 모달 열기
* @param {string} todoId - 편집할 Todo ID
*/
/*
function editTodo(todoId) {
const todo = meetingTodos.find(t => t.id === todoId);
if (!todo) return;
@@ -1610,39 +1574,13 @@
* @param {string} todoId - Todo ID
* @param {boolean} isChecked - 체크박스 상태
*/
/*
function toggleTodoComplete(todoId, isChecked) {
if (isChecked) {
// 완료 처리
if (confirm('완료 처리하시겠습니까?')) {
const todo = meetingTodos.find(t => t.id === todoId);
if (todo) {
todo.status = 'completed';
showToast('Todo가 완료되었습니다', 'success');
updateTodoProgress();
renderTodoList();
}
} else {
event.target.checked = false;
}
} else {
// 미완료로 되돌리기
if (confirm('미완료로 변경하시겠습니까?')) {
const todo = meetingTodos.find(t => t.id === todoId);
if (todo) {
todo.status = 'incomplete';
showToast('미완료로 변경되었습니다', 'info');
updateTodoProgress();
renderTodoList();
}
} else {
event.target.checked = true;
}
}
// 제거됨: Todo 완료 토글 기능
}
*/
/**
* Todo 진행률 업데이트
*/
/*
function updateTodoProgress() {
const total = meetingTodos.length;
const completed = meetingTodos.filter(t => t.status === 'completed').length;
@@ -1731,6 +1669,191 @@
if (filterCompletedCount) filterCompletedCount.textContent = completed;
}
/**
* 회의 생성자 여부 확인
* @param {string} meetingId - 회의 ID
* @param {string} userName - 사용자 이름
* @returns {boolean} 회의 생성자 여부
*/
function checkIfUserIsCreator(meetingId, userName) {
// 실제로는 서버 API를 호출하여 확인
// 프로토타입에서는 샘플 데이터로 시뮬레이션
const meetingCreators = {
'meeting-001': '김민준',
'meeting-002': '이서연',
'meeting-003': '박준호'
};
return meetingCreators[meetingId] === userName;
}
/**
* Todo 수정 함수 (index 기반)
* @param {number} index - Todo 인덱스 (1-based)
*/
function editTodo(index) {
// 1-based index를 0-based로 변환
const todo = meetingTodos[index - 1];
if (!todo) {
showToast('Todo를 찾을 수 없습니다', 'error');
return;
}
// 모달에 데이터 채우기
document.getElementById('editTodoId').value = index;
document.getElementById('editTodoTitle').value = todo.title;
// 담당자 처리 (assignee가 객체인 경우 name 속성 사용)
const assigneeName = typeof todo.assignee === 'object' ? todo.assignee.name : todo.assignee;
document.getElementById('editTodoAssignee').value = assigneeName;
document.getElementById('editTodoDueDate').value = todo.dueDate;
// 회의 생성자 여부 확인
const currentUser = '김민준'; // 현재 로그인 사용자
const isCreator = checkIfUserIsCreator(CURRENT_MEETING_ID, currentUser);
// 담당자 필드 표시 여부 결정 (회의 생성자만 표시)
const assigneeGroup = document.getElementById('editTodoAssigneeGroup');
if (isCreator) {
assigneeGroup.style.display = 'block';
} else {
assigneeGroup.style.display = 'none';
}
// 모달 열기
openModal('editTodoModal');
}
/**
* Todo 수정 저장 (index 기반)
*/
function saveTodoEdit() {
const index = parseInt(document.getElementById('editTodoId').value);
const title = document.getElementById('editTodoTitle').value.trim();
const assignee = document.getElementById('editTodoAssignee').value.trim();
const dueDate = document.getElementById('editTodoDueDate').value;
if (!title) {
showToast('제목을 입력해주세요', 'error');
return;
}
if (!assignee) {
showToast('담당자를 입력해주세요', 'error');
return;
}
if (!dueDate) {
showToast('마감일을 선택해주세요', 'error');
return;
}
// 1-based index를 0-based로 변환하여 Todo 업데이트
const todoIndex = index - 1;
if (todoIndex >= 0 && todoIndex < meetingTodos.length) {
const todo = meetingTodos[todoIndex];
const oldAssignee = typeof todo.assignee === 'object' ? todo.assignee.name : todo.assignee;
const oldDueDate = todo.dueDate;
// Todo 업데이트 (실제로는 API 호출)
todo.title = title;
// assignee가 객체인 경우 name 속성만 업데이트
if (typeof todo.assignee === 'object') {
todo.assignee.name = assignee;
} else {
todo.assignee = assignee;
}
todo.dueDate = dueDate;
showToast('Todo가 수정되었습니다', 'success');
// 담당자 변경 시 알림
if (oldAssignee !== assignee) {
setTimeout(() => {
showToast(`${oldAssignee}${assignee}에게 알림이 전송되었습니다`, 'info');
}, 1000);
}
// 마감일 변경 시 알림
if (oldDueDate !== dueDate) {
setTimeout(() => {
showToast('캘린더가 업데이트되었습니다', 'info');
}, oldAssignee !== assignee ? 2000 : 1000);
}
}
closeModal('editTodoModal');
// 페이지 새로고침 (실제로는 해당 Todo 항목만 업데이트)
setTimeout(() => {
location.reload();
}, 1500);
}
/**
* Todo 추가 함수
*/
function addTodo() {
const title = document.getElementById('addTodoTitle').value.trim();
const assignee = document.getElementById('addTodoAssignee').value.trim();
const dueDate = document.getElementById('addTodoDueDate').value;
// 유효성 검사
if (!title) {
showToast('Todo 내용을 입력해주세요', 'error');
return;
}
if (!assignee) {
showToast('담당자를 선택해주세요', 'error');
return;
}
if (!dueDate) {
showToast('마감일을 선택해주세요', 'error');
return;
}
// 새 Todo 추가 (실제로는 API 호출)
const newTodo = {
id: 'todo-' + Date.now(),
meetingId: CURRENT_MEETING_ID,
title: title,
assignee: assignee,
dueDate: dueDate,
status: 'pending'
};
meetingTodos.push(newTodo);
showToast('Todo가 추가되었습니다', 'success');
// 담당자에게 알림 전송
setTimeout(() => {
showToast(`${assignee}에게 알림이 전송되었습니다`, 'info');
}, 1000);
// 캘린더 업데이트 알림
setTimeout(() => {
showToast('캘린더가 업데이트되었습니다', 'info');
}, 2000);
closeModal('addTodoModal');
// 입력 필드 초기화
document.getElementById('addTodoTitle').value = '';
document.getElementById('addTodoAssignee').value = '';
document.getElementById('addTodoDueDate').value = '';
// 페이지 새로고침 (실제로는 Todo 리스트만 업데이트)
setTimeout(() => {
location.reload();
}, 2500);
}
/**
* 페이지 초기화
*/
@@ -1740,13 +1863,19 @@
const isCreator = checkIfUserIsCreator(CURRENT_MEETING_ID, currentUser);
if (isCreator) {
const titleContainer = document.getElementById('meeting-title-container');
const badge = titleContainer.querySelector('.badge');
const badgesContainer = document.getElementById('meeting-badges');
const crownIcon = document.createElement('span');
crownIcon.textContent = '👑';
crownIcon.style.fontSize = '24px';
// badge 다음에 👑 삽입
badge.insertAdjacentElement('afterend', crownIcon);
crownIcon.style.fontSize = '20px';
crownIcon.title = '회의 생성자';
// 배지 영역에 크라운 추가
badgesContainer.appendChild(crownIcon);
} else {
// 회의 생성자가 아닐 경우 creator-only 요소 숨김
const creatorOnlyElements = document.querySelectorAll('.creator-only');
creatorOnlyElements.forEach(element => {
element.classList.add('hidden');
});
}
updateTodoProgress();
+65 -70
View File
@@ -6,6 +6,17 @@
<title>회의록 수정 - 회의록 서비스</title>
<link rel="stylesheet" href="common.css">
<style>
/*
MVP 스코프 축소 v1.5.2 적용됨:
- ❌ 실시간 협업 표시 ("편집 중" 표시 제거)
- ❌ Todo 편집 기능 제거 (단순 조회만 가능)
- ❌ 검증률 표시 및 최종 확정 버튼 제거
- ✅ 안건별 검증 완료 체크박스 사용
- ✅ Last Write Wins (LWW) 정책 적용
- ✅ AI 요약 기능 통합: "AI 상세 요약" → "AI 요약"으로 명칭 변경
- ✅ AI 재생성 버튼: 텍스트 편집 영역 내용 기반으로 한줄 요약 재생성
*/
/* 페이지별 커스텀 스타일만 유지 */
/* 공통 스타일(헤더, 메인콘텐츠, 안건, AI요약, 관련회의록, 액션바)은 common.css 사용 */
@@ -101,32 +112,8 @@
gap: var(--space-xs);
}
/* AI 한줄 요약 (읽기 전용, UFR-AI-036) */
.ai-summary-oneline {
background: var(--gray-50);
border-left: 4px solid var(--primary);
border-radius: var(--radius-md);
padding: var(--space-sm) var(--space-md);
margin-bottom: var(--space-md);
display: flex;
align-items: center;
gap: var(--space-sm);
}
.ai-summary-oneline .lock-icon {
font-size: 18px;
color: var(--gray-500);
flex-shrink: 0;
}
.ai-summary-oneline .summary-text {
font-size: var(--font-small);
color: var(--gray-700);
font-weight: var(--font-weight-medium);
flex: 1;
min-width: 0;
}
/* AI 요약 편집 영역 (UFR-AI-036) */
/* 헤더, textarea, footer 스타일은 common.css 사용 */
/* AI 요약 편집 Footer (common.css에 없는 부분) */
.ai-summary-footer {
display: flex;
@@ -187,6 +174,14 @@
.reference-item {
position: relative;
padding-right: 40px; /* 삭제 버튼 공간 확보 */
cursor: default; /* 카드 전체는 클릭 불가 */
}
/* 수정 페이지에서는 카드 hover 효과 제거 (삭제 버튼만 클릭 가능) */
.reference-item:hover {
transform: none;
border-color: var(--gray-200);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.remove-btn {
@@ -245,6 +240,19 @@
gap: var(--space-sm);
}
/* 회의 생성자 전용 UI 표시 제어 */
.creator-only {
display: flex; /* 기본: 회의 생성자 환경 */
}
.agenda-verification:not([data-is-creator="true"]) .creator-only {
display: none; /* 참석자 환경에서는 숨김 */
}
.agenda-verification:not(.verified) .creator-only {
display: none; /* 검증 안 된 경우 버튼 숨김 */
}
/* 읽기 전용 표시 */
.readonly-badge {
display: inline-flex;
@@ -395,23 +403,17 @@
</div>
</div>
<!-- AI 한줄 요약 (읽기 전용, UFR-AI-036) -->
<div class="ai-summary-oneline">
<span class="lock-icon">🔒</span>
<span class="summary-text">타겟 고객을 20-30대로 설정, UI/UX 개선 집중</span>
</div>
<!-- AI 상세 요약 편집 -->
<!-- AI 요약 편집 (UFR-AI-036) -->
<div class="ai-summary-edit">
<div class="ai-summary-header">
<span class="ai-summary-label">💡 AI 상세 요약</span>
<button class="btn-secondary btn-sm" onclick="regenerateSummary(1)">AI 재생성</button>
<span class="ai-summary-label">💡 AI 요약</span>
<button class="btn btn-primary btn-sm" onclick="regenerateSummary(1)">AI 재생성</button>
</div>
<textarea
class="ai-summary-textarea"
placeholder="AI 요약을 입력하거나 수정하세요"
readonly
>신제품은 AI 기반 회의록 자동화 서비스로 결정. 타겟은 중소기업 및 스타트업이며, 주요 기능은 음성인식, AI 요약, Todo 추출입니다. 경쟁사 대비 차별점은 실시간 검증 및 협업 기능입니다.</textarea>
>타겟 고객을 20-30대로 설정, UI/UX 개선 집중</textarea>
<div class="ai-summary-footer">
<span class="ai-summary-time">마지막 수정: 1시간 전</span>
</div>
@@ -466,16 +468,18 @@
</div>
</div>
<!-- 안건별 검증 (회의 생성자 권한) -->
<div class="agenda-verification verified" id="verify-agenda-1">
<!-- 안건별 검증 (UFR-COLLAB-030) -->
<!-- 참석자: 체크박스만 표시 (검증완료 시 읽기 전용) -->
<!-- 생성자: 검증완료 시 "잠금 해제" 버튼 표시 -->
<div class="agenda-verification verified" id="verify-agenda-1" data-is-creator="true">
<input type="checkbox" class="checkbox" id="verify-1" checked disabled>
<div class="verification-label">
<label for="verify-1">
<span class="font-medium">검증 완료</span>
<span class="text-caption text-muted"> (잠금됨 · 회의 생성자만 수정 가능)</span>
</label>
</div>
<div class="verification-actions">
<!-- 회의 생성자만 보이는 잠금 해제 버튼 (검증완료 시에만 표시) -->
<div class="verification-actions creator-only">
<button class="btn btn-secondary btn-sm" onclick="unlockAgendaVerification(1)">🔓 잠금 해제</button>
</div>
</div>
@@ -492,23 +496,17 @@
</div>
</div>
<!-- AI 한줄 요약 (읽기 전용, UFR-AI-036) -->
<div class="ai-summary-oneline">
<span class="lock-icon">🔒</span>
<span class="summary-text">개발 기간 3개월, 백엔드 2명/프론트 2명/AI 1명 투입</span>
</div>
<!-- AI 상세 요약 편집 -->
<!-- AI 요약 편집 (UFR-AI-036) -->
<div class="ai-summary-edit">
<div class="ai-summary-header">
<span class="ai-summary-label">💡 AI 상세 요약</span>
<button class="btn-secondary btn-sm" onclick="regenerateSummary(2)">AI 재생성</button>
<span class="ai-summary-label">💡 AI 요약</span>
<button class="btn btn-primary btn-sm" onclick="regenerateSummary(2)">AI 재생성</button>
</div>
<textarea
class="ai-summary-textarea"
placeholder="AI 요약을 입력하거나 수정하세요"
readonly
>개발 기간 3개월로 설정. 백엔드 2명, 프론트 2명, AI 엔지니어 1명 투입. 주간 스프린트로 진행하며, 2주마다 베타 테스트 실시.</textarea>
>개발 기간 3개월, 백엔드 2명/프론트 2명/AI 1명 투입</textarea>
<div class="ai-summary-footer">
<span class="ai-summary-time">생성: 2025-10-25 16:32</span>
</div>
@@ -547,16 +545,18 @@
</div>
</div>
<!-- 안건별 검증 (회의 생성자 권한) -->
<div class="agenda-verification verified" id="verify-agenda-2">
<!-- 안건별 검증 (UFR-COLLAB-030) -->
<!-- 참석자: 체크박스만 표시 (검증완료 시 읽기 전용) -->
<!-- 생성자: 검증완료 시 "잠금 해제" 버튼 표시 -->
<div class="agenda-verification verified" id="verify-agenda-2" data-is-creator="true">
<input type="checkbox" class="checkbox" id="verify-2" checked disabled>
<div class="verification-label">
<label for="verify-2">
<span class="font-medium">검증 완료</span>
<span class="text-caption text-muted"> (잠금됨 · 회의 생성자만 수정 가능)</span>
</label>
</div>
<div class="verification-actions">
<!-- 회의 생성자만 보이는 잠금 해제 버튼 (검증완료 시에만 표시) -->
<div class="verification-actions creator-only">
<button class="btn btn-secondary btn-sm" onclick="unlockAgendaVerification(2)">🔓 잠금 해제</button>
</div>
</div>
@@ -573,23 +573,17 @@
</div>
</div>
<!-- AI 한줄 요약 (읽기 전용, UFR-AI-036) -->
<div class="ai-summary-oneline">
<span class="lock-icon">🔒</span>
<span class="summary-text">프리 런칭 캠페인, LinkedIn 및 스타트업 커뮤니티 집중</span>
</div>
<!-- AI 상세 요약 편집 -->
<!-- AI 요약 편집 (UFR-AI-036) -->
<div class="ai-summary-edit">
<div class="ai-summary-header">
<span class="ai-summary-label">💡 AI 상세 요약</span>
<button class="btn-secondary btn-sm" onclick="regenerateSummary(3)">AI 재생성</button>
<span class="ai-summary-label">💡 AI 요약</span>
<button class="btn btn-primary btn-sm" onclick="regenerateSummary(3)">AI 재생성</button>
</div>
<textarea
class="ai-summary-textarea"
placeholder="AI 요약을 입력하거나 수정하세요"
readonly
>베타 출시 전 프리 런칭 캠페인 진행. 주요 채널은 LinkedIn 및 스타트업 커뮤니티. 초기 100팀 무료 제공 후 유료 전환 유도.</textarea>
>프리 런칭 캠페인, LinkedIn 및 스타트업 커뮤니티 집중</textarea>
<div class="ai-summary-footer">
<span class="ai-summary-time">생성: 2025-10-25 16:35</span>
</div>
@@ -624,15 +618,15 @@
</div>
<!-- 안건별 검증 (회의 생성자 권한) -->
<div class="agenda-verification verified" id="verify-agenda-3">
<div class="agenda-verification verified" id="verify-agenda-3" data-is-creator="true">
<input type="checkbox" class="checkbox" id="verify-3" checked disabled>
<div class="verification-label">
<label for="verify-3">
<span class="font-medium">검증 완료</span>
<span class="text-caption text-muted"> (잠금됨 · 회의 생성자만 수정 가능)</span>
</label>
</div>
<div class="verification-actions">
<!-- 회의 생성자만 보이는 잠금 해제 버튼 (검증완료 시에만 표시) -->
<div class="verification-actions creator-only">
<button class="btn btn-secondary btn-sm" onclick="unlockAgendaVerification(3)">🔓 잠금 해제</button>
</div>
</div>
@@ -743,12 +737,13 @@
}, 1000);
}
// AI 요약 재생성
// AI 한줄 요약 재생성 (텍스트 편집 영역 내용 기반, UFR-AI-036)
function regenerateSummary(agendaId) {
showToast('AI 요약을 생성 중입니다...', 'info');
showToast('AI 요약을 생성 중입니다...', 'info');
setTimeout(() => {
showToast('AI 요약이 생성되었습니다', 'success');
showToast('생성되었습니다', 'success');
// 재생성된 한줄 요약은 회의록 상세조회 화면의 대시보드 및 회의록 탭에 즉시 반영됨
markAsUnsaved();
}, 2000);
}
@@ -453,10 +453,6 @@
<span class="sidebar-nav-icon"><img src="img/edit.png" width="32"></span>
<span>회의록</span>
</a>
<a href="09-Todo관리.html" class="sidebar-nav-item">
<span class="sidebar-nav-icon"><img src="img/list.png" width="32"></span>
<span>Todo 관리</span>
</a>
</nav>
<!-- 사용자 정보 영역 (Desktop) -->
@@ -581,9 +577,6 @@
<a href="12-회의록목록조회.html" class="nav-item active">
<img src="img/edit.png" alt="회의록" style="width: 45px;">
</a>
<a href="09-Todo관리.html" class="nav-item">
<img src="img/list.png" alt="Todo" style="width: 45px;">
</a>
</nav>
<script src="common.js"></script>
+14 -5
View File
@@ -1429,11 +1429,12 @@ input[type="date"]::-webkit-calendar-picker-indicator {
.related-meeting-item {
background: var(--white);
border-radius: var(--radius-md);
padding: var(--space-sm);
padding: var(--space-md);
margin-bottom: var(--space-sm);
display: flex;
gap: var(--space-sm);
transition: background var(--transition-fast);
cursor: pointer;
transition: all var(--transition-fast);
border: 1px solid var(--gray-200);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.reference-item:last-child,
@@ -1443,7 +1444,15 @@ input[type="date"]::-webkit-calendar-picker-indicator {
.reference-item:hover,
.related-meeting-item:hover {
background: var(--gray-100);
border-color: var(--primary);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
transform: translateY(-1px);
}
.reference-item:active,
.related-meeting-item:active {
transform: translateY(0);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.reference-content,
+9 -2
View File
@@ -31,7 +31,7 @@ const SAMPLE_MEETINGS = [
time: '14:00',
duration: 90,
location: '본사 2층 대회의실',
status: 'scheduled', // ongoing, scheduled, completed
status: 'draft', // ongoing, scheduled, completed, draft(작성중), complete(확정완료)
participants: [
{ id: 'user-001', name: '김민준', avatar: '김', avatarColor: 'green' },
{ id: 'user-002', name: '박서연', avatar: '박', avatarColor: 'blue' },
@@ -39,7 +39,8 @@ const SAMPLE_MEETINGS = [
{ id: 'user-004', name: '최유진', avatar: '최', avatarColor: 'pink' }
],
sections: 3,
todos: 5
todos: 5,
minutesId: 'minutes-001' // 회의록 ID 연결
},
{
id: 'meeting-002',
@@ -1083,6 +1084,12 @@ function getMeetingStatusInfo(meeting) {
if (meeting.status === 'ongoing') {
return { badgeType: 'ongoing', badgeText: '진행중' };
}
if (meeting.status === 'draft') {
return { badgeType: 'draft', badgeText: '작성중' };
}
if (meeting.status === 'complete') {
return { badgeType: 'complete', badgeText: '확정완료' };
}
if (meeting.status === 'completed') {
return { badgeType: 'complete', badgeText: '확정완료' };
}
+18 -5
View File
@@ -1,5 +1,14 @@
# 회의록 서비스 스타일 가이드
## 문서 정보
- **작성일**: 2025-10-21
- **최종 수정일**: 2025-10-27
- **작성자**: 강지수 (Product Designer), 이미준 (서비스 기획자), 도그냥 (서비스 기획자)
- **버전**: 1.3.1
- **설계 철학**: Mobile First Design
---
## 1. 디자인 철학
### 핵심 원칙
@@ -368,8 +377,10 @@
- 02-대시보드: 최근 회의 카드, 내 회의록 카드
- 10-회의록상세조회: 회의록 정보 섹션
### D-day 배지
Todo 마감일 표시를 위한 D-day 배지 스타일입니다.
### D-day 배지 (참고용)
**⚠️ MVP 스코프 축소 (v1.3.1)**: D-day 배지는 09-Todo관리 화면에서만 사용됩니다. 10-회의록상세조회 및 11-회의록수정 화면에서는 Todo 단순 조회만 제공하므로 D-day 배지가 표시되지 않습니다.
Todo 마감일 표시를 위한 D-day 배지 스타일입니다 (09-Todo관리 화면 전용).
```css
/* D-Day (오늘 마감) */
@@ -1277,7 +1288,7 @@ Todo 마감일 표시를 위한 D-day 배지 스타일입니다.
- 참석자 관리 (추가/삭제)
- 회의록 최종 확정
- 검증 완료된 안건 잠금 해제
- 모든 Todo 수정 (담당자 변경 포함)
- ~~모든 Todo 수정 (담당자 변경 포함)~~ **MVP 스코프 축소 (v1.3.1)**: Todo 편집 기능 제거
- **사용 예시**:
- "회의 생성자 전용 기능"
- "회의 생성자만 회의를 종료할 수 있습니다"
@@ -1288,11 +1299,11 @@ Todo 마감일 표시를 위한 D-day 배지 스타일입니다.
- 회의록 조회
- 안건 편집 (검증 완료 전)
- 안건 검증
- 본인의 Todo 수정 (담당자 변경 불가)
- ~~본인의 Todo 수정 (담당자 변경 불가)~~ **MVP 스코프 축소 (v1.3.1)**: Todo 편집 기능 제거, 단순 조회만 가능
- 회의록 목록 조회 (본인이 참석한 회의만)
- **사용 예시**:
- "모든 참석자가 편집할 수 있습니다"
- "참석자는 본인의 Todo만 수정 가능합니다"
- ~~"참석자는 본인의 Todo만 수정 가능합니다"~~ **변경 (v1.3.1)**: "Todo는 조회만 가능합니다"
### 사용하지 않는 용어
- ❌ "회의록 작성자" - 명확하지 않으므로 사용 금지
@@ -1304,6 +1315,8 @@ Todo 마감일 표시를 위한 D-day 배지 스타일입니다.
| 버전 | 날짜 | 작성자 | 변경 내용 |
|------|------|--------|----------|
| 1.3.1 | 2025-10-27 | 강지수 | MVP 스코프 축소 v2.4.0 반영 (Todo 관련 섹션 수정)<br>- **D-day 배지 섹션**: 참고용으로 변경, 09-Todo관리 화면에서만 사용됨을 명시<br> - 10-회의록상세조회 및 11-회의록수정 화면에서는 Todo 단순 조회만 제공<br>- **사용자 역할 용어**: 권한 설명 업데이트<br> - 회의 생성자: "모든 Todo 수정" 권한 제거됨 (취소선 표시)<br> - 회의 참석자: "본인의 Todo 수정" 권한 제거됨 (취소선 표시)<br> - Todo는 조회만 가능하도록 변경<br>- **일관성 유지**: UI/UX 설계서 v1.5.1과 동기화 |
| 1.3.0 | 2025-10-24 | 이미준 | 사용자 역할 용어 통일 (유저스토리 v2.1.2 반영)<br>- **용어 정의 섹션 추가**: "회의 생성자"와 "회의 참석자" 용어 명확히 정의<br> - 회의 생성자: 회의 예약을 생성한 사용자, 회의 시작/종료/최종 확정 권한<br> - 회의 참석자: 회의에 참석하는 모든 사용자 (생성자 포함), 회의록 편집/조회 권한<br>- **사용하지 않는 용어 명시**: "회의록 작성자", "작성자" 용어 사용 금지<br>- **권한 상세 설명**: 생성자 전용 기능, 참석자 공통 기능 구체화<br>- **일관성 달성**: 유저스토리, 화면설계서, 스타일 가이드 간 용어 완전 통일 |
| 1.0 | 2025-10-21 | 최유진 | 최초 작성 - reference/sampleimg 샘플 이미지 기반 스타일 가이드 작성 |
| 1.0.1 | 2025-10-21 | 이미준 | 네비게이션 간소화 및 인터랙션 개선<br>- 설정 메뉴를 프로필 메뉴로 통합 (사이드바, 하단 네비게이션)<br>- 로그아웃 및 개인 설정 기능은 프로필 영역에서 접근<br>- Todo 항목 클릭 시 회의록 상세 화면으로 이동하는 인터랙션 추가<br>- 네비게이션 메뉴 항목: 대시보드, 회의 목록, Todo 관리, 프로필 (4개 항목) |
| 1.1 | 2025-10-21 | 이미준 | 반응형 네비게이션 및 2열 레이아웃 패턴 추가<br>- **반응형 네비게이션 전략**: Mobile (하단 네비게이션), Desktop (왼쪽 사이드바 240px)<br>- **사이드바 네비게이션 (Desktop)**: 로고 영역, 메뉴 항목 (대시보드/회의 목록/Todo 관리), 사용자 정보 영역<br>- **하단 네비게이션 (Mobile)**: 홈/회의록/Todo/프로필 (4개 메뉴)<br>- **2열 레이아웃 패턴**: 회의 진행 화면용 (왼쪽 65% 에디터, 오른쪽 35% 탭 패널)<br>- **탭 네비게이션 사용 예시**: 회의록 상세 (2개 탭), 회의 진행 (4개 탭) |
+312 -224
View File
@@ -2,25 +2,60 @@
## 문서 정보
- **작성일**: 2025-10-21
- **최종 수정일**: 2025-10-25
- **최종 수정일**: 2025-10-27
- **작성자**: 이미준 (서비스 기획자)
- **버전**: 1.4.20
- **버전**: 1.5.3
- **설계 철학**: Mobile First Design
---
## 목차
1. [설계 개요](#설계-개요)
- [설계 목표](#설계-목표)
- [설계 원칙](#설계-원칙)
- [유저스토리 매핑](#유저스토리-매핑)
- [주요 추가 기능 (v1.1)](#주요-추가-기능-v11)
2. [프로토타입 화면 목록](#프로토타입-화면-목록)
3. [화면 간 사용자 플로우](#화면-간-사용자-플로우)
- [주요 사용자 시나리오별 플로우](#주요-사용자-시나리오별-플로우)
- [플로우 다이어그램](#플로우-다이어그램)
4. [화면별 상세 설계](#화면별-상세-설계)
- [01-로그인](#01-로그인)
- [02-대시보드](#02-대시보드)
- [03-회의예약](#03-회의예약)
- [04-템플릿선택](#04-템플릿선택)
- [05-회의진행](#05-회의진행)
- [07-회의종료](#07-회의종료)
- [09-Todo관리](#09-todo관리)
- [10-회의록상세조회](#10-회의록상세조회)
- [11-회의록수정](#11-회의록수정)
- [12-회의록목록조회](#12-회의록목록조회)
5. [공통 UI 컴포넌트](#공통-ui-컴포넌트)
6. [공통 에러 메시지 표준](#공통-에러-메시지-표준)
- [네트워크 오류](#네트워크-오류)
- [데이터 로딩 실패](#데이터-로딩-실패)
- [권한 오류](#권한-오류)
- [인증 오류](#인증-오류)
- [입력 검증 오류](#입력-검증-오류)
- [서버 오류](#서버-오류)
7. [화면 간 전환 및 네비게이션](#화면-간-전환-및-네비게이션)
8. [반응형 설계 전략](#반응형-설계-전략)
- [브레이크포인트](#브레이크포인트)
- [레이아웃 전략](#레이아웃-전략)
- [컴포넌트별 반응형 전략](#컴포넌트별-반응형-전략)
- [이미지 및 미디어](#이미지-및-미디어)
9. [접근성 보장 방안](#접근성-보장-방안)
10. [성능 최적화 방안](#성능-최적화-방안)
- [1. 로딩 성능](#1-로딩-성능)
- [2. 렌더링 성능](#2-렌더링-성능)
- [3. 네트워크 최적화](#3-네트워크-최적화)
- [4. 실시간 동기화 최적화](#4-실시간-동기화-최적화)
- [5. 성능 모니터링](#5-성능-모니터링)
- [성능 목표](#성능-목표)
11. [변경 이력](#변경-이력)
12. [부록](#부록)
- [참고 자료](#참고-자료)
- [디자인 시스템 (추후 작성)](#디자인-시스템-추후-작성)
---
@@ -72,14 +107,16 @@
- 관련도 표시 (퍼센트 또는 별점)
- 최대 3개 자동 표시, 더보기로 전체 목록 확인 가능
[↑ 목차로 돌아가기](#목차)
---
## 프로토타입 화면 목록
| 번호 | 화면명 | 관련 유저스토리 | 비즈니스 중요도 | 사이드바 유무 | 이전화면 이동버튼 유무 | 비고 |
|------|--------|----------------|-------------------|-----------|------------------------|-------|
| 01 | 로그인 | UFR-USER-010 | 필수 | 사용자 인증 | X | X | |
| 02 | 대시보드 | - | 필수 | 메인 랜딩 페이지 | O | X | |
| 번호 | 화면명 | 관련 유저스토리 | 비즈니스 중요도 | 설명 | 사이드바 유무 | 이전화면 이동버튼 유무 | 비고 |
|------|--------|----------------|-------------------|------------------------|------------|------------------------|-------|
| 01 | 로그인 | UFR-USER-010 | 필수 | 사용자 인증 | X | X | |
| 02 | 대시보드 | UFR-USER-020 | 필수 | 메인 랜딩 페이지 | O | X | |
| 03 | 회의예약 | UFR-MEET-010 | 높음 | 회의 생성 | X | O | |
| 04 | 템플릿선택 | UFR-MEET-020 | 중간 | 회의록 템플릿 선택 | X | O | |
| 05 | 회의진행 | UFR-MEET-030, UFR-STT-010/020, UFR-AI-010, UFR-COLLAB-010 | 높음 | 실시간 회의 진행 및 회의록 작성 | X | X | |
@@ -87,7 +124,9 @@
| 09 | Todo관리 | UFR-TODO-010, UFR-TODO-030 | 높음 | Todo 목록 및 진행 관리 | O | X | |
| 10 | 회의록상세조회 | UFR-MEET-047 | 중간 | 회의록 상세 보기 | X | O | |
| 11 | 회의록수정 | UFR-MEET-055 | 중간 | 지난 회의록 수정 | X | O | |
| 12 | 회의록목록조회 | UFR-MEET-046 | 높음 | 회의록 목록 필터링/정렬/검색 | O | X | |
| 12 | 회의록목록조회 | UFR-MEET-046 | 높음 | 회의록 목록 필터링/정렬/검색 | O | X | |
[↑ 목차로 돌아가기](#목차)
---
@@ -143,6 +182,8 @@ graph TD
E -.실시간 연동.-> L
```
[↑ 목차로 돌아가기](#목차)
---
## 화면별 상세 설계
@@ -207,20 +248,25 @@ graph TD
### 02-대시보드
#### 개요
- **목적**: 주요 기능 접근 허브, 최근 활동 및 Todo 요약 제공
- **관련 유저스토리**: 여러 유저스토리의 진입점, UFR-MEET-030 (회의록 조회), UFR-TODO-010 (Todo 조회)
- **목적**: 주요 기능 접근 허브, 최근 활동 요약 제공
- **관련 유저스토리**: UFR-USER-020 (대시보드 조회)
- **비즈니스 중요도**: 필수
- **접근 경로**: 로그인 후 메인 화면
#### 주요 기능
#### 주요 기능 (MVP 스코프 축소 v1.5.0)
1. 빠른 회의 시작 및 예약
2. **예정된/진행중 회의 목록** (upcoming & ongoing meetings)
- 예정된 회의 (아직 시작 전)
- 진행중 회의 (참여 가능한 회의)
3. **내 Todo 우선순위별 표시** (지연중 → 진행중 → 미진행 → 완료, 최대 5개)
4. **내 회의록** (참여자/생성자로 등록된 최근 3개, 상태 포함)
3. **통계 정보 표시** (예정된 회의, 작성중 회의록)
4. **내 회의록** (참여자/생성자로 등록된 최근 4개, 상태 포함)
5. 전역 검색
**변경사항 (v1.5.0)**:
- ❌ 제거: "내 Todo" 섹션 및 Todo 관리 메뉴
- ✅ 추가: "작성중 회의록" 통계 카드
- ✅ 변경: 네비게이션 간소화 (대시보드, 회의록만 유지)
#### UI 구성요소
**Mobile (320px~768px)**
@@ -231,14 +277,15 @@ graph TD
- 예정된 회의가 없을 경우: "예정된 회의가 없습니다"
- **메인 콘텐츠** (스크롤, padding-bottom: 80px, background: gray-50)
- **통계 카드 컴팩트 배치** (단일 카드) - **개선안 A 적용 (v1.5)**
- 제목: "📊 오늘의 현황" (H5, Semibold)
- 수평 배치 (flex, space-around):
- "📅 예정 {N}" (Icon + Label + Value)
- "✅진행 {N}" (Icon + Label + Value)
- "📈 완료 {N}%" (Icon + Label + Value)
- 높이: ~80px (기존 대비 70% 감소)
- 반응형: 태블릿 이상에서 justify-content: flex-start, gap 증가
- **통계 카드** (2열 그리드) - **v1.5.0 변경**
- "📅 예정된 회의" 카드
- 값: 전체 예정 + 진행 중 회의 개수
- 클릭 액션: 없음 (정보 표시만)
- "📝 작성중 회의록" 카드
- 값: 내가 참석한 회의 중 '작성중' 상태인 회의록 개수
- 클릭 액션: 없음 (정보 표시만)
- 높이: ~80px
- 반응형: 태블릿 이상에서 간격 증가
- **최근 회의** 섹션
- 헤더: "예정된 회의" (H4) + "전체 보기 →" 링크
@@ -270,26 +317,9 @@ graph TD
- 타이머 표시: "10분 후 참여 가능" (시작 시간까지 남은 시간)
- 빈 상태: "예정된 회의가 없습니다"
- **내 Todo** 카드 (개선)
- 헤더: "내 Todo" (H4) + "전체 보기 →" 링크 (Todo 관리 화면으로 이동)
- **통계 요약 영역**:
- 진행 중 개수 배지
- 마감 임박 개수 (아이콘: schedule, 경고색)
- **Todo 리스트** (우선순위 순, 최대 5개):
1. 지연 중 (기한 지남, 빨간색)
2. 진행 중 (상태: in_progress)
3. 기한이 남은 미진행 (상태: not_started)
4. 완료 (상태: done, 회색 처리)
- 각 Todo 항목:
- 제목 (Medium weight)
- 메타정보: 담당자, 마감일
- D-day (색상: 지남-빨강, 오늘-경고, 여유-회색)
- 우선순위 배지 (high-빨강, medium-노랑, low-회색)
- 빈 상태: "할당된 Todo가 없습니다"
- **내 회의록** 카드 (개선)
- **내 회의록** 카드 - **v1.5.0 변경 (Todo 섹션 제거)**
- 헤더: "내 회의록" (H4) + "전체 보기 →" 링크 (회의록 목록 화면으로 이동)
- **최근 회의록 리스트** (최대 3개):
- **최근 회의록 리스트** (최대 4개, 2x2 그리드):
- 필터: 내가 참여자 또는 생성자로 등록된 회의록
- 정렬: 최근 생성 순 (createdAt 기준)
- 각 항목:
@@ -297,14 +327,16 @@ graph TD
- 회의 일시 (날짜 + 시간)
- 참석자 수
- **상태 배지**:
- "작성중" (draft, 노란색 배지)
- "작성중" (draft, 주황색 배지)
- "확정완료" (confirmed, 초록색 배지)
- 최종 수정 시간 (상대 시간: "1시간 전", "어제" 등)
- 검증완료율 표시 (작성중인 경우만)
- 클릭 시: 회의록 상세 화면으로 이동
- 빈 상태: "작성한 회의록이 없습니다. 첫 회의를 시작해보세요!"
- 빈 상태: "참여한 회의록이 없습니다"
**Mobile (320px~768px)**
- **하단 네비게이션**: [Mobile 하단 네비게이션](#mobile-하단-네비게이션-320px768px) 참조 (홈 활성)
**Mobile (320px~768px)** - **v1.5.0 네비게이션 간소화**
- **하단 네비게이션**: 2개 메뉴만 표시
- 홈 (대시보드) - 활성 상태
- 회의록 (회의록 목록)
**Tablet/Desktop (768px+)**
- **좌측 사이드바**: [Desktop 좌측 사이드바](#desktop-좌측-사이드바-768px) 참조 (대시보드 활성)
@@ -314,22 +346,17 @@ graph TD
- "안녕하세요, {사용자명}님!" (H2)
- "오늘의 일정을 확인하세요" (부제)
- **통계 카드 그리드** (3개, auto-fit)
- **통계 카드 그리드** (2개) - **v1.5.0 변경**
- 예정된 회의 (📅)
- 진행 중 Todo ()
- Todo 완료율 (📈)
- 작성중 회의록 (📝)
- **최근 회의 그리드** (2-3컬럼)
- 회의 카드들 (진행중 우선)
- 참여하기/수정/보기 버튼
- **할당된 Todo 리스트**
- 화이트 카드 배경
- 각 Todo 항목 구분선
- **내 회의록 리스트**
- 화이트 카드 배경
- 전체보기 → 11-회의록목록조회.html
- 전체보기 → 12-회의록목록조회.html
- **하단 네비게이션**: 숨김 (데스크톱에서는 사이드바 사용)
@@ -628,22 +655,27 @@ graph TD
#### 개요
- **목적**: 실시간 회의 진행 및 AI 기반 회의록 자동 작성
- **관련 유저스토리**: UFR-MEET-030, UFR-STT-010/020, UFR-AI-010, UFR-AI-040, UFR-COLLAB-010, UFR-RAG-010/020, UFR-PART-010/020/030, UFR-HOST-010/020, UFR-TERM-010/020
- **관련 유저스토리**: UFR-MEET-030, UFR-STT-010/020, UFR-AI-010, UFR-AI-040, UFR-COLLAB-010, UFR-RAG-010/020, UFR-PART-020, UFR-HOST-010/020, UFR-TERM-010/020
- **비즈니스 중요도**: 높음 (핵심 화면)
- **접근 경로**: 대시보드 → "참여하기" 버튼 (페이지 전환)
- **권한** (MVP 개선):
- **회의 생성자 전용**: 회의 종료, 녹음 제어 (일시정지/재개/종료)
- **모든 참석자**: 회의 참여, AI 주요 내용 체크, 용어 확인, 관련 회의록 확인, 중도 퇴장
- **모든 참석자**: 회의 참여, AI 기반 메모 작성, 용어 확인, 관련 회의록 확인, 중도 퇴장
#### 주요 기능
#### 주요 기능 (MVP 스코프 축소 v1.5.0)
1. 음성 녹음 및 실시간 텍스트 변환 (STT)
2. AI 자동 회의록 작성 (구조화)
3. **AI 기반 주요 메모 항목 실시간 제안** (UFR-MEET-030)
3. **AI 기반 메모 작성** (UFR-PART-020): AI가 실시간으로 감지한 주요 내용을 참석자가 선택하여 개인 메모로 저장
4. 전문용어 자동 감지 및 맥락 기반 설명
5. **참고자료 자동 연결** (이전 회의록, 관련 회의록)
6. 참석자 관리 및 초대 기능
7. 회의 진행 시간 표시
**변경사항 (v1.5.0)**:
- ✅ 변경: "AI 제안" 탭 → "AI 기반 메모" 탭으로 기능 변경
- ✅ 추가: 개인 메모 입력 및 저장 기능 (각 참석자별 개별 저장)
- ✅ 정책: 메모는 회의 종료 전까지만 표시/편집 가능, 다른 참석자 메모는 볼 수 없음
#### UI 구성요소
**전체 레이아웃**
@@ -654,7 +686,7 @@ graph TD
- **메인 콘텐츠 영역: 정보 패널** (탭 구조)
- **탭 네비게이션** (4개 탭)
- 참석자 (3명)
- AI 제안
- AI 기반 메모
- 용어 사전
- 관련 자료 (32건)
@@ -676,17 +708,69 @@ graph TD
- flex layout, 하단 구분선 (마지막 제외)
- 상태 표시 제거됨 (발언 중/온라인 등 표시 안 함)
- **AI 제안 탭**
- 제목: "AI 제안"
- **카드 디자인** (통일된 스타일):
- 배경: 연한 회색 (#FAFAFA)
- 테두리: 회색 점선 (1px dashed #D0D0D0)
- 테두리 둥글기: 8px
- 내부 패딩: 16px
- 카드 간 여백: 16px
- 헤더 폰트: 16px Bold, 민트 그린 (#4DD5A7)
- 본문 폰트: 14px, gray-700
- 구조: 헤더 + 본문 텍스트 + 액션 버튼
- **AI 기반 메모 탭** (UFR-PART-020)
- 제목: "AI 기반 메모"
- **메모 입력 영역** (상단):
- **메모 입력 텍스트박스**:
- placeholder: "메모를 입력하세요..."
- 다중 행 입력 지원 (textarea)
- 배경: 화이트 (#FFFFFF)
- 테두리: 회색 실선 (1px solid #E5E7EB)
- 테두리 둥글기: 8px
- 내부 패딩: 12px
- 최소 높이: 80px
- **저장 버튼**:
- 텍스트: "저장"
- 스타일: btn btn-primary (민트 그린)
- 위치: 메모 입력창 하단 우측
- 여백: 상단 8px
- **구분선**:
- 메모 입력 영역 하단에 회색 구분선 (1px solid #E5E7EB)
- 상하 여백: 16px
- **AI가 감지한 주요 내용 영역** (하단):
- **섹션 헤더**:
- 텍스트: "AI가 감지한 주요 내용"
- 폰트: 16px Bold, gray-800
- 하단 여백: 12px
- **주요 내용 리스트**:
- **리스트 아이템 디자인**:
- 배경: 연한 회색 (#FAFAFA)
- 테두리: 회색 점선 (1px dashed #D0D0D0)
- 테두리 둥글기: 8px
- 내부 패딩: 12px
- 아이템 간 여백: 8px
- 호버 시: 민트 그린 배경 (#E8F9F3), 커서 포인터
- **아이템 구조**:
- 시간 태그 (좌측):
- 형식: "[HH:MM]"
- 폰트: 12px Bold, 민트 그린 (#4DD5A7)
- 배경: 민트 그린 연한 배경 (#E8F9F3)
- 패딩: 4px 8px
- 테두리 둥글기: 4px
- 주요 내용 텍스트 (우측):
- 폰트: 14px, gray-700
- flex-grow: 1
- 좌측 여백: 8px
- **아이템 예시**:
- `[15:32] 예산 책정 관련 결정`
- `[15:35] 다음 회의 일정 합의`
- `[15:38] API 설계 패턴 논의`
- `[15:42] 마이크로서비스 아키텍처 채택`
- **클릭 인터랙션**:
- 아이템 클릭 시 → 메모 입력창에 "[시간] 내용" 형식으로 자동 추가
- 기존 메모가 있으면 줄바꿈 후 추가
- 입력된 메모는 수정 가능
- **정책**:
- 각 참석자별로 개별 저장 (다른 참석자의 메모는 볼 수 없음)
- 메모는 회의 종료 전까지만 표시 및 편집 가능
- 회의 종료 시 AI가 회의록 생성할 때 모든 참석자의 메모 참조
- **용어 사전 탭**
- 제목: "용어 사전"
@@ -792,15 +876,26 @@ graph TD
- 상태 표시 없음 (발언 중/온라인 등 제거)
- 참석자 수 동적 업데이트 (초대 성공 시)
- **AI 제안 탭**: AI가 생성한 주요 메모 항목 제안 (UFR-MEET-030)
- **실시간 주요 메모 추천**:
- **AI 기반 메모 탭** (UFR-PART-020): AI가 감지한 주요 내용을 참석자가 선택하여 개인 메모로 저장
- **메모 작성 및 저장**:
- 메모 입력창에 자유롭게 메모 작성 가능
- "저장" 버튼 클릭 시 개인 메모로 저장 (각 참석자별 개별 저장)
- 저장 성공 시 "{n}개의 메모가 저장되었습니다" 성공 토스트
- 저장 실패 시 "메모 저장에 실패했습니다" 오류 토스트
- **AI가 감지한 주요 내용**:
- 음성→텍스트 변환 후 AI가 실시간으로 회의 내용 분석
- **중요한 내용으로 판단된 경우에만** 주요 메모 항목 제안
- 논의항목/결정사항 등의 구분 없이 중요 내용을 주요 메모로 제안
- 추천 빈도는 중요 내용 발생에 따라 가변적 (고정 간격 아님)
- 각 제안 항목에 "주요 메모에 추가" 버튼 제공
- 클릭 시 해당 안건의 주요 메모에 자동 저장
- 실시간 업데이트: 새로운 제안은 상단에 표시
- **중요한 내용으로 판단된 경우에만** 주요 내용 항목 표시
- 각 항목: "[시간] 주요 내용 텍스트" 형식 (예: "[15:32] 예산 책정 관련 결정")
- 실시간 업데이트: 새로운 항목은 하단에 추가
- 항목 클릭 시:
1. 메모 입력창에 "[시간] 내용" 형식으로 자동 추가
2. 기존 메모가 있으면 줄바꿈 후 추가
3. 입력된 메모는 수정 가능 (자동/수동 구분 표시)
4. 저장 버튼 활성화
- **정책**:
- 메모는 회의 종료 전까지만 표시/편집 가능
- 각 참석자의 메모는 다른 참석자에게 보이지 않음
- 회의 종료 시 AI가 모든 참석자의 메모를 참조하여 회의록 생성
- **용어 사전 탭**: 회의에서 언급된 전문용어 설명
- **용어 검색 기능**:
@@ -840,24 +935,25 @@ graph TD
- 참석자 초대 이메일
- **출력**:
- 실시간 텍스트 변환 결과 (STT)
- **AI 제안 목록** (주요 메모 항목 제안)
- **AI가 감지한 주요 내용 목록** (시간 + 내용)
- **개인 메모** (각 참석자별 개별 저장)
- **전문용어 및 설명** (용어 사전)
- **관련 회의록 목록** (32건, 관련도 포함)
- 참석자 목록
- **연동**:
- STT 서비스 (UFR-AI-010)
- AI 서비스 (주요 메모 제안 생성, UFR-AI-040)
- AI 서비스 (주요 내용 감지, UFR-AI-040)
- RAG 서비스 (관련 회의록 검색, 전문용어 자동 감지)
- Collaboration 서비스 (실시간 동기화)
- PARTICIPANT 서비스 (메모 저장, UFR-PART-020)
#### 에러 처리
- **마이크 권한 거부**: "마이크 권한이 필요합니다" 토스트 + 설정 안내 링크
- **STT 실패**: "음성 인식에 실패했습니다" 토스트 + 재시도 안내
- **AI 제안 생성 실패**: "AI 제안을 불러올 수 없습니다" 토스트
- **AI 주요 내용 감지 실패**: "AI 주요 내용 감지에 실패했습니다" 토스트 (회의 계속 진행 가능)
- **메모 저장 실패**: "메모 저장에 실패했습니다" 토스트 + 재시도 버튼
- **용어 사전 로드 실패**: "용어 사전을 불러올 수 없습니다" 메시지 표시
- **관련 자료 검색 실패**: "관련 회의록을 찾을 수 없습니다" 메시지 표시
- **참석자 초대 실패**: "초대 링크 전송에 실패했습니다" 토스트 + 재시도 버튼
- **동기화 실패**: "네트워크 연결을 확인해주세요" 토스트
- **회의 종료 실패**: "회의 종료 중 오류가 발생했습니다" 토스트 + 재시도 버튼
---
@@ -1157,27 +1253,34 @@ graph TD
#### 개요
- **목적**: 지난 회의록의 전체 내용 및 상세 정보 확인
- **관련 유저스토리**: UFR-MEET-047, UFR-AI-040
- **관련 유저스토리**: UFR-MEET-047, UFR-AI-040, UFR-MEET-048
- **비즈니스 중요도**: 중간
- **접근 경로**: 대시보드 → "내 회의록" 항목 클릭 또는 Todo관리 → 회의록 링크
- **접근 경로**: 대시보드 → "내 회의록" 항목 클릭
- **권한**: 모든 회의 참석자 (조회 전용)
#### 주요 기능
#### 주요 기능 (MVP 스코프 축소 v1.5.0)
1. 회의 기본 정보 표시
2. **안건별 AI 요약 표시** (안건 최상단)
3. 안건별 상세 내용 표시
4. **참고자료 표시** (안건 하단)
5. Todo 항목 및 진행 상황 표시
5. **Todo 단순 조회** (UFR-MEET-047): 제목, 담당자만 표시 (D-day, 우선순위 라벨 제거)
6. 첨부파일 다운로드
7. 회의록 수정/공유 액션
**변경사항 (v1.5.0)**:
- ❌ 제거: Todo 관리 화면 연동 링크 (화면 자체가 제거됨)
- ❌ 제거: Todo D-day 라벨, 우선순위 배지 표시
- ✅ 변경: Todo는 단순 조회만 가능 (제목 + 담당자 + 마감일만 표시)
- ✅ 변경: "수정" 버튼을 회의 제목 우측으로 이동
#### UI 구성요소
**Mobile (320px~768px)**
- **헤더**
- 뒤로가기 버튼
- 회의 제목
- 메뉴 버튼 (수정, 삭제)
- "수정" 버튼 (회의 제목 우측, 아이콘 또는 텍스트 버튼)
- 메뉴 버튼 (삭제, 공유 등)
- **기본 정보 카드**
- 회의 일시
@@ -1221,14 +1324,12 @@ graph TD
- 결정사항 카드 리스트
- 각 카드: 결정 내용 + 결정자 + 시간 + 배경 설명
- **Todo 진행상황 섹션** (📋)
- **전체 진행률 표시**: 상단에 원형 진행 바 (완료 Todo 개수 / 전체 Todo 개수)
- 진행률 퍼센트 중앙 표시 (예: "60%")
- 색상: Primary 색상 (#4DD5A7)
- 크기: 80px (Desktop), 60px (Mobile)
- 상태별 필터 탭 (전체/시작 전/진행 중/완료)
- 담당자별 그룹화
- 각 Todo: 제목 + 마감일 + 우선순위 배지 (개별 진행률 바 제거)
- **Todo 진행상황 섹션** (📋) - MVP 스코프 축소
- **단순 조회만 제공** (UFR-MEET-047)
- Todo 리스트:
- 각 Todo: 제목 + 담당자 + 마감일만 표시
- ❌ 제거: D-day 라벨, 우선순위 배지, 진행률 바, 상태별 필터
- ❌ 제거: Todo 관리 화면 연동 (클릭 액션 없음)
- **참고자료 섹션** (📚)
- 참고자료 탭 (관련 회의록/프로젝트 문서/이슈 트래커/위키 페이지)
@@ -1237,21 +1338,20 @@ graph TD
- 관련도 점수 배지 (92%, 88% 등)
- 2-3줄 요약
- **Todo 섹션** (강조)
- **Todo 섹션** (단순 조회) - MVP 스코프 축소
- Todo 항목 리스트:
- 체크박스 (완료/미완료)
- Todo 내용
- Todo 내용 (제목)
- 담당자 이름
- 마감일
- 우선순위 배지
- ❌ 제거: 체크박스, 우선순위 배지, D-day 라벨
- **첨부파일 섹션**
- 파일 아이콘 + 파일명
- 다운로드 버튼
- **하단 액션 바** (Fixed)
- "수정" 버튼 (권한 있는 경우만)
- **하단 액션 바** (Fixed) - MVP 스코프 축소
- "공유" 버튼
- ❌ 제거: "수정" 버튼 (헤더로 이동)
**Tablet/Desktop (768px+)**
- **상단**: 탭 네비게이션
@@ -1279,25 +1379,24 @@ graph TD
- 관련도 색상 코딩: 90%+ (초록), 70-89% (노랑), 70% 미만 (회색)
- "더보기" 클릭 → 전체 참고자료 목록 모달
3. **대시보드 탭 인터랙션**
3. **대시보드 탭 인터랙션** - MVP 스코프 축소
- **핵심내용 섹션**:
- 키워드 태그 클릭 → 해당 키워드 관련 안건으로 스크롤
- 통계 항목 클릭 → 상세 정보 툴팁 표시
- **결정사항 섹션**:
- 결정사항 카드 클릭 → 회의록 탭의 해당 안건으로 이동
- 배경 설명 접기/펼치기
- **Todo 진행상황**:
- 필터 탭 클릭 → 해당 상태의 Todo만 표시
- Todo 카드 클릭 → Todo관리 화면으로 이동
- 진행률 바: 실시간 업데이트
- **Todo 진행상황** (단순 조회만):
- ❌ 제거: 필터 탭, 진행률 바, Todo 관리 화면 연동
- Todo는 읽기 전용으로만 표시 (클릭 액션 없음)
- **참고자료 섹션**:
- 탭 전환 (관련 회의록/프로젝트 문서/이슈 트래커/위키 페이지)
- 참고자료 카드 클릭 → 해당 문서로 이동
- 관련도 점수: 배지로 표시 (92%, 88% 등)
4. **Todo 인터랙션**
- Todo 체크박스: 완료 처리 (권한 있는 경우)
- Todo 클릭: Todo관리 화면으로 이동
4. **Todo 인터랙션** - MVP 스코프 축소
- ❌ 제거: Todo 체크박스, Todo 관리 화면 연동
- Todo는 단순 조회만 가능 (클릭 액션 없음)
5. **첨부파일 다운로드**
- 파일명 클릭: 다운로드 시작
@@ -1342,32 +1441,41 @@ graph TD
#### 개요
- **목적**: 지난 회의록 조회 및 수정
- **관련 유저스토리**: UFR-MEET-055, UFR-AI-040, **UFR-TODO-040 (Todo 수정)**
- **관련 유저스토리**: UFR-MEET-055, UFR-AI-040, UFR-COLLAB-020
- **비즈니스 중요도**: 중간
- **접근 경로**: 10-회의록상세조회 → 하단 액션 바 "수정" 버튼 클릭
- **권한 제어**:
- **검증완료 전**: 모든 참석자가 수정 가능
- **검증완료 후**: 회의 생성자만 수정 가능 (참석자는 "수정" 버튼 비활성화)
#### 주요 기능
#### 주요 기능 (MVP 스코프 축소 v1.5.2)
1. 회의 기본 정보 표시 및 수정
- 회의 제목: 수정 가능
- 회의 일시/장소: 읽기 전용 (회의 예약 화면에서만 변경 가능)
- 참석자 관리: 회의 생성자만 추가/삭제 가능
2. **회의록 내용 수정 (안건별)** - 용어 변경: 섹션 → 안건
3. **AI 한줄 요약 표시 (안건별, UFR-AI-036)** - 신규
- 편집 불가능한 AI 한줄 요약 (30자 이내)
- 각 안건 최상단에 표시
4. **AI 상세 요약 수정 (안건별)** - 기존 AI 요약 기능
5. **참고자료 편집** (추가/제거)
6. **Todo 수정 (UFR-TODO-040)** - 회의 생성자만
7. **안건별 검증 (UFR-COLLAB-030)** - 신규
- 안건별 검증 완료 체크박스
- 회의 생성자: 잠금 해제 후 수정 가능
- 참석자: 읽기 전용
8. 자동 저장 (30초 간격)
9. 수정 이력 관리
10. 상태 변경 (검증완료 → 작성중으로 자동 변경)
3. **AI 요약 표시 및 재생성 (안건별, UFR-AI-036)**
- AI 한줄 요약 표시 (30자 이내, 읽기 전용)
- 텍스트 편집 영역에서 안건 내용 수정 가능
- "AI 재생성" 버튼: 텍스트 편집 영역 내용 기반으로 한줄 요약만 재생성 (2-5초 처리)
- 재생성된 한줄 요약은 회의록 상세조회 화면의 대시보드 및 회의록 탭에 즉시 반영
4. **참고자료 편집** (추가/제거)
5. **Todo 단순 조회** (제목 + 담당자 + 마감일만 표시)
6. **안건별 검증 완료 체크박스 (UFR-COLLAB-020)**
- 회의 생성자: 검증 완료 체크박스 활성화, 잠금 해제 후 수정 가능
- 참석자: 검증완료 안건은 읽기 전용
7. 자동 저장 (30초 간격)
8. 수정 이력 관리
9. 상태 변경 (검증완료 → 작성중으로 자동 변경)
**변경사항 (v1.5.2)**:
- ✅ 명칭 변경: "AI 상세 요약" → "AI 요약"
- ✅ 기능 통합: AI 재생성 버튼 클릭 시 텍스트 편집 영역 내용 기반으로 한줄 요약 생성 (UFR-AI-036)
- ❌ 제거: AI 상세 요약 및 한줄 요약 분리 표시 (한줄 요약만 표시)
- ❌ 제거: 실시간 협업 표시 ("편집 중" 표시 제거)
- ❌ 제거: Todo 편집 기능 (체크박스, 담당자/마감일/우선순위 변경, 추가/삭제)
- ❌ 제거: 검증률 표시 및 최종 확정 버튼
- ✅ 정책: Last Write Wins (마지막 저장 우선) 적용
#### UI 구성요소
@@ -1389,45 +1497,35 @@ graph TD
- "참석자 추가" 버튼 (이메일 입력 + 초대)
- 회의록 상태 배지 (자동 관리)
- **편집 화면**
- **편집 화면** (MVP 스코프 축소)
- **안건별 편집 영역** (용어 변경: 섹션 → 안건)
- 각 안건:
- **안건 헤더**
- 안건 제목 (H4, Bold)
- 검증 상태 배지 (검증완료/미검증)
- 편집 중 표시 (동시 편집 시)
- 다른 사용자 아바타 + 이름
- 예: "김민준님 편집 중" (아이콘 + 텍스트)
- **AI 한줄 요약** (편집 불가, UFR-AI-036) - 신규
- 🔒 아이콘 + 30자 이내 한줄 요약
- 읽기 전용 (회색 배경, 민트 그린 좌측 액센트 라인)
- ❌ 제거: "편집 중" 표시 (실시간 협업 기능 제거)
- **AI 요약** (읽기 전용, UFR-AI-036)
- 💡 "AI 요약" 레이블
- AI 한줄 요약 표시 (30자 이내)
- 읽기 전용 영역 (회색 배경, 민트 그린 좌측 액센트 라인)
- 호버 시: "이 내용은 편집할 수 없습니다" 툴팁
- **AI 상세 요약 편집 영역**
- 💡 "AI 상세 요약" 레이블 (명칭 변경)
- 요약 텍스트 편집 필드 (textarea)
- "AI 재생성" 버튼 (요약 다시 생성)
- **텍스트 편집 영역**
- 안건 내용 편집 필드 (textarea)
- 논의 주제, 발언자별 의견, 결정 사항, 보류 사항 등 자유 작성
- "AI 재생성" 버튼: 텍스트 편집 영역 내용 기반으로 AI 요약의 한줄 요약 재생성
- 마지막 수정 시간 표시
- 편집 가능한 텍스트 영역
- 논의 주제
- 발언자별 의견
- 결정 사항
- 보류 사항
- **참고자료 편집 영역**
- 기존 참고자료 목록 (제거 버튼 포함)
- "참고자료 추가" 버튼
- 회의록 검색 및 선택 UI
- **Todo 섹션 편집 영역** (회의 생성자만)
- Todo 목록 표시
- **Todo 섹션 단순 조회** (편집 불가)
- Todo 목록 표시 (읽기 전용)
- 각 Todo 항목:
- 체크박스 (완료 상태)
- Todo 제목
- 담당자 (변경 가능)
- 마감일 (변경 가능)
- 우선순위 (변경 가능)
- "편집" 버튼 (인라인 편집 활성화)
- "삭제" 버튼
- "Todo 추가" 버튼
- **안건별 검증 영역** (UFR-COLLAB-030) - 신규
- 담당자
- 마감일
- ❌ 제거: 체크박스, 우선순위 배지, D-day 라벨, 편집/삭제 버튼
- **안건별 검증 영역** (UFR-COLLAB-020)
- **회의 생성자 화면**:
- 검증 완료 체크박스 (활성화)
- "잠금 해제" 버튼 (검증완료 안건만 표시)
@@ -1456,38 +1554,36 @@ graph TD
- 자동 저장: 30초 간격, 인디케이터 표시
- 수동 저장: "저장" 버튼 클릭
3. **AI 한줄 요약 확인 (UFR-AI-036)** - 신규
3. **AI 한줄 요약 확인 (UFR-AI-036)** - MVP 스코프 축소
- **읽기 전용 표시**:
- 🔒 아이콘으로 편집 불가 명시
- 회색 배경 + 민트 그린 좌측 액센트 라인
- **호버 인터랙션**:
- 툴팁 표시: "이 내용은 편집할 수 없습니다"
- 툴팁 표시: "이 내용은 편집할 수 없습니다. 회의 종료 시 1회만 생성됩니다."
- **위치**: 각 안건 최상단 (안건 제목 바로 아래)
- ❌ 제거: "AI 재생성" 버튼 (한줄 요약은 회의 종료 시 1회만 생성)
4. **AI 상세 요약 편집**
4. **AI 상세 요약 편집** - MVP 스코프 축소
- 요약 텍스트 필드 클릭: 직접 수정 가능
- "AI 재생성" 버튼 클릭:
- 현재 안건 내용 기반으로 상세 요약 재생성
- 현재 안건 내용 기반으로 **상세 요약만** 재생성 (한줄 요약 제외)
- 로딩 인디케이터 표시
- 생성 완료 시 자동 업데이트
- 자동 저장 (30초 간격)
5. **안건별 검증 (UFR-COLLAB-030)** - 신규
5. **안건별 검증 완료 체크박스 (UFR-COLLAB-020)** - MVP 스코프 축소
- **회의 생성자 권한**:
- 검증 완료 체크박스 클릭:
- 체크: 안건 검증 완료 처리 (배지 "검증완료"로 변경)
- 언체크: 미검증 상태로 변경
- "잠금 해제" 버튼 클릭 (검증완료 안건만 표시):
- 확인 다이얼로그: "이 안건의 잠금을 해제하시겠습니까?"
- 확인 시: 안건 편집 가능 상태로 변경
- 확인 시: 안건 검증 완료 체크 해제 → 편집 가능 상태로 변경
- **참석자 화면**:
- 검증완료 안건: 🔒 "읽기 전용" 배지 표시
- 안내 텍스트: "(잠금됨 · 회의 생성자만 수정 가능)"
- 모든 입력 필드 비활성화 (disabled)
- **검증률 계산 및 표시**:
- 검증률 = 검증 완료된 안건 수 / 전체 안건 수
- 헤더에 검증률 표시 (예: "검증률: 70% (7/10)")
- 모든 안건 검증 완료 시 "최종 확정" 버튼 활성화
- ❌ 제거: 검증률 계산 및 표시, "최종 확정" 버튼
6. **참고자료 편집**
- "참고자료 추가" 버튼 클릭:
@@ -1497,98 +1593,72 @@ graph TD
- 제거 버튼 (X): 참고자료 목록에서 제거
- 순서 변경: 드래그하여 순서 조정 (선택)
7. **Todo 섹션 편집 (UFR-TODO-040)** (회의 생성자만)
- **권한 제어**:
- 회의 생성자만 Todo 섹션 편집 가능
- 일반 참석자는 조회만 가능 (편집 버튼 숨김)
- **편집 버튼 클릭**:
- 인라인 편집 모드 활성화
- **수정 가능 항목** (회의 생성자 권한):
- ✏️ Todo 제목
- 👤 담당자 (드롭다운 선택, 참석자 목록)
- 📅 마감일 (날짜 선택기)
- 🎯 우선순위 (high/medium/low)
- "저장" 버튼: 수정 완료
- "취소" 버튼: 편집 모드 취소
- **수정 완료 시**:
- "Todo가 수정되었습니다" 토스트 메시지
- 회의록 자동 저장
- 담당자 변경 시: 이전/새 담당자에게 알림 발송
- 마감일 변경 시: 캘린더 자동 업데이트
- **Todo 추가**:
- "Todo 추가" 버튼 클릭
- Todo 정보 입력 모달 (제목, 담당자, 마감일, 우선순위)
- 저장 시 Todo 목록에 추가
- **Todo 삭제**:
- "삭제" 버튼 클릭
- 확인 다이얼로그 ("삭제하시겠습니까?")
- 삭제 시 Todo 목록에서 제거
- 담당자에게 삭제 알림 발송
7. **Todo 섹션 단순 조회** - MVP 스코프 축소
- ❌ 제거: Todo 편집/추가/삭제 기능 전체 제거
- Todo는 읽기 전용으로만 표시 (제목 + 담당자 + 마감일)
- 모든 사용자 (생성자 포함)에게 조회만 가능
8. **상태 변경**
8. **상태 변경** - MVP 스코프 축소
- 확정완료 회의록 수정 시: 자동으로 "작성중" 상태로 변경
- 모든 안건 검증 완료 시: "확정완료"로 변경 제안
- ❌ 제거: "확정완료"로 변경 제안 (검증률 기능 제거로 인해)
9. **저장 로직** - MVP 스코프 축소
- **"저장" 버튼 클릭 시**:
- 검증완료된 안건: 저장 스킵
- 미검증 안건: 저장 진행
- **저장 결과 알림**:
- "N개 안건이 저장되었습니다"
- "M개 안건은 검증완료 상태로 저장되지 않았습니다"
- 저장 불가 안건 목록 표시
- **자동 저장** (30초 간격):
- 미검증 안건만 자동 저장
- 검증완료 안건은 자동 저장 스킵
9. **안건 기반 충돌 해결 (UFR-COLLAB-020)**
10. **안건 기반 충돌 해결 (UFR-COLLAB-020)** - MVP 스코프 축소
- **안건 기반 충돌 방지 메커니즘**:
- **다른 안건 동시 편집**: 충돌 없음
- 참석자 A가 안건 1 편집
- 참석자 A가 안건 1 편집
- 참석자 B가 안건 2 편집 가능
- 양쪽 모두 정상 저장 및 동기화
- 양쪽 모두 정상 저장
- **동일 안건 내 다른 필드 편집**: 자동 병합
- 참석자 A가 안건 1의 "상세 요약" 편집
- 참석자 B가 안건 1의 "관련회의록" 편집
- 양쪽 변경 사항 자동 병합
- **동일 안건 검증 완료 체크로 충돌 방지**:
- 검증완료된 안건: 편집 불가 (회의 생성자만 잠금 해제 가능)
- 미검증 안건: Last Write Wins (마지막 저장 우선)
- **동일 필드 동시 수정**: Last Write Wins
- 마지막에 저장된 변경 사항이 적용
- 덮어쓰기 경고: "다른 사용자가 이미 수정했습니다. 최신 내용을 확인하세요"
- 선택 옵션: 최신 내용 확인 / 내 변경 사항 유지
- 별도 경고 없이 덮어쓰기
- **편집 중 표시**:
- 다른 사용자가 편집 중인 안건 표시
- 편집자 아바타 + 이름 실시간 표시
- 예: "김민준님이 이 안건을 편집 중입니다" + 아바타
- 편집 시작 시 해당 안건에 브로드캐스트
- 편집 종료 시 표시 제거
- ❌ 제거: 실시간 "편집 중" 표시
- ❌ 제거: 충돌 경고 모달 및 선택 옵션
- **충돌 경고 모달**:
- 제목: "동시 수정 감지"
- 메시지: "다른 사용자가 이미 이 내용을 수정했습니다"
- 옵션 버튼:
- "최신 내용 보기" (Primary): 다른 사용자 변경사항 로드
- "내 변경사항 유지" (Secondary): 현재 내용 유지 (덮어쓰기)
#### 데이터 요구사항
#### 데이터 요구사항 (MVP 스코프 축소)
- **입력**:
- 회의록 ID (조회)
- 수정 내용 (안건 ID, 내용) - 용어 변경: 섹션 → 안건
- **AI 한줄 요약** (읽기 전용, 입력 불가) - 신규
- **AI 한줄 요약** (읽기 전용, 입력 불가)
- **AI 상세 요약 수정** (안건 ID, 요약 내용)
- **참고자료 변경** (추가/제거할 회의록 ID)
- **안건별 검증 상태** (안건 ID, 검증 여부) - 신규
- **안건별 검증 상태** (안건 ID, 검증 여부)
- **출력**:
- 회의록 목록 (필터/정렬/검색 결과)
- 수정 결과 (성공/실패)
- **AI 한줄 요약** (회의 종료 시 생성, 편집 불가) - 신규
- **AI 상세 요약 재생성 결과**
- **AI 한줄 요약** (회의 종료 시 생성, 편집 불가)
- **AI 상세 요약 재생성 결과** (한줄 요약 제외)
- 수정 이력 (누가, 언제, 무엇을)
- **검증률** (검증 완료된 안건 수 / 전체 안건 수) - 신규
- **연동**: Meeting 서비스, AI 서비스 (UFR-AI-010, UFR-AI-036, UFR-AI-040), Collaboration 서비스 (UFR-COLLAB-030)
- ❌ 제거: 검증률 출력
- **연동**: Meeting 서비스, AI 서비스 (UFR-AI-010, UFR-AI-036, UFR-AI-040), PARTICIPANT 서비스 (UFR-COLLAB-020)
#### 에러 처리
#### 에러 처리 (MVP 스코프 축소)
- **권한 없음**: "본인이 작성한 회의록만 수정할 수 있습니다"
- **자동 저장 실패**: "네트워크 연결을 확인해주세요. 로컬에 임시 저장됩니다"
- **AI 요약 재생성 실패**: "요약 생성에 실패했습니다. 수동으로 작성해주세요"
- **참고자료 검색 실패**: "회의록을 검색할 수 없습니다"
- **충돌 발생**:
- 안건 기반 충돌 방지로 최소화
- 동일 필드 동시 수정 시: "다른 사용자가 이미 수정했습니다" 경고 모달
- 선택 옵션: 최신 내용 확인 / 내 변경사항 유지
- 병합 실패 시: "병합 중 오류가 발생했습니다" 에러 메시지
- **검증완료 안건 저장 시도**:
- 저장 결과 알림: "N개 안건이 저장되었습니다. M개 안건은 검증완료 상태로 저장되지 않았습니다"
- 저장 불가 안건 목록 표시
- **삭제 실패**: "회의록 삭제에 실패했습니다"
- ❌ 제거: 충돌 경고 모달 (Last Write Wins 적용으로 인해)
---
@@ -1795,6 +1865,8 @@ graph TD
- 필터링 결과 없음: "조건에 맞는 회의록이 없습니다"
- 전체 회의록 없음: "회의록이 없습니다. 첫 회의를 시작해보세요!" + 회의 시작 버튼
[↑ 목차로 돌아가기](#목차)
---
## 공통 UI 컴포넌트
@@ -1853,6 +1925,8 @@ graph TD
- **Desktop (768px+)**:
- 프로필 아이콘 숨김 (사이드바 하단 영역 사용)
[↑ 목차로 돌아가기](#목차)
---
## 공통 에러 메시지 표준
@@ -1892,6 +1966,8 @@ graph TD
- **로깅**: 오류 상세 정보를 서버로 전송 (Sentry)
- **적용 화면**: 전체
[↑ 목차로 돌아가기](#목차)
---
## 화면 간 전환 및 네비게이션
@@ -1923,6 +1999,8 @@ graph TD
- 특정 Todo 직접 접근: `/todo/{todoId}`
- 회의록 공유 링크: `/share/{shareToken}`
[↑ 목차로 돌아가기](#목차)
---
## 반응형 설계 전략
@@ -1974,6 +2052,8 @@ graph TD
- Lazy Loading: 뷰포트 진입 시 로딩
- 최적화: WebP 포맷, 적절한 압축
[↑ 목차로 돌아가기](#목차)
---
## 접근성 보장 방안
@@ -2011,6 +2091,8 @@ graph TD
- 자동 테스트: Lighthouse, axe DevTools
- 수동 테스트: 키보드 네비게이션, 스크린 리더 (NVDA, JAWS, VoiceOver)
[↑ 목차로 돌아가기](#목차)
---
## 성능 최적화 방안
@@ -2062,13 +2144,14 @@ graph TD
- **STT 지연 시간**: < 1s
- **실시간 동기화 지연**: < 500ms
[↑ 목차로 돌아가기](#목차)
---
## 변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
|------|------|--------|----------|
| 1.4.20 | 2025-10-25 | 이미준, 강지수 | 유저스토리 v2.3.0 반영<br>- 회의 종료 화면 정책 명확화 (확인 전용, 바로 최종 확정 옵션 상세화)<br>- UFR-MEET-050: 최종 확정 2가지 시나리오 설명 추가<br>- UFR-COLLAB-020: 안건 기반 충돌 해결 메커니즘 상세 추가<br>- 실시간 협업 충돌 방지 정책 강화 |
| 1.0 | 2025-10-21 | 이미준 | 최초 작성 - 11개 화면 설계 완료 |
| 1.1 | 2025-10-21 | 이미준 | AI 요약 및 참고자료 기능 추가<br>- 05-회의진행: AI 회의 내용 요약 자동 생성 및 참고자료 자동 연결 추가<br>- 10-회의록상세조회: 섹션별 AI 요약 표시 및 참고자료 영역 추가<br>- 11-회의록수정: AI 요약 수정 및 참고자료 편집 기능 추가<br>- 관련 유저스토리: UFR-AI-040 (관련 회의록 자동 연결) |
| 1.1.1 | 2025-10-21 | 이미준 | 회의록 상세 화면 구조 개선 (프로토타입 기반)<br>- 10-회의록상세조회: 탭 기반 네비게이션 추가 (회의록/대시보드)<br>- 대시보드 탭 추가: 핵심내용, 결정사항, Todo 진행상황, 참고자료 섹션<br>- 참고자료 관련도 점수 표시 (백분율 + 색상 코딩)<br>- 참고자료 카테고리 탭 (관련 회의록/프로젝트 문서/이슈 트래커/위키 페이지)<br>- 참조: design-gappa/uiux/prototype 파일 (11-회의록대시보드.html, 05-회의진행.html) |
@@ -2102,7 +2185,12 @@ 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 (실시간 주요 메모 추천 명시 부족 개선) |
| 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% 반영 |
| 1.4.20 | 2025-10-25 | 이미준, 강지수 | 유저스토리 v2.3.0 반영<br>- 회의 종료 화면 정책 명확화 (확인 전용, 바로 최종 확정 옵션 상세화)<br>- UFR-MEET-050: 최종 확정 2가지 시나리오 설명 추가<br>- UFR-COLLAB-020: 안건 기반 충돌 해결 메커니즘 상세 추가<br>- 실시간 협업 충돌 방지 정책 강화 |
| 1.5.1 | 2025-10-27 | 강지수 | MVP 스코프 축소 v2.4.0 반영 (4개 화면 수정)<br>- **02-대시보드**: Todo 위젯 및 통계 제거 (UFR-USER-020 반영)<br> - Todo 위젯 전체 제거 (나의 Todo 섹션 삭제)<br> - 통계 카드: "나의 Todo" 제거, "작성중 회의록" 유지 (2개 항목)<br> - 네비게이션: 하단 네비게이션 및 사이드바에서 Todo 관리 메뉴 제거<br> - Desktop 통계 그리드: 2개 항목만 표시<br>- **05-회의진행**: "AI 제안" 탭 → "AI 기반 메모" 탭 기능 변경<br> - 메모 입력창 + 저장 버튼 추가<br> - AI가 감지한 주요 내용 리스트 표시 (시간 + 내용)<br> - 각 참석자별 개별 저장, 다른 참석자 메모 볼 수 없음<br> - 메모는 회의 종료 전까지만 표시/편집 가능<br> - 에러 처리: AI 주요 내용 감지 실패, 메모 저장 실패 추가<br>- **10-회의록상세조회**: Todo 단순 조회 기능으로 변경<br> - Todo는 제목 + 담당자 + 마감일만 표시<br> - D-day 라벨, 우선순위 배지, 진행률 바, 상태별 필터 제거<br> - Todo 관리 화면 연동 링크 제거 (화면 자체가 제거됨)<br> - "수정" 버튼을 헤더로 이동<br>- **11-회의록수정**: 실시간 협업 기능 제거, 안건 기반 충돌 방지 강화<br> - "편집 중" 표시 제거 (실시간 협업 기능 제거)<br> - Todo 편집/추가/삭제 기능 전체 제거 (단순 조회만 가능)<br> - AI 한줄 요약 재생성 불가 (회의 종료 시 1회만 생성)<br> - 검증률 표시 및 최종 확정 버튼 제거<br> - 저장 로직 추가: 검증완료 안건 저장 스킵, 저장 결과 알림<br> - 안건별 검증 완료 체크박스로 충돌 방지 (Last Write Wins 적용)<br> - 에러 처리: 충돌 경고 모달 제거 (LWW로 인해) |
| 1.5.2 | 2025-10-27 | 강지수 | AI 요약 기능 통합 및 단순화 (유저스토리 v2.4.0 반영)<br>- **11-회의록수정**: AI 요약 기능 통합<br> - 명칭 변경: "AI 상세 요약" → "AI 요약"<br> - AI 요약 영역: AI 한줄 요약만 표시 (30자 이내, 읽기 전용)<br> - 텍스트 편집 영역: 안건 내용 자유 작성 (논의 주제, 발언자별 의견, 결정 사항 등)<br> - "AI 재생성" 버튼: 텍스트 편집 영역 내용 기반으로 AI 요약의 한줄 요약 재생성 (2-5초 처리)<br> - 재생성된 한줄 요약은 회의록 상세조회 화면의 대시보드 및 회의록 탭에 즉시 반영<br> - AI 상세 요약 및 한줄 요약 분리 표시 제거<br>- **프로토타입 UI 개선**:<br> - AI 재생성 버튼 스타일 통일: btn-secondary → btn-primary (다른 화면과 일관성)<br> - 안건별 검증완료 UI 단순화: 참석자는 체크박스만, 회의 생성자는 검증완료 시 잠금해제 버튼 표시<br> - .creator-only CSS 클래스 추가: data-is-creator 속성 기반 표시 제어<br>- **관련 유저스토리**: UFR-AI-036 (AI 한줄요약 확인 및 재생성), UFR-MEET-055 (안건별 검증), UFR-COLLAB-030 (충돌 방지) |
| 1.5.3 | 2025-10-27 | 강지수 | Todo 추가/편집 권한 정책 명확화 (유저스토리 v2.4.1 반영)<br>- **10-회의록상세조회**: Todo 추가/편집 권한 정책 추가 (대시보드 탭)<br> - "추가" 버튼: 모든 회의 참석자에게 노출 (Todo 리스트 우측 상단)<br> - "편집(✏️)" 버튼: 회의 생성자에게만 노출 (각 Todo 항목 우측)<br> - Todo 추가 모달: 제목, 담당자, 마감일 입력 (모든 참석자)<br> - Todo 편집 모달: 제목, 담당자, 마감일 수정 (회의 생성자만)<br> - 담당자 필드: 추가 시 또는 생성자의 편집 시만 표시<br>- **프로토타입 UI 개선**: 10-회의록상세조회.html<br> - Todo 추가/편집 모달 바텀시트 스타일 통일 (모바일: 하단 슬라이드 업, 데스크톱: 중앙 모달)<br> - .creator-only 클래스 적용하여 편집 버튼 권한별 표시/숨김 처리<br> - JavaScript initPage() 함수에서 회의 생성자 여부 확인 후 creator-only 요소 제어<br> - Todo 추가 성공: "담당자에게 알림이 전송되었습니다" → "캘린더가 업데이트되었습니다" 순차 토스트<br> - Todo 편집 성공: 담당자 변경 시 알림, 마감일 변경 시 캘린더 업데이트 토스트<br>- **관련 유저스토리**: UFR-MEET-047 (회의록상세조회), Todo 권한 정책 신규 추가 |
[↑ 목차로 돌아가기](#목차)
---
+203
View File
@@ -0,0 +1,203 @@
# 유저스토리 목록 (v2.4.1)
최종 수정일: 2025-10-27
## 📋 전체 유저스토리 목록
| ID | 서비스 | 역할 | 제목 | As a | I want to | So that | 상태 |
|---|---|---|---|---|---|---|---|
| UFR-USER-010 | User | 사용자 | 로그인 | 사용자로서 | 사번과 비밀번호로 로그인 | 시스템에 접근하기 위해 | ✅ |
| UFR-USER-020 | User | 사용자 | 대시보드 | 사용자로서 | 대시보드를 조회 | 나의 회의 현황을 파악하기 위해 | ✅ |
| UFR-MEET-010 | Meeting | 회의 생성자 | 회의예약 | 회의 생성자로서 | 회의를 예약하고 참석자를 초대 | 회의를 효율적으로 준비하기 위해 | ✅ |
| UFR-MEET-015 | Meeting | 회의 참석자 | 회의진행 중 참석자 초대 | 회의 참석자로서 | 실시간으로 참석자를 초대 | 회의 중 추가 참석자가 필요할 때 | ✅ |
| UFR-MEET-020 | Meeting | 회의 생성자 | 템플릿선택 | 회의 생성자로서 | 회의 유형에 맞는 템플릿을 선택 | 회의록을 효율적으로 작성하기 위해 | ✅ |
| UFR-MEET-030 | Meeting | 회의 생성자 | 회의시작 | 회의 생성자로서 | 회의를 시작하고 음성 녹음을 준비 | 회의를 시작하고 회의록을 작성하기 위해 | ✅ v2.4.1 개선 |
| UFR-MEET-040 | Meeting | 회의 생성자 | 회의종료 | 회의 생성자로서 | 회의를 종료하고 요약 내용을 확인한 후 다음 단계를 선택 | 회의를 종료하고 회의록을 정리하기 위해 | ✅ v2.4.1 수정 |
| UFR-MEET-050 | Meeting | 회의 생성자 | 최종확정 | 회의 생성자로서 | 모든 안건을 검증하고 최종 회의록을 확정 | 회의록을 완성하기 위해 | ✅ |
| UFR-MEET-046 | Meeting | 회의 참석자 | 회의록목록조회 | 회의 참석자로서 | 회의록 목록을 조회하고 필터링 | 참여한 회의록들을 효율적으로 관리하기 위해 | ✅ |
| UFR-MEET-047 | Meeting | 회의 참석자 | 회의록상세조회 | 회의 참석자로서 | 지난 회의록의 상세 정보와 전체 내용을 한눈에 확인 | 회의록을 효율적으로 검토하기 위해 | ✅ |
| UFR-MEET-055 | Meeting | 회의 참석자 | 회의록수정 | 회의 참석자로서 | 검증이 완료되지 않은 안건을 수정하고 검증완료 체크 | 회의록의 정확성을 보장하기 위해 | ✅ |
| UFR-AI-010 | AI | 회의 참석자 | 회의록자동작성 | 회의 참석자로서 | AI가 발언 내용을 실시간으로 정리하고 회의 종료 시 전체 안건을 요약 | 회의록 작성 부담을 줄이기 위해 | ✅ |
| UFR-AI-020 | AI | 회의 참석자 | Todo자동추출 | 회의 참석자로서 | AI가 안건별 내용에서 Todo 항목을 자동으로 추출하고 기본값을 설정 | 회의 후 실행 사항을 명확히 하기 위해 | ✅ |
| UFR-AI-030 | AI | 회의 참석자 | 실시간AI제안 | 회의 참석자로서 | AI가 실시간으로 주요 내용을 분석하여 제안 | 회의 중 놓치는 내용을 최소화하기 위해 | ✅ |
| UFR-AI-036 | AI | 회의 참석자 | AI한줄요약 | 회의 참석자로서 | AI가 생성한 한줄 요약을 확인하고 필요 시 재생성 | 각 안건의 핵심을 빠르게 파악하기 위해 | ✅ |
| UFR-AI-040 | AI | 회의 참석자 | 관련회의록연결 | 회의 참석자로서 | AI가 같은 폴더 내 관련 있는 과거 회의록을 자동으로 찾아 연결하고 유사 내용을 요약 | 이전 회의 내용을 쉽게 참조하기 위해 | ✅ v2.4.1 개선 |
| UFR-STT-010 | STT | 회의 참석자 | 음성녹음인식 | 회의 참석자로서 | 음성이 실시간으로 녹음되고 인식 | 발언 내용이 자동으로 기록되기 위해 | ✅ |
| UFR-STT-020 | STT | 시스템 | 텍스트변환 | 회의록 시스템으로서 | 음성을 텍스트로 변환 | 인식된 발언을 회의록에 기록하기 위해 | ✅ |
| UFR-RAG-010 | AI (RAG) | 회의 참석자 | 전문용어감지 | 회의 참석자로서 | 전문용어가 자동으로 감지되고 맥락에 맞는 설명을 제공 | 업무 지식이 없어도 회의록을 정확히 작성하기 위해 | ✅ |
| UFR-RAG-020 | AI (RAG) | 회의 참석자 | 맥락기반용어설명 | 회의 참석자로서 | 관련 회의록과 업무 이력을 바탕으로 실용적인 설명을 제공 | 전문용어를 맥락에 맞게 이해하기 위해 | ✅ |
| UFR-COLLAB-010 | Meeting | 회의 참석자 | 회의록수정동기화 | 회의 참석자로서 | 회의록을 수정하고 실시간으로 다른 참석자와 동기화 | 회의록을 함께 검증하기 위해 | ✅ |
| UFR-COLLAB-020 | Meeting | 회의 참석자 | 충돌해결 | 회의 참석자로서 | 안건별로 충돌 없이 편집 | 동시 수정 상황에서도 내용을 잃지 않기 위해 | ✅ |
| UFR-COLLAB-030 | Meeting | 회의 참석자 | 검증완료 | 회의 참석자로서 | 각 안건을 검증하고 완료 표시 | 회의록의 정확성을 보장하기 위해 | ✅ |
| UFR-NOTI-010 | Notification | 시스템 | 알림발송 | Notification 시스템으로서 | 주기적으로 알림 대상을 확인하여 이메일을 발송 | 사용자에게 중요한 이벤트를 알리기 위해 | ✅ |
| UFR-PART-010 | Meeting | 회의 참석자 | 회의입장 | 회의 참석자로서 | 대시보드에서 "참여하기" 버튼으로 회의에 입장 | 예정된 회의에 참여하기 위해 | ✅ v2.4.1 신규 |
| UFR-PART-020 | Meeting | 회의 참석자 | AI기반메모작성 | 회의 참석자로서 | AI가 추천한 주요 내용을 메모 입력창에 추가하고 편집 | 중요한 내용을 메모로 기록하기 위해 | ✅ v2.4.1 신규 |
| UFR-PART-030 | Meeting | 회의 참석자 | 회의중도퇴장 | 회의 참석자로서 | "나가기" 버튼으로 회의에서 퇴장 | 회의를 중간에 나가야 할 때 | ✅ v2.4.1 신규 |
| UFR-HOST-010 | Meeting | 회의 생성자 | 회의종료권한 | 회의 생성자로서 | "회의 종료" 버튼으로만 회의를 종료 | 회의를 마무리하기 위해 | ✅ v2.4.1 신규 |
| UFR-HOST-020 | Meeting | 회의 생성자 | 녹음제어권한 | 회의 생성자로서 | 녹음 일시정지/재개/종료 권한을 가짐 | 녹음을 관리하기 위해 | ✅ v2.4.1 신규 |
| UFR-TERM-010 | AI | 회의 참석자 | 용어자동감지 | 회의 참석자로서 | AI가 자동으로 감지한 용어를 "용어" 탭에서 확인 | 전문용어를 이해하기 위해 | ✅ v2.4.1 신규 |
| UFR-TERM-020 | AI | 회의 참석자 | 회사용어사전 | 회의 참석자로서 | 회사 용어 사전에 등록된 용어를 우선 표시 | 회사 특화 용어를 정확히 이해하기 위해 | ✅ v2.4.1 신규 |
| UFR-TERM-030 | AI | 관리자 | 용어관리 | 관리자로서 | 용어 사전을 등록/수정 | 회사 특화 용어를 관리하기 위해 | ✅ v2.4.1 신규 |
---
## 📊 서비스별 유저스토리 개수
| 서비스 | 개수 | 유저스토리 ID |
|---|:---:|---|
| **User** | 2 | UFR-USER-010, UFR-USER-020 |
| **Meeting** | 16 | UFR-MEET-010, UFR-MEET-015, UFR-MEET-020, UFR-MEET-030, UFR-MEET-040, UFR-MEET-050, UFR-MEET-046, UFR-MEET-047, UFR-MEET-055, UFR-COLLAB-010, UFR-COLLAB-020, UFR-COLLAB-030, UFR-PART-010, UFR-PART-020, UFR-PART-030, UFR-HOST-010, UFR-HOST-020 |
| **AI** | 9 | UFR-AI-010, UFR-AI-020, UFR-AI-030, UFR-AI-036, UFR-AI-040, UFR-RAG-010, UFR-RAG-020, UFR-TERM-010, UFR-TERM-020, UFR-TERM-030 |
| **STT** | 2 | UFR-STT-010, UFR-STT-020 |
| **Notification** | 1 | UFR-NOTI-010 |
| **전체** | **32** | - |
---
## 👥 역할별 유저스토리 분류
### 회의 생성자 (Host) - 7개
| ID | 제목 | 핵심 기능 |
|---|---|---|
| UFR-MEET-010 | 회의예약 | 회의 예약 및 참석자 초대 |
| UFR-MEET-020 | 템플릿선택 | 회의 템플릿 선택 |
| UFR-MEET-030 | 회의시작 | 회의 시작 및 녹음 준비 |
| UFR-MEET-040 | 회의종료 | 회의 종료 및 요약 확인 |
| UFR-MEET-050 | 최종확정 | 회의록 최종 확정 |
| UFR-HOST-010 | 회의종료권한 | 회의 종료 전용 권한 |
| UFR-HOST-020 | 녹음제어권한 | 녹음 제어 전용 권한 |
### 회의 참석자 (Participant) - 19개
| ID | 제목 | 핵심 기능 |
|---|---|---|
| UFR-MEET-015 | 회의진행 중 참석자 초대 | 실시간 참석자 추가 |
| UFR-MEET-046 | 회의록목록조회 | 회의록 목록 조회 및 필터링 |
| UFR-MEET-047 | 회의록상세조회 | 회의록 상세 정보 조회 |
| UFR-MEET-055 | 회의록수정 | 회의록 수정 및 검증 |
| UFR-AI-010 | 회의록자동작성 | AI 회의록 자동 작성 |
| UFR-AI-020 | Todo자동추출 | AI Todo 자동 추출 |
| UFR-AI-030 | 실시간AI제안 | 실시간 AI 주요 내용 제안 |
| UFR-AI-036 | AI한줄요약 | AI 한줄 요약 생성 |
| UFR-AI-040 | 관련회의록연결 | AI 관련 회의록 자동 연결 |
| UFR-STT-010 | 음성녹음인식 | 음성 실시간 녹음 및 인식 |
| UFR-RAG-010 | 전문용어감지 | 전문용어 자동 감지 |
| UFR-RAG-020 | 맥락기반용어설명 | 맥락 기반 용어 설명 |
| UFR-COLLAB-010 | 회의록수정동기화 | 실시간 회의록 동기화 |
| UFR-COLLAB-020 | 충돌해결 | 안건별 충돌 방지 |
| UFR-COLLAB-030 | 검증완료 | 안건 검증 완료 표시 |
| UFR-PART-010 | 회의입장 | 회의 입장 |
| UFR-PART-020 | AI기반메모작성 | AI 추천 메모 작성 |
| UFR-PART-030 | 회의중도퇴장 | 회의 중도 퇴장 |
| UFR-TERM-010 | 용어자동감지 | 용어 자동 감지 및 표시 |
| UFR-TERM-020 | 회사용어사전 | 회사 특화 용어 우선 표시 |
### 관리자 (Admin) - 1개
| ID | 제목 | 핵심 기능 |
|---|---|---|
| UFR-TERM-030 | 용어관리 | 용어 사전 등록/수정 |
### 시스템 (System) - 3개
| ID | 제목 | 핵심 기능 |
|---|---|---|
| UFR-STT-020 | 텍스트변환 | 음성-텍스트 변환 |
| UFR-NOTI-010 | 알림발송 | 이메일 알림 자동 발송 |
| UFR-USER-010 | 로그인 | 사용자 인증 |
| UFR-USER-020 | 대시보드 | 대시보드 조회 |
---
## 🆕 v2.4.1 변경 사항 (2025-10-27)
### 신규 유저스토리 (8개)
| ID | 제목 | 분류 | 설명 |
|---|---|---|---|
| UFR-PART-010 | 회의입장 | 참석자 공통 | 대시보드에서 "참여하기" 버튼으로 회의 입장 |
| UFR-PART-020 | AI기반메모작성 | 참석자 공통 | AI 추천 주요 내용을 메모 입력창에 추가 및 편집 |
| UFR-PART-030 | 회의중도퇴장 | 참석자 공통 | "나가기" 버튼으로 회의 퇴장 |
| UFR-HOST-010 | 회의종료권한 | 생성자 전용 | 생성자만 "회의 종료" 버튼 사용 가능 |
| UFR-HOST-020 | 녹음제어권한 | 생성자 전용 | 생성자만 녹음 일시정지/재개/종료 가능 |
| UFR-TERM-010 | 용어자동감지 | AI 기능 | AI가 자동으로 감지한 용어를 "용어" 탭에 표시 |
| UFR-TERM-020 | 회사용어사전 | AI 기능 | 회사 용어 사전(JSON) 우선 표시 |
| UFR-TERM-030 | 용어관리 | 관리 기능 | 관리자가 용어 사전 등록/수정 |
### 수정된 유저스토리 (3개)
| ID | 제목 | 수정 내용 |
|---|---|---|
| UFR-MEET-040 | 회의종료 | 회의 종료 권한을 생성자 전용으로 명확화, "확인 전용" 화면 정책 추가, 3가지 옵션 명확화 (회의록 수정/바로 최종 확정/대시보드) |
| UFR-MEET-030 | 회의시작 | 회의 진입 경로 2가지 명시 (바로시작, 참여하기), AI 제안 탭에 개인 메모 작성 영역 추가 (참석자별 독립) |
| UFR-AI-040 | 관련회의록연결 | 유사 내용 요약 추가 (최대 3개 추천, 관련도 퍼센트, 3-5문장 요약, 성능 목표 1초 이내) |
---
## 🔍 주요 기능별 유저스토리 매핑
### 회의 생명주기 (Meeting Lifecycle)
1. **회의 예약**: UFR-MEET-010
2. **템플릿 선택**: UFR-MEET-020
3. **회의 시작**: UFR-MEET-030, UFR-PART-010
4. **회의 진행**: UFR-STT-010, UFR-AI-010, UFR-AI-030, UFR-PART-020
5. **회의 종료**: UFR-MEET-040, UFR-HOST-010
6. **회의록 수정**: UFR-MEET-055, UFR-COLLAB-010, UFR-COLLAB-020
7. **최종 확정**: UFR-MEET-050, UFR-COLLAB-030
### AI 기능 (AI Features)
- **회의록 자동 작성**: UFR-AI-010
- **Todo 자동 추출**: UFR-AI-020
- **실시간 AI 제안**: UFR-AI-030
- **AI 한줄 요약**: UFR-AI-036
- **관련 회의록 연결**: UFR-AI-040
- **전문 용어 감지**: UFR-RAG-010, UFR-TERM-010
- **맥락 기반 용어 설명**: UFR-RAG-020, UFR-TERM-020
### 실시간 협업 (Real-time Collaboration)
- **참석자 초대**: UFR-MEET-015
- **수정 동기화**: UFR-COLLAB-010
- **충돌 해결**: UFR-COLLAB-020
- **검증 완료**: UFR-COLLAB-030
### 권한 관리 (Authorization)
- **생성자 전용**: UFR-HOST-010, UFR-HOST-020
- **참석자 공통**: UFR-PART-010, UFR-PART-020, UFR-PART-030
- **관리자 전용**: UFR-TERM-030
---
## 📝 유저스토리 작성 규칙
본 문서의 유저스토리는 다음 형식을 따릅니다:
```
UFR-{SERVICE}-{NUMBER}: [{기능명}] {역할}로서 | 나는, {목적}를 위해 | {행동}을 하고 싶다.
```
### 서비스 코드
- **USER**: 사용자 인증 및 대시보드
- **MEET**: 회의 및 회의록 관리
- **AI**: AI 기반 자동화 기능
- **STT**: 음성-텍스트 변환
- **RAG**: 벡터 검색 및 맥락 기반 설명
- **COLLAB**: 실시간 협업 (Meeting 서비스에 통합)
- **NOTI**: 알림 발송
- **PART**: 회의 참석자 공통 기능
- **HOST**: 회의 생성자 전용 기능
- **TERM**: 용어 관리 기능
---
## 📌 백로그 및 향후 계획
### Phase 2 후보 기능
- 회의 템플릿 커스터마이징
- Todo 대시보드 및 칸반 보드
- 회의록 버전 관리 및 변경 이력
- 회의 통계 및 분석 대시보드
- 다국어 지원 (음성 인식 및 UI)
---
## 📚 참고 문서
- 유저스토리 원본: [design/userstory.md](./userstory.md)
- UI/UX 설계서: [design/uiux/uiux.md](./uiux/uiux.md)
- 프로토타입: [design/uiux/prototype/](./uiux/prototype/)
+108 -67
View File
@@ -1,10 +1,25 @@
# AI기반 회의록 작성 및 이력 관리 개선 서비스 - 유저스토리 (v2.4.0)
# AI기반 회의록 작성 및 이력 관리 개선 서비스 - 유저스토리 (v2.4.1)
- [AI기반 회의록 작성 및 이력 관리 개선 서비스 - 유저스토리 (v2.4.0)](#ai기반-회의록-작성-및-이력-관리-개선-서비스---유저스토리-v240)
- [차별화 전략](#차별화-전략)
- [1. 기본 기능 (Hygiene Factors)](#1-기본-기능-hygiene-factors)
- [2. 핵심 차별화 포인트 (Differentiators)](#2-핵심-차별화-포인트-differentiators)
- [마이크로서비스 구성](#마이크로서비스-구성)
## 목차
- [차별화 전략](#차별화-전략)
- [1. 기본 기능 (Hygiene Factors)](#1-기본-기능-hygiene-factors)
- [2. 핵심 차별화 포인트 (Differentiators)](#2-핵심-차별화-포인트-differentiators)
- [마이크로서비스 구성](#마이크로서비스-구성)
- [유저스토리 - USER & MEETING 서비스](#유저스토리---user--meeting-서비스)
- [USER 서비스](#user-서비스)
- [MEETING 서비스](#meeting-서비스)
- [유저스토리 - AI, STT, RAG, COLLAB, NOTIFICATION 서비스](#유저스토리-v230---ai-stt-rag-collab-todo-notification-서비스)
- [AI 서비스](#ai-서비스)
- [STT 서비스](#stt-서비스)
- [RAG 서비스 (AI 서비스에 통합)](#rag-서비스-ai-서비스에-통합)
- [COLLAB 서비스 (Meeting 서비스에 통합)](#collab-서비스-meeting-서비스에-통합)
- [NOTIFICATION 서비스](#notification-서비스-신규)
- [MVP 개선 사항 (v2.3.1)](#mvp-개선-사항-v231)
- [회의 참석자 권한 및 기능 단순화](#회의-참석자-권한-및-기능-단순화)
- [회의 생성자 전용 기능](#회의-생성자-전용-기능)
- [용어 설명 기능 (MVP 단순화)](#용어-설명-기능-mvp-단순화)
- [기존 유저스토리 수정](#기존-유저스토리-수정)
- [문서 이력](#문서-이력)
---
@@ -44,7 +59,7 @@
- 업무 이력 통합
---
# 유저스토리 v2.3.0 - USER & MEETING 서비스
# 유저스토리 - USER & MEETING 서비스
## USER 서비스
@@ -135,25 +150,23 @@
2. 회의 제목 입력 (최대 100자)
3. 날짜 선택 (오늘 이후 날짜, 달력 UI)
4. 시작/종료 시간 선택 (15분 단위 커스텀 시간 선택기)
5. (선택) 종일 회의 토글 활성화 시 시간 입력 비활성화
6. 온라인/오프라인 회의 선택 (토글)
7. 장소 입력 (최대 200자)
5. 온라인/오프라인 회의 선택 (토글)
6. 장소 입력 (최대 200자)
- 오프라인: 예) 본사 2층 대회의실
- 온라인: 예) Zoom, Google Meet + 회의 링크 입력 또는 자동 생성
8. 참석자 추가 (현재 사용자는 기본 포함)
7. 참석자 추가 (현재 사용자는 기본 포함)
- "참석자 추가" 버튼 클릭
- 검색 모달에서 이름 또는 이메일로 검색
- 사용자 선택하여 추가
- 칩으로 표시, X 버튼으로 제거 가능 (본인 제외)
9. (선택) 안건 입력 (텍스트 영역)
10. "임시저장" 버튼 또는 "예약 완료" 버튼 클릭
8. (선택) 안건 입력 (텍스트 영역)
9. "임시저장" 버튼 또는 "예약 완료" 버튼 클릭
**입력:**
- 회의 제목: 텍스트 입력, 필수, 최대 100자, 문자 카운터 표시
- 날짜: date 타입, 필수, 오늘 이후 날짜만 선택 가능, 달력 아이콘(📅) 표시
- 시작 시간: 커스텀 시간 선택기 (readonly), 필수, 15분 단위 (00, 15, 30, 45)
- 종료 시간: 커스텀 시간 선택기 (readonly), 필수, 15분 단위
- 종일 회의: 토글 스위치 (선택)
- 온라인 회의: 토글 스위치 (선택)
- 장소: 텍스트 입력, 선택, 최대 200자, 문자 카운터 표시
- 회의 링크: URL 입력, 선택, 온라인 회의인 경우에만 표시, "자동 생성" 버튼 제공
@@ -218,15 +231,18 @@
### UFR-MEET-020: [템플릿선택] 회의 생성자로서 | 나는, 회의록을 효율적으로 작성하기 위해 | 회의 유형에 맞는 템플릿을 선택하고 싶다.
**템플릿선택 진입 경로:**
- **경로 1**: 대시보드(02-대시보드.html) → "바로시작" FAB 버튼 → 템플릿 선택(04-템플릿선택.html)
- **경로 2**: 회의예약 (03-회의예약.html) → 템플릿 선택(04-템플릿선택.html)
-
**수행절차:**
1. 대시보드에서 "바로시작" FAB 버튼 클릭
2. 템플릿 선택 화면(04-템플릿선택.html) 표시
3. 4가지 템플릿 중 선택 또는 "건너뛰기" 선택
1. 위 경로 중 하나를 통해 템플릿 선택 화면(04-템플릿선택.html) 진입
2. 4가지 템플릿 선택 또는 "건너뛰기" 선택
- 일반 회의: 회의 개요, 논의 사항, 결정 사항, 액션 아이템
- 스크럼 회의: 어제 한 일, 오늘 할 일, 블로커/이슈
- 킥오프 회의: 프로젝트 개요, 목표 및 범위, 역할 및 책임, 일정 및 마일스톤
- 주간 회의: 지난주 성과, 이번주 계획, 주요 이슈, 다음 액션
4. 선택 완료 시 회의 시작 (05-회의진행.html로 이동)
3. 선택 완료 시 회의 시작 (05-회의진행.html로 이동)
**입력:**
- 템플릿 선택: 4가지 중 1개 선택 또는 건너뛰기
@@ -242,6 +258,7 @@
**관련 유저스토리:**
- UFR-USER-020: 대시보드 조회
- UFR-MEET-010: 회의예약
- UFR-MEET-030: 회의시작
---
@@ -260,11 +277,14 @@
5. 웨이브폼 애니메이션 표시 (녹음 상태 시각화)
6. 탭 네비게이션으로 기능 전환:
- 참석자: 참석자 목록 및 실시간 초대
- AI 제안: 실시간 AI 분석 결과 및 메모 추가
- 용어사전: 자동 추출된 용어 및 검색
- 관련회의록: 자동 연결된 이전 회의록
7. 회의 메모 작성 (하단 고정 메모 영역)
8. 일시정지 또는 회의 종료 버튼 클릭
- AI 제안: 실시간 AI 분석 결과 및 개인 메모 작성
- AI가 인식한 주요 내용 표시
- 참석자별 개인 메모 작성 영역 (수동 저장만 지원)
- 용어사전: 실시간 AI 자동 인식된 용어 및 검색
- 관련회의록: 실시간 AI 자동 연결된 이전 회의록
7. 하단 고정 버튼 (역할별 차별화)
- 회의 생성자: [일시정지/녹음재개] + [회의 종료]
- 회의 참석자: [회의 나가기]
**입력:**
- 녹음 시작/일시정지: 버튼 클릭
@@ -275,16 +295,22 @@
- 헤더: 회의 제목, 녹음 상태 (녹음 중/일시정지), 경과 시간
- 웨이브폼 애니메이션: 녹음 상태 시각화
- 참석자 탭: 참석자 목록, 초대 버튼
- AI 제안 탭: AI 분석 카드, "메모에 추가" 버튼
- AI 제안 탭:
- AI가 인식한 주요 내용 리스트
- 개인 메모 작성 영역 (참석자별 독립)
- 저장 버튼 (수동 저장만)
- 용어사전 탭: 자동 추출된 용어, 검색 기능
- 관련회의록 탭: 자동 연결된 이전 회의록 목록
- 하단 고정 버튼: 일시정지, 회의 종료
- 하단 고정 버튼:
- 회의 생성자: [일시정지/녹음재개] + [회의 종료]
- 회의 참석자: [회의 나가기]
**예외처리:**
- 녹음 권한 없음: "마이크 권한이 필요합니다" 에러 메시지
- 네트워크 오류: "녹음 중 오류가 발생했습니다" 에러 메시지
- 일시정지 확인: "일시정지하시겠습니까?" 확인 모달
- 종료 확인: "회의를 종료하시겠습니까?" 확인 모달
- 회의 종료 확인 (생성자): "회의를 종료하시겠습니까? 모든 참석자의 회의가 종료됩니다" 확인 모달
- 회의 나가기 확인 (참석자): "회의에서 나가시겠습니까? 저장하지 않은 메모는 삭제됩니다" 확인 모달
**관련 유저스토리:**
- UFR-MEET-020: 템플릿선택
@@ -464,12 +490,30 @@
- AI 상세 요약
- 관련회의록 링크
4. "수정" 버튼 클릭 시 회의록 수정 화면으로 이동
5. Todo 리스트 영역 (대시보드 탭):
- "추가" 버튼: 모든 참석자에게 노출, 클릭 시 Todo 추가 모달 표시
- Todo 항목별 "편집" 버튼: 회의 생성자에게만 노출
- Todo 추가 모달: 제목, 담당자, 마감일 입력
- Todo 편집 모달: 제목, 마감일 수정 (회의 생성자만 담당자 변경 가능)
**입력:**
- 탭 클릭: 대시보드 / 회의록
- Todo 추가 클릭: "추가" 버튼
- Todo 편집 클릭: Todo 항목별 "편집(✏️)" 버튼 (회의 생성자만)
- Todo 추가/편집 모달 입력:
- 제목: 텍스트, 필수
- 담당자: 드롭다운 선택, 필수 (추가 시 또는 편집 시 생성자만)
- 마감일: 날짜 선택, 필수
**출력/결과:**
- 헤더: 회의 제목, "수정" 버튼 (제목 텍스트 바로 옆에 배치, 권한에 따라 표시)
- Todo 리스트 (대시보드 탭):
- "추가" 버튼: 모든 참석자에게 표시
- Todo 항목별 "편집(✏️)" 버튼: 회의 생성자만 표시
- Todo 추가 성공: "Todo가 추가되었습니다" 성공 메시지 → "담당자에게 알림이 전송되었습니다" 정보 메시지 → "캘린더가 업데이트되었습니다" 정보 메시지
- Todo 편집 성공: "Todo가 수정되었습니다" 성공 메시지
- 담당자 변경 시: "이전 담당자와 새 담당자에게 알림이 전송되었습니다" 정보 메시지
- 마감일 변경 시: "캘린더가 업데이트되었습니다" 정보 메시지
- 대시보드 탭:
- 통계, 키워드, 핵심내용, 결정사항, Todo 진행상황, 관련회의록
- Todo 카드: 제목, 담당자, 마감일만 표시 (D-day, 우선순위 라벨 없음)
@@ -480,6 +524,18 @@
- 회의록 조회 실패: "회의록 조회 중 오류가 발생했습니다" 에러 메시지
- Todo 없음: "등록된 Todo가 없습니다" 빈 상태 표시
- 관련회의록 없음: "관련 회의록이 없습니다" 빈 상태 표시
- Todo 추가/편집 시 필수 입력 누락: "제목/담당자/마감일을 입력해주세요" 에러 메시지
- Todo 편집 권한 없음 (일반 참석자): 편집 버튼 미표시
**Todo 권한 정책 (v2.4.1 신규):**
- **Todo 추가**: 모든 회의 참석자 가능
- "추가" 버튼 모든 참석자에게 노출
- 추가 모달에서 제목, 담당자, 마감일 입력
- 담당자는 회의 참석자 중 선택
- **Todo 편집**: 회의 생성자만 가능
- 편집(✏️) 버튼은 회의 생성자에게만 노출
- 편집 모달에서 제목, 담당자, 마감일 수정 가능
- 일반 참석자는 편집 버튼이 보이지 않음
**관련 유저스토리:**
- UFR-MEET-046: 회의록목록조회
@@ -682,58 +738,42 @@
---
### UFR-AI-035: [섹션AI요약] 회의 참석자로서 | 나는, 작성한 섹션 내용을 쉽게 요약하기 위해 | 버튼 클릭으로 AI가 섹션 내용을 요약해주기를 원한다.
### UFR-AI-036: [AI한줄요약] 회의 참석자로서 | 나는, 각 안건의 핵심을 빠르게 파악하기 위해 | AI가 생성한 한줄 요약을 확인하고 필요 시 재생성하고 싶다.
**수행절차:**
1. 회의록 수정 화면(11-회의록수정.html)에서 안건 상세 요약 편집
2. "재생성" 버튼 클릭
3. AI가 해당 안건의 전체 내용 (메모, STT 텍스트) 분석
4. 2-3문장 요약 생성 (2-5초 처리)
5. 기존 상세 요약 대체
**시나리오 1: 자동 생성 (회의 종료 시)**
1. 회의 종료 시 AI가 안건별로 한줄 요약 생성
2. 안건 관련 메모 및 STT 텍스트를 분석하여 30자 이내로 핵심 내용 압축
3. 회의 종료 화면에 안건별 한줄 요약 표시 (읽기 전용)
**시나리오 2: 수동 재생성 (회의록 수정 시)**
1. 회의록 수정 화면(11-회의록수정.html)에서 안건별 "AI 요약" 영역 확인
2. 텍스트 편집 영역에서 안건 내용 수정
3. "AI 재생성" 버튼 클릭
4. AI가 수정된 텍스트 편집 영역 내용을 분석하여 한줄 요약 생성 (2-5초 처리)
5. "AI 요약" 영역에 새로운 한줄 요약 표시
6. "재생성되었습니다" 토스트 메시지 표시
7. 재생성된 한줄 요약은 회의록 상세조회 화면의 대시보드 및 회의록 탭에 즉시 반영
**입력:**
- 안건 제목
- 안건 관련 메모 및 STT 텍스트
- 자동 생성: 안건 관련 메모 및 STT 텍스트
- 재생성: 텍스트 편집 영역의 안건 내용
- 재생성 버튼 클릭 이벤트
**출력/결과:**
- 로딩 상태: "재생성 중..." 표시
- 재생성 완료: 새로운 AI 상세 요약 (2-3문장)
- 토스트 메시지: "재생성되었습니다"
- 자동 저장 트리거
**예외처리:**
- AI 재생성 실패: "재생성 중 오류가 발생했습니다" 에러 메시지
- 네트워크 오류: 재시도 로직 또는 기존 요약 유지
- 타임아웃: "재생성 시간이 초과되었습니다. 다시 시도해주세요" 안내
**관련 유저스토리:**
- UFR-MEET-055: 회의록수정
- UFR-AI-010: 회의록자동작성
---
### UFR-AI-036: [AI한줄요약] 회의 참석자로서 | 나는, 각 안건의 핵심을 빠르게 파악하기 위해 | AI가 생성한 편집 불가능한 한줄 요약을 확인하고 싶다.
**수행절차:**
1. 회의 종료 시 AI가 각 안건별로 한줄 요약 생성
2. 30자 이내로 핵심 내용 압축
3. 회의 종료 화면 및 회의록 수정 화면에 표시
4. 읽기 전용 필드로 표시 (편집 불가)
5. 회의록 상세 조회 시 안건별로 한줄 요약 표시
**입력:**
- 안건의 AI 상세 요약
- 안건 관련 메모 및 STT 텍스트
**출력/결과:**
- AI 한줄 요약 (30자 이내, 읽기 전용)
- 회의 종료 화면, 회의록 수정 화면, 회의록 상세 조회 화면에 표시
- AI 한줄 요약 (30자 이내)
- 회의 종료 화면: 안건별 한줄 요약 (읽기 전용)
- 회의록 수정 화면: "AI 요약" 영역에 한줄 요약 표시 및 재생성 기능
- 회의록 상세조회 화면: 대시보드 및 회의록 탭에 한줄 요약 표시
- 재생성 시: "재생성 중..." 로딩 → 한줄 요약 업데이트 → "재생성되었습니다" 토스트
**예외처리:**
- 한줄 요약 생성 실패: 안건 제목 사용 또는 "요약 없음" 표시
- 30자 초과: 자동 트림 처리
- AI 재생성 실패: "재생성 중 오류가 발생했습니다" 에러 메시지
- 네트워크 오류: 재시도 로직 또는 기존 요약 유지
- 타임아웃: "재생성 시간이 초과되었습니다. 다시 시도해주세요" 안내
**관련 유저스토리:**
- UFR-AI-010: 회의록자동작성
@@ -1395,7 +1435,8 @@
| 버전 | 날짜 | 작성자 | 변경 내용 |
|------|------|--------|-----------|
| v2.4.0 | 2025-10-27 | 팀 전체 | • MVP 스코프 축소: Todo 관리 기능 제거<br>• UFR-USER-020 수정: 대시보드에서 "나의 Todo" 제거, "작성중 회의록" 추가<br>• UFR-PART-020 변경: AI주요내용체크 → AI기반메모작성 (메모 입력창 + AI 추천)<br>• UFR-AI-010 개선: 회의록 생성 시 참석자 메모 참조<br>• UFR-MEET-055 개선: 회의록 수정 시 실시간 협업 제거, 검증완료 체크로 보호<br>• TODO 서비스 전체 제거 (UFR-TODO-010/030/040)<br>• NOTIFICATION 서비스: Todo 관련 알림 제거<br>• 네비게이션 간소화: Todo 관리 메뉴 제거 (대시보드, 회의록만 유지) |
| v2.4.1 | 2025-10-27 | 팀 전체 | • UFR-MEET-047 개선: Todo 추가/편집 권한 정책 명확화<br>&nbsp;&nbsp;- Todo 추가: 모든 회의 참석자 가능 ("추가" 버튼 모든 참석자에게 노출)<br>&nbsp;&nbsp;- Todo 편집: 회의 생성자만 가능 (편집 버튼은 생성자에게만 노출)<br>&nbsp;&nbsp;- Todo 추가 모달: 제목, 담당자, 마감일 입력 (모든 참석자)<br>&nbsp;&nbsp;- Todo 편집 모달: 제목, 담당자, 마감일 수정 (생성자만, 바텀시트 스타일)<br>• 프로토타입 UI 개선: 10-회의록상세조회.html<br>&nbsp;&nbsp;- Todo 추가 모달과 편집 모달 바텀시트 스타일 통일<br>&nbsp;&nbsp;- 편집 버튼에 creator-only 클래스 적용하여 권한별 표시/숨김 처리 |
| v2.4.0 | 2025-10-27 | 팀 전체 | • MVP 스코프 축소: Todo 관리 기능 제거<br>• AI 요약 기능 통합 및 단순화<br>• UFR-USER-020 수정: 대시보드에서 "나의 Todo" 제거, "작성중 회의록" 추가<br>• UFR-PART-020 변경: AI주요내용체크 → AI기반메모작성 (메모 입력창 + AI 추천)<br>• UFR-AI-010 개선: 회의록 생성 시 참석자 메모 참조<br>• UFR-MEET-055 개선: 회의록 수정 시 실시간 협업 제거, 검증완료 체크로 보호<br>&nbsp;&nbsp;- 프로토타입 UI 개선: 안건별 검증완료 UI 단순화 (참석자: 체크박스만, 생성자: 검증완료 시 잠금해제 버튼)<br>• TODO 서비스 전체 제거 (UFR-TODO-010/030/040)<br>• NOTIFICATION 서비스: Todo 관련 알림 제거<br>• 네비게이션 간소화: Todo 관리 메뉴 제거 (대시보드, 회의록만 유지)<br>• UFR-MEET-030 개선: AI 제안 탭 내 개인 메모 작성 기능 명확화 (수동 저장만), 하단 고정 버튼 역할별 차별화 (생성자: 일시정지/재개+종료, 참석자: 나가기)<br>• UFR-AI-035 삭제: 섹션AI요약 제거 (중복 기능)<br>• UFR-AI-036 개선: AI 한줄요약 확인 및 재생성 기능 통합<br>&nbsp;&nbsp;- 회의 종료 시: 자동 생성 (읽기 전용)<br>&nbsp;&nbsp;- 회의록 수정 시: 텍스트 편집 영역 내용 기반 재생성 기능 추가<br>&nbsp;&nbsp;- "AI 상세요약" → "AI 요약"으로 명칭 변경<br>&nbsp;&nbsp;- 회의록 상세조회 화면의 대시보드 및 회의록 탭에 한줄요약 표시<br>&nbsp;&nbsp;- 프로토타입 UI 개선: AI 재생성 버튼 스타일 통일 (btn-secondary → btn-primary)<br>• UFR-COLLAB-030 개선: 안건 기반 충돌 방지 메커니즘 (검증완료 체크로 보호)|
| v2.3.1 | 2025-10-27 | 팀 전체 | • MVP 개선: 회의 참석자 권한 단순화<br>• 신규 유저스토리: UFR-PART-010/020/030 (참석자 공통), UFR-HOST-010/020 (생성자 전용)<br>• 신규 유저스토리: UFR-TERM-010/020/030 (용어 기능 MVP 단순화)<br>• UFR-MEET-040 수정: 회의 종료 권한 생성자 전용으로 명확화<br>• UFR-MEET-030 개선: 회의 진입 경로 2가지 명시 (바로시작, 참여하기)<br>• UFR-AI-040 개선: 관련 회의록 유사 내용 요약 추가 (최대 3개, 퍼센트 표시, 3-5문장 요약)<br>• 메모 기능 단순화: 체크박스 방식으로 변경<br>• 용어 설명 단순화: JSON 용어 사전 방식 도입 |
| v2.3.0 | 2025-10-24 | 이미준 | • 프로토타입 분석을 통한 유저스토리 전면 재정비<br>• 신규 유저스토리 추가: UFR-MEET-015 (참석자 실시간 초대), UFR-NOTI-010 (알림 발송)<br>• 알림 아키텍처 폴링 방식으로 통일 (실시간 발송 → 주기적 폴링)<br>• 10개 프로토타입 화면 반영 완료<br>• 마이크로서비스 구성 재정의 (User, Meeting, STT, AI, Notification)<br>• 기존 24개 유저스토리 ID 승계 및 정리 |
| v2.2.0 | 2025-10-23 | 이미준 | 이전 버전 |
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff