07-회의종료 화면 UI/UX 개선 (유저스토리 v2.1.1 반영)

[주요 변경사항]
- 편집 불가 정책 적용: 확인 전용 화면으로 변경
  - Todo 수정 버튼 제거
  - 읽기 전용 안내 박스 추가
  - 체크박스 disabled 처리

- 3가지 선택 옵션 추가:
  1. 대시보드로 이동 (작성중 상태 저장)
  2. 회의록 수정 (11-회의록수정.html)
  3. 바로 최종 확정 (모든 안건 자동 검증)

- 안건별 AI 요약 구조화:
  - AI 한줄 요약 (30자, 편집 불가, 🔒 아이콘)
  - 상세 요약 정리 (논의/의견/결정/보류)
  - 안건별 Todo 자동 추출 결과 표시
  - 확장/축소 인터랙션 구현

- 공유 버튼 제거 (유저스토리 v2.0.1 반영)

[관련 유저스토리]
- UFR-MEET-040: 회의종료 (확인 전용, 3가지 옵션)
- UFR-MEET-050: 최종확정 (바로 확정 시나리오 추가)
- UFR-AI-010: 회의록자동작성 (안건별 요약)
- UFR-AI-036: AI한줄요약 (편집 불가)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
yabo0812 2025-10-24 13:02:30 +09:00
parent 86fd30f4cc
commit 45578b0f7b
2 changed files with 425 additions and 207 deletions

View File

@ -113,13 +113,99 @@
transition: width 1s ease; transition: width 1s ease;
} }
/* Todo 리스트 */ /* 안건 카드 */
.todo-list-item { .agenda-card {
padding: var(--space-md);
background: var(--white); background: var(--white);
border-radius: var(--radius-md); border-radius: var(--radius-md);
box-shadow: var(--shadow-sm); box-shadow: var(--shadow-sm);
margin-bottom: var(--space-md);
overflow: hidden;
border: 1px solid var(--gray-200);
}
.agenda-header {
padding: var(--space-md);
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
background: var(--gray-50);
}
.agenda-header:hover {
background: var(--gray-100);
}
.agenda-title {
font-size: var(--font-h4);
font-weight: var(--font-weight-bold);
color: var(--gray-900);
margin-bottom: var(--space-xs);
}
.ai-summary-short {
background: var(--gray-100);
border-left: 4px solid var(--primary);
padding: var(--space-sm) var(--space-md);
margin-top: var(--space-sm);
border-radius: var(--radius-sm);
font-size: var(--font-small);
color: var(--gray-700);
display: flex;
align-items: center;
gap: var(--space-sm);
}
.ai-summary-short .lock-icon {
color: var(--gray-500);
font-size: 16px;
}
.expand-icon {
font-size: 20px;
color: var(--gray-500);
transition: transform 0.3s ease;
}
.agenda-card.expanded .expand-icon {
transform: rotate(180deg);
}
.agenda-content {
display: none;
padding: var(--space-md);
border-top: 1px solid var(--gray-200);
}
.agenda-card.expanded .agenda-content {
display: block;
}
.agenda-section {
margin-bottom: var(--space-md);
}
.agenda-section-title {
font-size: var(--font-small);
font-weight: var(--font-weight-bold);
color: var(--gray-500);
margin-bottom: var(--space-xs);
text-transform: uppercase;
}
.agenda-section-content {
font-size: var(--font-body);
color: var(--gray-700);
line-height: 1.6;
}
/* Todo 리스트 (읽기 전용) */
.todo-list-item {
padding: var(--space-md);
background: var(--gray-50);
border-radius: var(--radius-md);
margin-bottom: var(--space-sm); margin-bottom: var(--space-sm);
opacity: 0.8;
} }
.todo-header { .todo-header {
@ -129,10 +215,15 @@
margin-bottom: var(--space-sm); margin-bottom: var(--space-sm);
} }
.todo-checkbox {
margin-right: var(--space-sm);
cursor: not-allowed;
}
.todo-content { .todo-content {
flex: 1; flex: 1;
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium);
color: var(--gray-900); color: var(--gray-700);
} }
.todo-meta { .todo-meta {
@ -143,83 +234,58 @@
color: var(--gray-500); color: var(--gray-500);
} }
/* 체크리스트 */ /* 하단 액션 바 - 3개 버튼 배치 */
.checklist { .action-bar {
background: var(--gray-100); position: fixed;
bottom: 0;
left: 0;
right: 0;
background: var(--white);
padding: var(--space-md); padding: var(--space-md);
border-radius: var(--radius-md); box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
margin-bottom: var(--space-md);
}
.checklist-item {
display: flex; display: flex;
align-items: center;
gap: var(--space-sm); gap: var(--space-sm);
padding: var(--space-sm) 0; z-index: 100;
color: var(--success);
font-size: var(--font-small);
} }
.checklist-item::before { .action-bar .btn {
content: '✓';
font-weight: var(--font-weight-bold);
}
/* 하단 액션 바 - common.css에서 기본 스타일 적용됨 */
/* 이 화면만 버튼 크기 비율 조정: 공유(1) : 수정(1) : 대시보드(4) */
.action-bar .btn-secondary {
flex: 1; flex: 1;
} }
.action-bar .btn-primary { .action-bar .btn-primary {
flex: 4; flex: 2; /* 바로 최종 확정 버튼 강조 */
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.stats-grid { .stats-grid {
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
} }
.action-bar {
position: static;
box-shadow: none;
justify-content: center;
gap: var(--space-md);
}
.action-bar .btn {
flex: 0 1 200px;
}
.action-bar .btn-primary {
flex: 0 1 250px;
}
} }
/* 날짜 입력 필드 래퍼 - 달력 아이콘 보호 */ .readonly-notice {
.date-input-wrapper { background: var(--warning-light);
position: relative; border: 1px solid var(--warning);
} border-radius: var(--radius-md);
padding: var(--space-md);
.date-input-wrapper input[type="date"] { margin-bottom: var(--space-lg);
position: relative; font-size: var(--font-small);
z-index: 1; color: var(--warning-dark);
} text-align: center;
/* 달력 아이콘을 별도 요소로 표시 */
.date-input-wrapper::after {
content: '📅';
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
font-size: 18px;
z-index: 3;
}
/* 네이티브 달력 아이콘 숨김 */
.date-input-wrapper input[type="date"]::-webkit-calendar-picker-indicator {
position: absolute;
right: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
z-index: 2;
/* Edge 브라우저 캘린더 팝업에 그림자 추가 */
filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.2));
}
/* Edge 브라우저용 포커스 시 하단 테두리 강조 */
.date-input-wrapper input[type="date"]:focus {
box-shadow: 0 0 0 3px rgba(77, 213, 167, 0.15),
0 4px 0 0 var(--primary);
} }
</style> </style>
</head> </head>
@ -232,6 +298,11 @@
<p class="meeting-title">2025년 1분기 제품 기획 회의</p> <p class="meeting-title">2025년 1분기 제품 기획 회의</p>
</div> </div>
<!-- 읽기 전용 안내 -->
<div class="readonly-notice">
🔒 이 화면은 <strong>확인 전용</strong>입니다. 내용을 수정하려면 "회의록 수정" 버튼을 클릭하세요.
</div>
<!-- 통계 카드 그리드 --> <!-- 통계 카드 그리드 -->
<div class="stats-grid"> <div class="stats-grid">
<div class="stat-card"> <div class="stat-card">
@ -243,8 +314,8 @@
<div class="stat-label">참석자</div> <div class="stat-label">참석자</div>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<div class="stat-value" id="sectionsValue">0</div> <div class="stat-value" id="agendasValue">0</div>
<div class="stat-label">섹션</div> <div class="stat-label">안건</div>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<div class="stat-value" id="todosValue">0</div> <div class="stat-value" id="todosValue">0</div>
@ -271,97 +342,128 @@
<div class="speaker-stats" id="speakerStats"></div> <div class="speaker-stats" id="speakerStats"></div>
</div> </div>
<!-- AI Todo 추출 결과 --> <!-- 안건별 AI 요약 -->
<div class="card mb-md"> <div class="card mb-md">
<div class="card-header"> <h3 class="card-title">안건별 AI 요약</h3>
<h3 class="card-title">AI가 추출한 Todo</h3> <div id="agendaList"></div>
<button class="btn btn-ghost btn-sm" onclick="openModal('todoEditModal')">수정</button>
</div>
<div id="todoList"></div>
</div> </div>
<!-- 최종 확정 섹션 -->
<div class="card card-highlight mb-md">
<h3 class="card-title mb-md">최종 회의록 확정</h3>
<div class="checklist mb-md">
<div class="checklist-item">회의 제목 작성</div>
<div class="checklist-item">참석자 목록 작성</div>
<div class="checklist-item">주요 논의 내용 작성</div>
<div class="checklist-item">결정 사항 작성</div>
</div>
<button class="btn btn-primary" style="width: 100%;" onclick="confirmMeeting()">
최종 회의록 확정
</button>
</div>
<!-- 하단 액션 바 -->
<div class="action-bar">
<button class="btn btn-secondary" onclick="navigateTo('11-회의록수정.html')">
수정
</button>
<button class="btn btn-primary" onclick="navigateTo('02-대시보드.html')">
대시보드로 이동
</button>
</div> </div>
</div>
<!-- Todo 편집 모달 --> <!-- 하단 액션 바 (3가지 선택 옵션) -->
<div class="modal-overlay" id="todoEditModal"> <div class="action-bar">
<div class="modal"> <button class="btn btn-ghost" onclick="navigateTo('02-대시보드.html')">
<div class="modal-header"> 대시보드
<h3 class="modal-title">Todo 편집</h3> </button>
<button class="modal-close">×</button> <button class="btn btn-secondary" onclick="navigateTo('11-회의록수정.html')">
</div> 회의록 수정
<div class="modal-body"> </button>
<div class="form-group"> <button class="btn btn-primary" onclick="confirmMeetingDirectly()">
<label class="form-label">Todo 내용</label> 바로 최종 확정
<input type="text" class="form-control" value="API 명세서 작성"> </button>
</div>
<div class="form-group">
<label class="form-label">담당자</label>
<select class="form-control">
<option>이준호</option>
<option>박서연</option>
<option>김민준</option>
</select>
</div>
<div class="form-group">
<label class="form-label">마감일</label>
<div class="date-input-wrapper">
<input type="date" class="form-control" value="2025-10-23">
</div>
</div>
<div class="form-group">
<label class="form-label">우선순위</label>
<select class="form-control">
<option value="high">높음</option>
<option value="medium">보통</option>
<option value="low">낮음</option>
</select>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('todoEditModal')">취소</button>
<button class="btn btn-primary" onclick="saveTodoEdit()">저장</button>
</div>
</div> </div>
</div> </div>
<script src="common.js"></script> <script src="common.js"></script>
<script> <script>
// 샘플 안건 데이터
const SAMPLE_AGENDAS = [
{
id: 'agenda-1',
title: '1. 신제품 기획 방향성',
aiSummaryShort: '타겟 고객을 20-30대로 설정, UI/UX 개선 집중',
details: {
discussion: '신제품의 주요 타겟 고객층을 20-30대 직장인으로 설정하고, 기존 제품 대비 UI/UX를 대폭 개선하기로 함',
opinions: [
{ speaker: '김민준', opinion: '타겟 고객층을 명확히 설정하여 마케팅 전략 수립 필요' },
{ speaker: '박서연', opinion: 'UI/UX 개선에 AI 기술 적용 검토' }
],
decisions: ['타겟 고객: 20-30대 직장인', 'UI/UX 개선을 최우선 과제로 설정'],
pending: []
},
todos: [
{
title: '시장 조사 보고서 작성',
assignee: SAMPLE_MEETINGS[0].participants[0],
dueDate: '2025-11-01',
priority: 'high'
},
{
title: 'UI/UX 개선안 초안 작성',
assignee: SAMPLE_MEETINGS[0].participants[1],
dueDate: '2025-11-05',
priority: 'medium'
}
]
},
{
id: 'agenda-2',
title: '2. 예산 편성 및 일정',
aiSummaryShort: '총 예산 5억, 개발 기간 6개월 확정',
details: {
discussion: '신제품 개발을 위한 총 예산을 5억원으로 책정하고, 개발 기간은 6개월로 확정함',
opinions: [
{ speaker: '이준호', opinion: '개발 기간 6개월은 타이트하므로 우선순위 명확화 필요' },
{ speaker: '최유진', opinion: '예산 배분은 개발 60%, 마케팅 40%로 제안' }
],
decisions: ['총 예산: 5억원', '개발 기간: 6개월', '예산 배분: 개발 60%, 마케팅 40%'],
pending: ['세부 일정 확정은 다음 회의에서 논의']
},
todos: [
{
title: '세부 개발 일정 수립',
assignee: SAMPLE_MEETINGS[0].participants[2],
dueDate: '2025-10-28',
priority: 'high'
}
]
},
{
id: 'agenda-3',
title: '3. 기술 스택 및 개발 방향',
aiSummaryShort: 'React 기반 프론트엔드, AI 챗봇 기능 추가',
details: {
discussion: '프론트엔드는 React 기반으로 개발하고, 고객 지원을 위한 AI 챗봇 기능을 추가하기로 함',
opinions: [
{ speaker: '박서연', opinion: 'AI 챗봇은 GPT-4 기반으로 개발 제안' },
{ speaker: '이준호', opinion: 'React 외에 Next.js 도입 검토 필요' }
],
decisions: ['프론트엔드: React 기반', 'AI 챗봇 기능 추가', 'Next.js 도입 검토'],
pending: ['AI 챗봇 학습 데이터 확보 방안']
},
todos: [
{
title: 'AI 챗봇 프로토타입 개발',
assignee: SAMPLE_MEETINGS[0].participants[1],
dueDate: '2025-11-10',
priority: 'medium'
},
{
title: 'Next.js 도입 검토 보고서',
assignee: SAMPLE_MEETINGS[0].participants[3],
dueDate: '2025-11-03',
priority: 'low'
}
]
}
];
// 페이지 초기화 // 페이지 초기화
function initPage() { function initPage() {
// 통계 카운트 애니메이션 // 통계 카운트 애니메이션
animateCounter('durationValue', 90); animateCounter('durationValue', 90);
animateCounter('participantsValue', 4); animateCounter('participantsValue', 4);
animateCounter('sectionsValue', 3); animateCounter('agendasValue', SAMPLE_AGENDAS.length);
animateCounter('todosValue', 5);
// Todo 전체 개수 계산
const totalTodos = SAMPLE_AGENDAS.reduce((sum, agenda) => sum + (agenda.todos?.length || 0), 0);
animateCounter('todosValue', totalTodos);
// 발언 통계 렌더링 // 발언 통계 렌더링
renderSpeakerStats(); renderSpeakerStats();
// Todo 리스트 렌더링 // 안건 리스트 렌더링
renderTodoList(); renderAgendaList();
} }
// 카운터 애니메이션 // 카운터 애니메이션
@ -416,42 +518,117 @@
}, 100); }, 100);
} }
// Todo 리스트 렌더링 // 안건 리스트 렌더링
function renderTodoList() { function renderAgendaList() {
const todos = SAMPLE_TODOS.filter(todo => todo.meetingId === 'meeting-001'); const container = $('#agendaList');
const container = $('#todoList');
todos.forEach(todo => { SAMPLE_AGENDAS.forEach(agenda => {
const statusInfo = getTodoStatusInfo(todo); // 안건 카드
const item = createElement('div', { className: 'todo-list-item' }, ` const card = createElement('div', {
<div class="todo-header"> className: 'agenda-card',
<div class="todo-content">${todo.title}</div> id: `agenda-${agenda.id}`,
${createBadge(todo.priority === 'high' ? '높음' : todo.priority === 'medium' ? '보통' : '낮음', onclick: `toggleAgenda('${agenda.id}')`
`priority-${todo.priority}`)} });
</div>
<div class="todo-meta"> // 헤더
${createAvatar(todo.assignee, 'sm')} const header = createElement('div', { className: 'agenda-header' }, `
<span>${todo.assignee.name}</span> <div>
<span></span> <div class="agenda-title">${agenda.title}</div>
<span>${formatDate(todo.dueDate)}</span> <div class="ai-summary-short">
<span class="lock-icon">🔒</span>
<span>${agenda.aiSummaryShort}</span>
</div>
</div> </div>
<div class="expand-icon"></div>
`); `);
container.appendChild(item); card.appendChild(header);
// 상세 내용
const content = createElement('div', { className: 'agenda-content' });
// 논의 주제
if (agenda.details.discussion) {
content.appendChild(createElement('div', { className: 'agenda-section' }, `
<div class="agenda-section-title">논의 주제</div>
<div class="agenda-section-content">${agenda.details.discussion}</div>
`));
}
// 발언자별 의견
if (agenda.details.opinions && agenda.details.opinions.length > 0) {
const opinionsHtml = agenda.details.opinions.map(op =>
`<li><strong>${op.speaker}:</strong> ${op.opinion}</li>`
).join('');
content.appendChild(createElement('div', { className: 'agenda-section' }, `
<div class="agenda-section-title">발언자별 의견</div>
<div class="agenda-section-content"><ul>${opinionsHtml}</ul></div>
`));
}
// 결정 사항
if (agenda.details.decisions && agenda.details.decisions.length > 0) {
const decisionsHtml = agenda.details.decisions.map(d => `<li>✓ ${d}</li>`).join('');
content.appendChild(createElement('div', { className: 'agenda-section' }, `
<div class="agenda-section-title">결정 사항</div>
<div class="agenda-section-content"><ul>${decisionsHtml}</ul></div>
`));
}
// 보류 사항
if (agenda.details.pending && agenda.details.pending.length > 0) {
const pendingHtml = agenda.details.pending.map(p => `<li>⏸ ${p}</li>`).join('');
content.appendChild(createElement('div', { className: 'agenda-section' }, `
<div class="agenda-section-title">보류 사항</div>
<div class="agenda-section-content"><ul>${pendingHtml}</ul></div>
`));
}
// Todo 목록
if (agenda.todos && agenda.todos.length > 0) {
const todosSection = createElement('div', { className: 'agenda-section' }, `
<div class="agenda-section-title">Todo 자동 추출 결과</div>
`);
agenda.todos.forEach(todo => {
const todoItem = createElement('div', { className: 'todo-list-item' }, `
<div class="todo-header">
<input type="checkbox" class="todo-checkbox" disabled>
<div class="todo-content">${todo.title}</div>
${createBadge(todo.priority === 'high' ? '높음' : todo.priority === 'medium' ? '보통' : '낮음',
`priority-${todo.priority}`)}
</div>
<div class="todo-meta">
${createAvatar(todo.assignee, 'sm')}
<span>${todo.assignee.name}</span>
<span></span>
<span>${formatDate(todo.dueDate)}</span>
</div>
`);
todosSection.appendChild(todoItem);
});
content.appendChild(todosSection);
}
card.appendChild(content);
container.appendChild(card);
}); });
} }
// 회의록 확정 // 안건 카드 확장/축소
function confirmMeeting() { function toggleAgenda(agendaId) {
if (confirm('회의록을 최종 확정하시겠습니까?\n확정 후에는 Todo가 자동 할당됩니다.')) { const card = $(`#agenda-${agendaId}`);
showToast('회의록이 확정되었습니다', 'success'); card.classList.toggle('expanded');
navigateTo('02-대시보드.html');
}
} }
// Todo 편집 저장 // 바로 최종 확정
function saveTodoEdit() { function confirmMeetingDirectly() {
showToast('Todo가 수정되었습니다', 'success'); if (confirm('AI가 정리한 내용 그대로 최종 확정하시겠습니까?\n\n모든 안건이 자동으로 검증 완료 처리되며, 참석자에게 확정 알림이 발송됩니다.')) {
closeModal('todoEditModal'); showToast('회의록이 최종 확정되었습니다', 'success');
setTimeout(() => {
navigateTo('02-대시보드.html');
}, 1000);
}
} }
// 페이지 로드 시 초기화 // 페이지 로드 시 초기화

View File

@ -942,18 +942,28 @@ graph TD
### 07-회의종료 ### 07-회의종료
#### 개요 #### 개요
- **목적**: 회의 통계 표시 및 최종 회의록 확정 - **목적**: 회의 종료 후 AI 요약 내용 확인 및 다음 단계 선택
- **관련 유저스토리**: UFR-MEET-040, UFR-MEET-050, UFR-AI-020 - **관련 유저스토리**: UFR-MEET-040, UFR-MEET-050, UFR-AI-010, UFR-AI-020, UFR-AI-036
- **비즈니스 중요도**: 높음 - **비즈니스 중요도**: 높음
- **접근 경로**: 회의진행 → "회의 종료" 버튼 - **접근 경로**: 회의진행 → "회의 종료" 버튼
- **권한**: 회의 생성자 전용 - **권한**: 회의 생성자 전용
- **화면 정책**: **확인 전용 화면 (편집 불가)**
- 모든 내용은 읽기 전용
- 안건 내용 수정 불가
- Todo 수정 불가
- 확인 후 다음 단계 선택만 가능
#### 주요 기능 #### 주요 기능
1. 회의 통계 표시 (시간, 참석자, 발언 횟수 등) 1. 회의 통계 표시 (시간, 참석자, 발언 횟수 등)
2. 주요 키워드 클라우드 2. 주요 키워드 클라우드
3. AI 자동 추출된 Todo 항목 확인 3. **안건별 AI 요약 전체 표시** (신규)
4. 최종 회의록 확정 - 안건별 AI 한줄 요약 (30자 이내, 편집 불가)
5. 다음 액션 선택 (공유, 수정, 대시보드 복귀) - 안건별 상세 요약 정리
- 안건별 Todo 자동 추출 결과
4. **3가지 선택 옵션 제공** (신규)
- 옵션 1: 회의록 수정 화면으로 이동
- 옵션 2: 바로 최종 확정
- 옵션 3: 대시보드로 이동
#### UI 구성요소 #### UI 구성요소
@ -968,62 +978,93 @@ graph TD
- 주요 키워드 (태그 클라우드) - 주요 키워드 (태그 클라우드)
- 발언 통계 (화자별 발언 횟수 및 시간 - 바 차트) - 발언 통계 (화자별 발언 횟수 및 시간 - 바 차트)
- **AI Todo 추출 결과** - **안건별 AI 요약 섹션** (신규)
- "AI가 추출한 Todo" 섹션 - **안건 카드** (안건 개수만큼 반복):
- Todo 항목 리스트: - **안건 제목** (H4, Bold)
- Todo 내용 - **AI 한줄 요약** (읽기 전용, 회색 배경 박스)
- 담당자 (자동 식별 또는 수동 지정) - 30자 이내 간결한 표현
- 마감일 (있는 경우) - 🔒 "편집 불가" 아이콘 표시
- "Todo 수정" 버튼 - 민트 그린 좌측 액센트 라인
- **상세 요약 정리** (읽기 전용)
- 논의 주제
- 발언자별 의견
- 결정 사항
- 보류 사항
- **Todo 자동 추출 결과** (있는 경우)
- Todo 항목 리스트
- 담당자, 마감일, 우선순위 표시
- 읽기 전용 (체크박스 비활성화)
- **최종 확정 섹션** - **3가지 선택 옵션** (하단 액션 바)
- "최종 회의록 확정" 버튼 (Primary) - **옵션 1**: "회의록 수정" 버튼 (Secondary)
- 필수 항목 체크리스트: - 회의록 수정 화면(11-회의록수정)으로 이동
- ✓ 회의 제목 작성 - 회의록 상태: 작성중
- ✓ 참석자 목록 작성 - **옵션 2**: "바로 최종 확정" 버튼 (Primary, 강조)
- ✓ 주요 논의 내용 작성 - 확인 다이얼로그: "AI가 정리한 내용 그대로 최종 확정하시겠습니까?"
- ✓ 결정 사항 작성 - 모든 안건 자동 검증 완료 처리
- 회의록 상태: 확정완료
- **하단 액션** - 참석자에게 확정 알림 발송
- "회의록 공유하기" 버튼 - **옵션 3**: "대시보드로 이동" 버튼 (Ghost)
- "회의록 수정하기" 버튼 - 회의록 상태: 작성중 (추후 편집 가능)
- "대시보드로 돌아가기" 버튼 - 대시보드로 이동
**Tablet/Desktop (768px+)** **Tablet/Desktop (768px+)**
- 상단: 통계 카드 (Grid Layout) - 상단: 통계 카드 (Grid Layout)
- 중앙: AI Todo 추출 결과 - 중앙: 안건별 AI 요약 섹션 (2열 그리드)
- 하단: 최종 확정 및 액션 버튼 - 하단: 3가지 선택 옵션 버튼 (가로 배치)
#### 인터랙션 #### 인터랙션
1. **통계 표시** 1. **통계 표시**
- 애니메이션 효과로 숫자 카운트업 - 애니메이션 효과로 숫자 카운트업
- 차트는 페이드인 효과 - 차트는 페이드인 효과
2. **Todo 확인 및 수정** 2. **안건별 AI 요약 확인** (읽기 전용)
- Todo 항목 클릭: 상세 편집 모달 - **안건 카드 확장/축소**:
- 담당자 변경, 마감일 설정 가능 - 초기: 안건 제목 + AI 한줄 요약만 표시
- "Todo 추가" 버튼으로 수동 추가 - 클릭 시: 상세 요약 + Todo 전체 펼침
- **편집 불가 안내**:
- AI 한줄 요약 영역에 🔒 아이콘 표시
- 호버 시: "이 내용은 편집할 수 없습니다" 툴팁
- **Todo 확인**:
- 체크박스 비활성화 (disabled)
- 읽기 전용 표시
3. **최종 확정** 3. **다음 단계 선택**
- "최종 회의록 확정" 클릭: - **옵션 1: 회의록 수정**
- 필수 항목 검사 - 11-회의록수정.html로 이동
- 누락 시: 해당 섹션으로 이동 안내 - URL 파라미터: meetingId
- 완료 시: 확정 확인 다이얼로그 - 회의록 상태: 작성중
- 확정 후: Todo 자동 할당, 캘린더 연동 - **옵션 2: 바로 최종 확정**
- 확인 다이얼로그 표시
- 확인 시:
- 모든 안건 검증률 100% 자동 설정
- 회의록 상태: 확정완료
- 확정 시간 기록
- 참석자에게 확정 알림 발송
- 성공 토스트: "회의록이 최종 확정되었습니다"
- 02-대시보드.html로 이동
- **옵션 3: 대시보드로 이동**
- 회의록 상태: 작성중
- 02-대시보드.html로 이동
- 추후 회의록 목록에서 편집 가능
#### 데이터 요구사항 #### 데이터 요구사항
- **입력**: 회의 ID - **입력**: 회의 ID
- **출력**: - **출력**:
- 회의 통계 (시간, 참석자 수, 발언 통계, 키워드) - 회의 통계 (시간, 참석자 수, 발언 통계, 키워드)
- AI 추출 Todo 목록 - **안건별 AI 요약 데이터**:
- 확정 회의록 버전 ID - 안건 제목
- AI 한줄 요약 (30자 이내)
- 상세 요약 정리 (논의 주제, 발언자별 의견, 결정 사항, 보류 사항)
- 안건별 Todo 목록 (제목, 담당자, 마감일, 우선순위)
- 회의록 상태 (작성중/확정완료)
- **연동**: Meeting 서비스, AI 서비스, Todo 서비스 - **연동**: Meeting 서비스, AI 서비스, Todo 서비스
#### 에러 처리 #### 에러 처리
- **통계 생성 실패**: "통계를 생성할 수 없습니다" + 건너뛰기 옵션 - **통계 생성 실패**: "통계를 생성할 수 없습니다" + 건너뛰기 옵션
- **Todo 추출 실패**: "AI Todo 추출에 실패했습니다. 수동으로 추가해주세요" - **AI 요약 생성 실패**: "AI 요약을 생성할 수 없습니다. 회의록 수정 화면에서 직접 작성해주세요"
- **필수 항목 누락**: "필수 항목을 작성해주세요" + 해당 섹션으로 이동 - **바로 확정 실패**: "회의록 확정에 실패했습니다. 다시 시도해주세요"
- **확정 실패**: "회의록 확정에 실패했습니다. 다시 시도해주세요" - **네트워크 오류**: 자동 재시도 3회, 실패 시 재시도 버튼 제공
--- ---