mirror of
https://github.com/hwanny1128/HGZero.git
synced 2026-06-13 10:39:11 +00:00
Merge branch 'main' into feature/stt-ai - 로그 파일 충돌 해결
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
Vendored
+9
-2
@@ -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: '확정완료' };
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 권한 정책 신규 추가 |
|
||||
|
||||
[↑ 목차로 돌아가기](#목차)
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user