From 01bb4198d9c5560aa97d494b87ac385b1b569618 Mon Sep 17 00:00:00 2001 From: yabo0812 Date: Wed, 29 Oct 2025 13:51:38 +0900 Subject: [PATCH] =?UTF-8?q?UI/UX=20=EB=AC=B8=EC=84=9C=20=EC=A0=95=EB=A6=AC?= =?UTF-8?q?:=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EB=B0=B1=EC=97=85?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EB=B0=8F=20=EC=B0=B8=EC=A1=B0=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 주요 변경사항: - 프로토타입 백업 파일 삭제 (대시보드, 회의진행) - 참조 이미지 파일 정리 (KakaoTalk 스크린샷 4건) - UI/UX 설계서 및 유저스토리 업데이트 프로젝트 정리 및 문서 구조 개선 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- design/uiux/prototype/02-대시보드-backup.html | 832 ------ design/uiux/prototype/05-회의진행_bk.html | 2306 ----------------- .../KakaoTalk_Photo_2025-10-21-16-17-09.png | Bin 39685 -> 0 bytes .../KakaoTalk_Photo_2025-10-21-16-18-18.png | Bin 43828 -> 0 bytes .../KakaoTalk_Photo_2025-10-21-16-18-26.png | Bin 64712 -> 0 bytes .../KakaoTalk_Photo_2025-10-21-16-18-46.png | Bin 32467 -> 0 bytes design/uiux/uiux.md | 2167 ++++------------ design/userstory.md | 1139 ++------ 8 files changed, 727 insertions(+), 5717 deletions(-) delete mode 100644 design/uiux/prototype/02-대시보드-backup.html delete mode 100644 design/uiux/prototype/05-회의진행_bk.html delete mode 100644 design/uiux/ref_img/KakaoTalk_Photo_2025-10-21-16-17-09.png delete mode 100644 design/uiux/ref_img/KakaoTalk_Photo_2025-10-21-16-18-18.png delete mode 100644 design/uiux/ref_img/KakaoTalk_Photo_2025-10-21-16-18-26.png delete mode 100644 design/uiux/ref_img/KakaoTalk_Photo_2025-10-21-16-18-46.png diff --git a/design/uiux/prototype/02-대시보드-backup.html b/design/uiux/prototype/02-대시보드-backup.html deleted file mode 100644 index 738b5f6..0000000 --- a/design/uiux/prototype/02-대시보드-backup.html +++ /dev/null @@ -1,832 +0,0 @@ - - - - - - 대시보드 - 회의록 서비스 - - - - - - - - -
-
-

안녕하세요, 김민준님!

-

오늘의 일정을 확인하세요

-
- - -
- - -
-
-
-
-
김민준
-
minjun.kim@company.com
-
-
- -
-
- - -
- - -
-
-
📅
-
예정된 회의
-
3
-
-
-
-
진행 중 Todo
-
1
-
-
-
📈
-
Todo 완료율
-
33%
-
-
- - -
-
-

최근 회의

- 전체 보기 → -
-
- -
-
- - -
-
-

할당된 Todo

- 전체 보기 → -
-
- -
-
- - -
-
-

내 회의록

- 전체 보기 → -
-
- -
-
- -
- - - - - -
- - -
- -
- - - - - - - - diff --git a/design/uiux/prototype/05-회의진행_bk.html b/design/uiux/prototype/05-회의진행_bk.html deleted file mode 100644 index 28323dc..0000000 --- a/design/uiux/prototype/05-회의진행_bk.html +++ /dev/null @@ -1,2306 +0,0 @@ - - - - - 회의 진행 중 - 회의록 서비스 - - - - -
- -
-
-
-

2025년 1분기 제품 기획 회의

-
- -
-
-
- 00:28:06 -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- - -
-
- -
- -
-
회의 개요
-
논의 사항
-
결정 사항
-
액션 아이템
-
- - -
- -
- -
-
-

🤖 AI 요약

-
- 2분 전 생성 - -
-
-

- 2025년 1분기 신제품 개발을 위한 기획 회의입니다. AI 기반 회의록 자동화 서비스의 핵심 기능과 차별화 전략에 대해 논의하였으며, 예상 개발 일정은 3개월입니다. -

-
- - -
-
-

내용

- -
-
-

회의 목적: 2025년 1분기 신제품 개발 방향 수립

-

참석자: 김민준(PM), 박서연(AI), 이준호(Backend), 최유진(Frontend)

-

일시: 2025년 10월 25일 14:00 - 15:30

-

장소: 본사 2층 대회의실

-
-
- - -
- - -
-
- - - - - - - -
-
- - -
- - - - - -
- - -
-
-
-
-
-

참고자료

- -
-
- - - - - - - - - - - - - - -
-
-
- - -
- - -
-
- - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/design/uiux/ref_img/KakaoTalk_Photo_2025-10-21-16-17-09.png b/design/uiux/ref_img/KakaoTalk_Photo_2025-10-21-16-17-09.png deleted file mode 100644 index 0ef3662f2142ec55713d4f0aa3b3563f60a5d9bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39685 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 diff --git a/design/uiux/ref_img/KakaoTalk_Photo_2025-10-21-16-18-26.png b/design/uiux/ref_img/KakaoTalk_Photo_2025-10-21-16-18-26.png deleted file mode 100644 index 98b7ff3ab4e0028a5c1f0d916c7461e8c82ff242..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64712 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 U$7p?F1P>70b@0JqaF{oc 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 q#N07>^YvX- B[대시보드] - B --> C[회의예약] - C --> D[템플릿선택] - D --> E[회의진행] - E --> G[회의종료] - G --> H{회의록 수정?} - H -->|Yes| K[회의록수정] - H -->|No| B - K --> B +--- - B --> I[회의록상세조회] - I --> J{수정 필요?} - J -->|Yes| K - K --> I - J -->|No| B +## 화면 설계 표준 + +### 공통 화면 구조 템플릿 + +#### Mobile 기본 구조 (320px~768px) ``` +┌─────────────────────────┐ +│ 헤더 (Fixed) │ ← 뒤로가기, 타이틀, 액션버튼 +├─────────────────────────┤ +│ │ +│ 메인 콘텐츠 영역 │ +│ (스크롤 가능) │ +│ │ +├─────────────────────────┤ +│ 하단 네비게이션 (Fixed) │ ← 홈, 회의록 (2개) +└─────────────────────────┘ +``` + +#### Desktop 기본 구조 (768px+) +``` +┌──────┬──────────────────┐ +│ │ 헤더 (Fixed) │ +│ 사이 ├──────────────────┤ +│ 드바 │ │ +│ (固) │ 메인 콘텐츠 영역 │ +│ │ (최대 너비 제한) │ +│ │ │ +└──────┴──────────────────┘ +``` + +### 공통 레이아웃 패턴 + +#### 폼 레이아웃 +- **Mobile**: 단일 컬럼, 전체 너비 +- **Desktop**: 2컬럼 + 미리보기 패널(선택) + +#### 카드 리스트 +- **Mobile**: 단일 컬럼, 스택 레이아웃 +- **Tablet**: 2컬럼 그리드 +- **Desktop**: 2-3컬럼 그리드 + +#### 통계 카드 +- **Mobile**: 2열 그리드 (~80px 높이) +- **Desktop**: 가로 배치, 간격 증가 + +### 공통 데이터 타입 + +#### 회의 기본 정보 +- 회의 ID, 제목, 일시, 장소 +- 참여자 목록, 참여자 수 +- 생성자 ID, 상태(진행중/예정/완료) +- 생성일시, 수정일시 + +#### 회의록 정보 +- 회의록 ID, 회의 ID 참조 +- 상태(작성중/확정완료) +- 안건 구조, Todo 목록 +- 검증완료율(작성중만) + +#### 상태 배지 +- **진행중**: 빨강 배지, "진행중" +- **예정**: 파랑 배지, "예정" +- **작성중**: 주황 배지, "작성중" +- **확정완료**: 초록 배지, "확정완료" [↑ 목차로 돌아가기](#목차) @@ -152,1485 +175,421 @@ graph TD ### 01-로그인 #### 개요 -- **목적**: 사용자 인증 및 시스템 접근 권한 부여 +- **목적**: LDAP 인증 및 시스템 접근 - **관련 유저스토리**: UFR-USER-010 -- **비즈니스 중요도**: 필수 -- **접근 경로**: 애플리케이션 최초 진입 +- **접근 경로**: 앱 최초 진입 -#### 주요 기능 -1. 사번과 비밀번호를 이용한 LDAP 인증 +#### 고유 기능 +1. 사번/비밀번호 LDAP 인증 2. 로그인 상태 유지 옵션 3. 비밀번호 찾기/재설정 -4. 오류 처리 및 피드백 -#### UI 구성요소 - -**Mobile (320px~768px)** -- 상단: 서비스 로고 및 타이틀 -- 중앙: 로그인 폼 - - 사번 입력 필드 (필수) - - 비밀번호 입력 필드 (필수, 마스킹) - - "로그인 상태 유지" 체크박스 - - 로그인 버튼 (Primary CTA) -- 하단: "비밀번호 찾기" 링크 -- 오류 메시지 영역 - -**Tablet/Desktop (768px+)** -- 좌측: 서비스 소개 및 주요 기능 설명 (선택) -- 우측: 로그인 폼 (모바일과 동일 구조) +#### UI 구성 +- **Mobile**: 중앙 정렬 로그인 폼 ([폼 레이아웃](#폼-레이아웃) 참조) +- **Desktop**: 좌측 서비스 소개 + 우측 로그인 폼 #### 인터랙션 -1. **입력 검증** - - 실시간 필드 유효성 검사 (형식 오류 즉시 표시) - - 빈 필드 제출 시 해당 필드로 포커스 이동 +- [폼 검증 패턴](#폼-검증) 참조 +- Enter 키 → 다음 필드 이동/로그인 실행 +- 성공 시 대시보드로 페이드 전환 -2. **로그인 처리** - - 로그인 버튼 클릭 → 로딩 인디케이터 표시 - - 성공: 대시보드로 자동 이동 (페이드 전환) - - 실패: 오류 메시지 표시 (사번/비밀번호 불일치, 계정 잠금 등) - -3. **키보드 인터랙션** - - Enter 키로 다음 필드 이동 또는 로그인 실행 - - Tab 키로 포커스 이동 - -#### 데이터 요구사항 +#### 데이터 - **입력**: 사번(문자열), 비밀번호(문자열, 최소 8자) -- **출력**: 인증 토큰, 사용자 정보(이름, 권한) -- **연동**: User 서비스 - LDAP 인증 API +- **출력**: 인증 토큰, 사용자 정보 +- **연동**: User 서비스 -#### 에러 처리 -- **인증 실패**: "사번 또는 비밀번호가 올바르지 않습니다." (보안상 구체적 정보 제공 X) -- **계정 잠금**: "보안을 위해 계정이 일시적으로 잠겼습니다. 관리자에게 문의하세요." -- **네트워크 오류**: [공통 에러 메시지 - 네트워크 오류](#네트워크-오류) 참조 -- **서버 오류**: [공통 에러 메시지 - 서버 오류](#서버-오류) 참조 +#### 에러 +- 인증 실패: "사번 또는 비밀번호가 올바르지 않습니다" +- 계정 잠금: "계정이 일시적으로 잠겼습니다" +- [네트워크 오류](#네트워크-오류), [서버 오류](#서버-오류) 참조 --- ### 02-대시보드 #### 개요 -- **목적**: 주요 기능 접근 허브, 최근 활동 요약 제공 -- **관련 유저스토리**: UFR-USER-020 (대시보드 조회) -- **비즈니스 중요도**: 필수 +- **목적**: 주요 기능 허브, 최근 활동 요약 +- **관련 유저스토리**: UFR-USER-020 - **접근 경로**: 로그인 후 메인 화면 -#### 주요 기능 -1. 빠른 회의 시작 및 예약 -2. **최근 회의 목록** (최대 3개, 회의록 미생성 우선) - - 1순위: 진행중 회의 (참여 가능) - - 2순위: 예정된 회의 (시작 전) - - 3순위: 최근 종료된 회의 (회의록 있음, 1+2순위가 3개 미만일 때만 표시) -3. **통계 정보 표시** (예정된 회의, 작성중 회의록) -4. **내 회의록** (참여자/생성자로 등록된 최근 4개, 상태 포함) +#### 고유 기능 +1. **통계 카드** (2개): 예정된 회의, 작성중 회의록 +2. **최근 회의** (최대 3개): 진행중 우선 → 예정 → 완료 + - 정렬: 회의록 미생성 우선, 빠른 일시 순 + - 생성자 표시(👑), 상태 배지 +3. **내 회의록** (최대 4개, 2x2 그리드) + - 최근 생성 순, 상태 배지 + - "전체 보기" → 12-회의록목록조회 -#### UI 구성요소 - -**Mobile (320px~768px)** -- **헤더** (상단) - - "안녕하세요 👋" (H3, Bold) - - 부제: "오늘 {N}건의 회의가 예정되어 있어요" (Body, 회색) - - N = 예정된 회의 개수 (동적 업데이트) - - 예정된 회의가 없을 경우: "예정된 회의가 없습니다" - -- **메인 콘텐츠** (스크롤, padding-bottom: 80px, background: gray-50) - - **통계 카드** (2열 그리드) - - "📅 예정된 회의" 카드 - - 값: 전체 예정 + 진행 중 회의 개수 - - "📝 작성중 회의록" 카드 - - 값: 내가 참여한 회의 중 '작성중' 상태인 회의록 개수 - - 높이: ~80px - - 클릭 액션: 없음 (정보 표시만) - - 반응형: 태블릿 이상에서 간격 증가 - - - **최근 회의** 섹션 - - 헤더: "최근 회의" (H4) - - **정렬 기준** (UFR-USER-020 기준): - 1. **1순위**: 회의록 미생성 회의 (진행중 + 예정) 우선 표시 - 2. **2순위**: 1순위가 3개 미만이면 최근 종료된 회의(회의록 있음)로 나머지 채움 - 3. **각 그룹 내 정렬**: 빠른 일시 순 (시작 시간 기준) - 4. **최대 표시**: 3개 - - **회의 카드** (클릭 가능 블록): - - 상태 라벨 (배지) - - 진행중: "진행중" - - 예정: "예정" - - 완료: "작성중" 또는 "확정완료" - - 회의 제목 (H5) - - 생성자 표시 (👑 아이콘) - 내가 생성한 회의인 경우 - - 회의 일시 (아이콘: calendar_today) - - 참여자 수 (아이콘: people) - - 장소 정보 - - 상태 버튼 (표시용): - - 진행중: "참여하기" 버튼 - - 예정: 버튼 없음 (카드 클릭으로 처리) - - 완료: 버튼 없음 (카드 클릭으로 처리) - - 빈 상태: "예정된 회의가 없습니다" - - - **내 회의록** 카드 - - 헤더: "내 회의록" (H4) + "전체 보기 →" 링크 (회의록 목록 화면으로 이동) - - **최근 회의록 리스트** (최대 4개, 2x2 그리드): - - 필터: 내가 참여자 또는 생성자로 등록된 회의록 - - 정렬: 최근 생성 순 (createdAt 기준) - - 각 항목: - - 회의 제목 (H5) - - 회의 일시 (날짜 + 시간) - - 참여자 수 - - **상태 배지**: - - "작성중" (draft, 주황색 배지) - - "확정완료" (confirmed, 초록색 배지) - - 검증완료율 표시 (작성중인 경우만) - - 클릭 시: 회의록 상세 화면으로 이동 - - 빈 상태: "참여한 회의록이 없습니다" - -**Mobile (320px~768px)** - **v1.5.0 네비게이션 간소화** -- **하단 네비게이션**: 2개 메뉴만 표시 - - 홈 (대시보드) - 활성 상태 - - 회의록 (회의록 목록) - -**Tablet/Desktop (768px+)** -- **좌측 사이드바**: [Desktop 좌측 사이드바](#desktop-좌측-사이드바-768px) 참조 (대시보드 활성) - -- **메인 콘텐츠** (왼쪽 여백 240px) - - **헤더** - - "안녕하세요, {사용자명}님!" (H2) - - "오늘의 일정을 확인하세요" (부제) - - - **통계 카드 그리드** (2개) - **v1.5.0 변경** - - 예정된 회의 (📅) - - 작성중 회의록 (📝) - - - **최근 회의 그리드** (2-3컬럼) - - 회의 카드들 (진행중 우선) - - 참여하기/수정/보기 버튼 - - - **내 회의록 리스트** - - 화이트 카드 배경 - - 전체보기 → 12-회의록목록조회.html - -- **하단 네비게이션**: 숨김 (데스크톱에서는 사이드바 사용) +#### UI 구성 +- **헤더**: "안녕하세요 👋" + "오늘 N건의 회의가 예정되어 있어요" +- **통계 카드**: [통계 카드 레이아웃](#통계-카드) 참조 (2개) +- **네비게이션**: [하단 네비게이션](#mobile-하단-네비게이션-320px768px) / [사이드바](#desktop-좌측-사이드바-768px) 참조 #### 인터랙션 -1. **빠른 액션** - - "새 회의 시작" 클릭 → 템플릿선택 화면으로 이동 (페이드 전환) - - "회의 예약" 클릭 → 회의예약 화면으로 이동 - -2. **예정된/진행중 회의 인터랙션** - - **진행중 회의** (모든 참여자): - - "참여하기" 버튼 클릭 → 회의 진행 화면으로 즉시 이동 - - 회의 항목 클릭 → 회의 상세 정보 표시 (모달 또는 화면 이동) - - 애니메이션: "진행중" 배지 깜빡임 효과 (1초 간격) - - - **예정된 회의 - 생성자 (내가 생성한 회의)**: - - 회의 카드 클릭 → 회의예약 화면(수정 모드)으로 이동 - - 회의 제목, 일시, 참여자, 안건 등 수정 가능 - - 저장 시 참여자에게 변경 알림 발송 - - 크라운 아이콘 표시 (생성자 구분) - - - **예정된 회의 - 초대받은 참여자**: - - 회의 카드 클릭 → 시스템 알럿 표시 - - 메시지: "아직 회의 시간이 되지 않아 참여하실 수 없습니다" - - 다음 버전에서 회의 상세 조회 기능으로 개선 예정 - - - **공통**: - - 회의 항목 호버: 카드 그림자 증가 - - "전체 보기" 링크 클릭 → 회의 목록 화면으로 이동 - -3. **카드 인터랙션** - - 회의록 항목 클릭 → 회의록 상세 화면으로 이동 - - "전체 보기" 링크 클릭 → 해당 목록 화면으로 이동 - - 호버 효과: 카드 그림자 증가, 약간 상승 (transform: translateY(-2px)) - -4. **검색** - - 검색 아이콘 클릭: 전체 화면 검색 인터페이스 표시 - - 실시간 자동완성 및 최근 검색어 제공 - -#### 데이터 요구사항 -- **입력**: - - 사용자 ID (현재 로그인 사용자) - - 현재 날짜/시간 (예정된 회의 필터링용) +- **진행중 회의**: "참여하기" → 회의진행 화면 +- **예정 회의 - 생성자**: 카드 클릭 → 회의예약(수정 모드) +- **예정 회의 - 참여자**: 카드 클릭 → "아직 참여할 수 없습니다" 알럿 +- **완료 회의**: 카드 클릭 → 회의록상세조회 +- [카드 호버](#카드-인터랙션) 참조 +#### 데이터 +- **입력**: 사용자 ID, 현재 날짜/시간 - **출력**: - - **예정된/진행중 회의**: - - 회의 ID, 제목, 일시, 참여자 목록, 상태 (예정/진행중), D-day - - **생성자 ID** (권한 판별용) - - **현재 사용자 역할** (creator | attendee) - - **참여 가능 시간** (시작 시간 - 10분) - - 필터 조건: - - **진행중 회의**: 회의 시작 시간 <= 현재 시간 AND 회의 종료 안 됨, 사용자가 참여자 또는 생성자 - - **예정된 회의**: 회의 일시 >= 현재 시간, 사용자가 참여자 또는 생성자 - - 정렬 우선순위: - 1. 진행중 회의 우선 (상태 = ongoing) - 2. 예정된 회의 (회의 일시 순, 가까운 순) - - 최대 3개 (진행중 회의 우선) - - **버튼 표시 조건**: - - 진행중 회의: "참여하기" 버튼 (항상 표시) - - 예정된 회의 (생성자): "수정" 버튼 (항상 표시) - - 예정된 회의 (참여자): - - 현재 시간 >= 시작 시간 - 10분: "참여하기" 버튼 활성화 - - 현재 시간 < 시작 시간 - 10분: 버튼 비활성화 또는 타이머 표시 + - 통계: 예정/진행중 회의 수, 작성중 회의록 수 + - 최근 회의: 회의 기본 정보 + 생성자 ID + 현재 사용자 역할 + - 내 회의록: 회의록 정보 ([공통 데이터 타입](#공통-데이터-타입) 참조) +- **연동**: Meeting 서비스 - - **내 회의록**: - - 회의 ID, 제목, 일시, 참여자 수, 상태, 생성일시, 수정일시 - - 필터: 사용자가 참여자 또는 생성자 - - 정렬: 생성일시 (최근 순) - - 최대 3개 - - - **통계 데이터**: - - 예정된/진행중 회의 수 (진행중 회의 수 별도 배지) - - 작성중 회의록 수 - -- **연동**: - - Meeting 서비스 (회의 정보, 회의록 정보) - -#### 에러 처리 -- **데이터 로딩 실패**: - - 해당 카드에 "일시적으로 데이터를 불러올 수 없습니다." 표시 - - "다시 시도" 버튼 제공 (새로고침 아이콘) - - 로그 기록 및 에러 추적 - -- **부분 데이터 로딩 실패**: - - 실패한 섹션만 에러 표시, 나머지 섹션은 정상 표시 - - 사용자 경험 최소 방해 - -- **빈 상태** (각 섹션별): - - 예정된/진행중 회의: "예정된 회의가 없습니다" - - 내 회의록: "작성한 회의록이 없습니다. 첫 회의를 시작해보세요!" - -- **진행중 회의 참여 실패**: - - "회의에 참여할 수 없습니다." 토스트 메시지 - - 원인별 안내: - - 회의 종료됨: "이미 종료된 회의입니다" - - 권한 없음: [공통 에러 메시지 - 권한 오류](#권한-오류) 참조 - - 네트워크 오류: [공통 에러 메시지 - 네트워크 오류](#네트워크-오류) 참조 - -- **예정된 회의 접근 제한**: - - **시간 제한 (초대받은 참여자)**: - - "아직 참여할 수 없습니다. N분 후 참여 가능합니다." 토스트 메시지 - - 10분 전부터 참여 버튼 활성화 - - 타이머 자동 갱신 (1분 간격) - - **권한 제한 (수정 시도)**: - - [공통 에러 메시지 - 권한 오류](#권한-오류) 참조 - -- **회의 수정 실패** (생성자): - - "회의 정보를 수정할 수 없습니다." 토스트 메시지 - - 원인별 안내: - - 이미 시작된 회의: "진행 중인 회의는 수정할 수 없습니다" - - 네트워크 오류: [공통 에러 메시지 - 네트워크 오류](#네트워크-오류) 참조 - - 권한 변경됨: [공통 에러 메시지 - 권한 오류](#권한-오류) 참조 - -- **네트워크 오류**: [공통 에러 메시지 - 네트워크 오류](#네트워크-오류) 참조 +#### 에러 +- 데이터 로딩 실패: 해당 카드에 "다시 시도" 버튼 +- 부분 실패: 실패 섹션만 에러 표시 +- 진행중 회의 참여 실패: "회의에 참여할 수 없습니다" + 원인별 안내 --- ### 03-회의예약 #### 개요 -- **목적**: 예정된 회의 일정 등록 및 참여자 초대 +- **목적**: 회의 일정 등록 및 참여자 초대 - **관련 유저스토리**: UFR-MEET-010 -- **비즈니스 중요도**: 높음 -- **접근 경로**: 대시보드 → "회의 예약" 버튼 -- **권한**: 모든 사용자 (예약 생성 시 자동으로 회의 생성자가 됨) +- **접근 경로**: 대시보드 → "회의 예약" 또는 예정 회의 카드 클릭(생성자) -#### 주요 기능 +#### 고유 기능 1. 회의 기본 정보 입력 (제목, 날짜/시간, 장소) -2. 참여자 추가 (이메일 또는 조직도 검색) +2. 참여자 추가 (이메일/조직도 검색) 3. 회의 안건 사전 입력 (선택) 4. 참여자 초대 이메일 자동 발송 -5. 캘린더 연동 -#### UI 구성요소 - -**Mobile (320px~768px)** -- **헤더** - - 뒤로가기 버튼 - - "회의 예약" 타이틀 - - "저장" 버튼 (Primary) - -- **폼 섹션** (스크롤) - - **회의 제목** (필수) - - 텍스트 입력 필드 - - 최대 100자 카운터 - - - **날짜 및 시간** (필수) - - 날짜 선택기 (달력 UI) - - 시작 시간 선택기 - - 종료 시간 선택기 - - 종일 토글 (선택) - - - **장소** (선택) - - 텍스트 입력 필드 - - 온라인/오프라인 토글 - - 온라인 선택 시: 회의 링크 자동 생성 옵션 - - - **참여자** (필수, 최소 1명) - - 참여자 칩 (제거 가능) - - "참여자 추가" 버튼 - - 참여자 검색 (이메일 또는 이름) - - - **안건** (선택) - - 다중 라인 텍스트 입력 - -**Tablet/Desktop (768px+)** -- 좌측: 폼 (모바일과 동일) -- 우측: 미리보기 패널 (입력 내용 실시간 프리뷰) +#### UI 구성 +- **헤더**: 뒤로가기, "회의 예약", "저장" +- **폼**: [폼 레이아웃](#폼-레이아웃) 참조 + - 제목(필수, 100자), 날짜/시간(필수), 장소(선택) + - 참여자(필수, 최소 1명, 칩 UI) + - 안건(선택, 다중 라인) #### 인터랙션 -1. **날짜/시간 선택** - - 달력 UI: 과거 날짜 비활성화 - - 시간 선택: 30분 단위 드롭다운 - - 충돌 감지: 동일 시간대 다른 회의 있을 경우 경고 +- **날짜/시간**: 달력 UI, 과거 비활성화, 충돌 감지 +- **참여자 추가**: [참여자 관리 패턴](#참여자-관리) 참조 +- **저장**: [폼 검증](#폼-검증) → 성공 토스트 → 대시보드 -2. **참여자 추가** - - "참여자 추가" 클릭 → 검색 모달 표시 - - 실시간 검색 (이름, 이메일, 부서) - - 선택된 참여자는 칩 형태로 표시 - - 칩의 X 버튼으로 제거 가능 - -3. **저장 처리** - - 필수 필드 검증 - - 저장 성공: "회의가 예약되었습니다" 토스트 메시지, 대시보드로 이동 - - 초대 이메일 발송 확인 다이얼로그 - -#### 데이터 요구사항 -- **입력**: - - 제목(문자열, 최대 100자) - - 날짜(Date) - - 시작 시간(Time) - - 종료 시간(Time) - - 장소(문자열, 최대 200자, 선택) - - 참여자 목록(이메일 배열) - - 안건(문자열, 선택) -- **출력**: 회의 ID, 초대 이메일 발송 결과 +#### 데이터 +- **입력**: 제목, 날짜, 시간, 장소, 참여자 이메일, 안건 +- **출력**: 회의 ID, 초대 발송 결과 - **연동**: Meeting 서비스, Notification 서비스 -#### 에러 처리 -- **필수 필드 누락**: 해당 필드에 빨간색 테두리 및 오류 메시지 -- **참여자 0명**: "최소 1명의 참여자를 추가해주세요" -- **과거 날짜 선택**: "과거 날짜는 선택할 수 없습니다" -- **저장 실패**: "회의 예약에 실패했습니다. 다시 시도해주세요" +#### 에러 +- 필수 필드 누락: 빨간 테두리 + 오류 메시지 +- 참여자 0명: "최소 1명의 참여자를 추가해주세요" +- 과거 날짜: "과거 날짜는 선택할 수 없습니다" --- ### 04-템플릿선택 #### 개요 -- **목적**: 회의 유형에 맞는 회의록 템플릿 선택 및 커스터마이징 +- **목적**: 회의록 템플릿 선택 및 커스터마이징 - **관련 유저스토리**: UFR-MEET-020 -- **비즈니스 중요도**: 중간 -- **접근 경로**: 대시보드 → "새 회의 시작" 또는 회의예약 → "회의 시작" +- **접근 경로**: 회의예약 → "회의 시작" 또는 대시보드 → "새 회의 시작" - **권한**: 회의 생성자 전용 -#### 주요 기능 -1. 사전 정의된 템플릿 선택 (일반, 스크럼, 킥오프, 주간) +#### 고유 기능 +1. 사전 정의 템플릿 선택 (일반, 스크럼, 킥오프, 주간) 2. 템플릿 미리보기 3. 섹션 추가/삭제/순서 변경 4. 커스텀 템플릿 저장 -#### UI 구성요소 - -**Mobile (320px~768px)** -- **헤더** - - 뒤로가기 버튼 - - "템플릿 선택" 타이틀 - - "건너뛰기" 텍스트 버튼 (기본 템플릿 사용) - -- **템플릿 카드 리스트** - - 각 템플릿 카드: - - 템플릿 이름 및 아이콘 - - 간단한 설명 - - "선택" 버튼 - - "미리보기" 버튼 - -- **선택된 템플릿 상세** (모달 또는 전체 화면) - - 섹션 목록 (드래그하여 순서 변경 가능) - - 각 섹션: 이름, 삭제 버튼 - - "섹션 추가" 버튼 - - "이 템플릿으로 시작" 버튼 (Primary) - -**Tablet/Desktop (768px+)** -- 좌측: 템플릿 목록 -- 중앙: 선택된 템플릿 미리보기 -- 우측: 커스터마이징 패널 +#### UI 구성 +- **헤더**: 뒤로가기, "템플릿 선택", "건너뛰기" +- **템플릿 카드**: 이름, 아이콘, 설명, "선택"/"미리보기" 버튼 +- **커스터마이징**: 섹션 목록(드래그 가능), "섹션 추가", "이 템플릿으로 시작" #### 인터랙션 -1. **템플릿 선택** - - 템플릿 카드 클릭: 해당 템플릿 상세 보기 - - "선택" 버튼: 즉시 회의진행 화면으로 이동 +- 템플릿 카드 클릭 → 상세 보기 +- 섹션 드래그 → 순서 변경 +- "선택" → 회의진행 화면 +- [드래그 앤 드롭 패턴](#드래그-앤-드롭) 참조 -2. **커스터마이징** - - 섹션 드래그: 순서 변경 (터치/마우스) - - 섹션 삭제: 스와이프 또는 삭제 아이콘 - - 섹션 추가: "섹션 추가" → 섹션 이름 입력 모달 - -3. **저장 및 시작** - - "이 템플릿으로 시작": 회의진행 화면으로 전환 - - 커스텀 템플릿 저장 옵션 (선택) - -#### 데이터 요구사항 -- **입력**: 없음 (또는 회의 ID - 예약된 회의인 경우) -- **출력**: 선택된 템플릿 구조 (섹션 배열) +#### 데이터 +- **입력**: 회의 ID(선택) +- **출력**: 선택된 템플릿 구조 - **연동**: Meeting 서비스 -#### 에러 처리 -- **템플릿 로딩 실패**: "템플릿을 불러올 수 없습니다" + 재시도 버튼 -- **빈 템플릿**: "최소 1개의 섹션이 필요합니다" +#### 에러 +- 템플릿 로딩 실패: "다시 시도" 버튼 +- 빈 템플릿: "최소 1개의 섹션 필요" --- ### 05-회의진행 #### 개요 -- **목적**: 실시간 회의 진행 및 AI 기반 회의록 자동 작성 -- **관련 유저스토리**: UFR-MEET-030, UFR-STT-010/020, UFR-AI-010, UFR-AI-040, UFR-RAG-010/020, UFR-PART-020, UFR-HOST-010/020, UFR-TERM-010/020 -- **비즈니스 중요도**: 높음 (핵심 화면) -- **접근 경로**: 대시보드 → "참여하기" 버튼 (페이지 전환) -- **권한** (MVP 개선): - - **회의 생성자 전용**: 회의 종료, 녹음 제어 (일시정지/재개/종료) - - **모든 참여자**: 회의 참여, AI 기반 메모 작성, 용어 확인, 관련 회의록 확인, 중도 퇴장 +- **목적**: 실시간 회의 진행 및 AI 회의록 자동 작성 +- **관련 유저스토리**: UFR-MEET-030, UFR-STT-010/020, UFR-AI-010, UFR-AI-040, UFR-PART-020 +- **접근 경로**: 대시보드 → "참여하기" 버튼 +- **권한**: + - 생성자: 회의 종료, 녹음 제어 + - 참여자: 참여, AI 메모 작성, 용어 확인, 중도 퇴장 -#### 주요 기능 (MVP 스코프 축소 v1.5.0) -1. 음성 녹음 및 실시간 텍스트 변환 (STT) -2. AI 자동 회의록 작성 (구조화) -3. **AI 기반 메모 작성** (UFR-PART-020): AI가 실시간으로 감지한 주요 내용을 참여자가 선택하여 개인 메모로 저장 -4. 전문용어 자동 감지 및 맥락 기반 설명 -5. **참고자료 자동 연결** (이전 회의록, 관련 회의록) -6. 참여자 관리 및 초대 기능 -7. 회의 진행 시간 표시 +#### 고유 기능 +1. 음성 STT 및 AI 자동 회의록 작성 +2. **AI 기반 메모** (UFR-PART-020): AI가 감지한 주요 내용을 선택하여 개인 메모 저장 +3. 전문용어 자동 감지 및 맥락 기반 설명 +4. 참고자료 자동 연결 (관련 회의록 32건) +5. 참여자 관리 및 초대 -**변경사항 (v1.5.0)**: -- ✅ 변경: "AI 제안" 탭 → "AI 기반 메모" 탭으로 기능 변경 -- ✅ 추가: 개인 메모 입력 및 저장 기능 (각 참여자별 개별 저장) -- ✅ 정책: 메모는 회의 종료 전까지만 표시/편집 가능, 다른 참여자 메모는 볼 수 없음 +#### UI 구성 +- **헤더**: "회의 진행 중" + 경과시간 배지 + "회의 종료" +- **탭 네비게이션** (4개) + - 참여자 (인원수), AI 기반 메모, 용어 사전, 관련 자료(32건) -#### UI 구성요소 +#### 탭 콘텐츠 +**참여자 탭**: +- 참여자 추가 폼 (이메일 + "초대") +- 참여자 목록 (아바타 + 이름) -**전체 레이아웃** -- **헤더** (Fixed, 상단) - - 좌측: "회의 진행 중" 제목 + 경과시간 배지 (빨강, 01:03) - - 우측: "회의 종료" 버튼 (민트 그린 테두리) +**AI 기반 메모 탭**: +- 메모 입력창 + "저장" +- AI가 감지한 주요 내용 리스트 ("[HH:MM] 내용") +- 클릭 시 메모 입력창에 자동 추가 +- 정책: 개인별 저장, 회의 종료 전까지만 표시 -- **메인 콘텐츠 영역: 정보 패널** (탭 구조) - - **탭 네비게이션** (4개 탭) - - 참여자 (3명) - - AI 기반 메모 - - 용어 사전 - - 관련 자료 (32건) +**용어 사전 탭**: +- 검색 입력창 +- 용어 카드 (용어명 + 배지 + 정의 + 컨텍스트) +- 언급된 용어는 민트 그린 배경 + 💬 아이콘 - - **참여자 탭** (4명) - - 제목: "참여자 (4명)" (동적으로 인원수 업데이트) - - **참여자 추가 폼**: - - 이메일 입력 필드: placeholder "이메일 주소 입력", form-control 스타일 - - "초대" 버튼: btn btn-primary btn-sm - - 레이아웃: Flex (gap: 8px), 입력창(flex: 1) + 버튼 - - 하단 여백: 16px (margin-bottom: var(--space-md)) - - **참여자 목록** (아바타 + 이름) - - 김민준 (초록 아바타) - - 박서연 (파랑 아바타) - - 이준호 (노랑 아바타) - - 최유진 (핑크 아바타) - - **각 참여자 아이템**: - - 컬러 아바타 (avatar-sm: 32x32) - - 이름 (text-small font-medium, 14px) - - flex layout, 하단 구분선 (마지막 제외) - - 상태 표시 제거됨 (발언 중/온라인 등 표시 안 함) - - - **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가 회의록 생성할 때 모든 참여자의 메모 참조 - - - **용어 사전 탭** - - 제목: "용어 사전" - - 용어 검색 입력 필드 (placeholder: "용어 검색...") - - **카드 디자인** (gappa 스타일): - - 기본 상태: - - 배경: 화이트 (#FFFFFF) - - 테두리: 회색 실선 (1px solid #E5E7EB) - - 테두리 둥글기: 8px - - 내부 패딩: 16px - - 카드 간 여백: 12px - - 하이라이트 상태 (현재 회의에서 언급된 용어): - - 배경: 민트 그린 연한 배경 (#E8F9F3) - - 테두리: 민트 그린 실선 (1px solid #4DD5A7) - - 호버 시: 회색 배경 (#F9FAFB) - - - **용어 카드 구조**: - - 용어명 (16px bold) + 카테고리 배지 (민트 그린 연한 배경) + 언급 아이콘 (💬, 언급된 경우만) - - 정의: 14px 일반 텍스트 (gray-600) - - 컨텍스트 (11px, gray-500, 상단 회색 구분선): - - "회의에서 N회 언급됨" (현재 회의에서 언급) - - "관련 회의록에서 언급됨" (관련 회의록에만 언급) - - "회의에서 언급됨 (HH:MM)" (시간 정보 포함) - - "{관련 회의록명} (날짜)에서 {컨텍스트 정보}" (특정 관련 회의록 정보) - - - **용어 카드 예시**: - - AI + 기술 배지 + 💬 - - 정의: Artificial Intelligence의 약자로, 인공지능을 의미합니다. 이 프로젝트에서는 회의록 자동 작성에 활용됩니다. - - 컨텍스트: "회의에서 5회 언급됨" - - API Gateway + 아키텍처 배지 + 💬 - - 정의: 클라이언트와 백엔드 마이크로서비스 사이의 단일 진입점 역할을 하는 서버 - - 컨텍스트: "API 설계 리뷰 회의 (2024-09-28)에서 AWS API Gateway 채택 결정" - - 마이크로서비스 + 아키텍처 배지 (하이라이트 없음) - - 정의: 애플리케이션을 작고 독립적인 서비스로 분할하는 소프트웨어 아키텍처 스타일 - - 컨텍스트: "관련 회의록에서 언급됨" - - MVP + 방법론 배지 + 💬 - - 정의: Minimum Viable Product의 약자 - - 컨텍스트: "회의에서 언급됨 (14:23)" - - RESTful API + 기술 배지 + 💬 - - 정의: REST 아키텍처 스타일로 작성한 웹 서비스 API 설계 방식 - - 컨텍스트: "회의에서 3회 언급됨" - - - 카드 클릭 시: 상세 설명 모달 표시 - - - **관련 자료 탭** (32건) - - 제목: "관련 회의록 (32건)" - - **카드 디자인** (gappa 스타일): - - 배경: 회색 (#F5F5F5) - - 테두리: 회색 점선 (1px dashed #9CA3AF) - - 테두리 둥글기: 8px - - 내부 패딩: 16px - - 카드 간 여백: 12px - - 호버 시: 회색 배경 (#F3F4F6) - - 구조: 헤더 + 메타정보 + 요약 텍스트 - - - **관련 회의록 카드 구조**: - - 헤더: 회의록 제목 (16px bold) - - 메타정보: 날짜 + 관련도 (12px, gray-500) - - 요약: 회의록 핵심 내용 또는 관련 컨텍스트 (14px 일반, gray-600) - - - **관련 회의록 예시**: - - "2024년 4분기 제품 기획 회의" - - 메타정보: 2024-10-15 | 관련도 92% - - 요약: 신규 회의록 서비스의 MVP 범위와 일정을 논의. AI 기반 회의 요약 기능의 우선순위를 높게 설정. - - "API 설계 리뷰 회의" - - 메타정보: 2024-09-28 | 관련도 78% - - 요약: RESTful API 설계 패턴과 API Gateway 채택. 마이크로서비스 간 통신 방식 결정. - - "스프린트 회고 회의" - - 메타정보: 2024-10-01 | 관련도 65% - - 요약: 협업 도구 사용성 개선과 MVP 개발 프로세스 최적화 논의. - - - 카드 클릭 시: **새 탭으로 열기** (target="_blank") - -**반응형 디자인** -- **Mobile (320px~768px)** - - 헤더: 고정 상단, 좁은 너비 - - 메인 콘텐츠: 전체 너비 사용 - - 탭 콘텐츠: 세로 스크롤 - - 하단 버튼 영역: 고정 하단 - -- **Desktop (768px+)** - - 헤더: 고정 상단, 넓은 너비 - - 메인 콘텐츠: 최대 너비 제한 없이 반응형 - - 탭 콘텐츠: 더 넓은 영역 활용 - - 하단 버튼 영역: 고정 하단 +**관련 자료 탭**: +- 관련 회의록 카드 (제목 + 날짜 + 관련도 + 요약) +- 카드 클릭 → 새 탭 열기 #### 인터랙션 +- 탭 전환: 클릭으로 콘텐츠 교체 +- 참여자 초대: [참여자 관리 패턴](#참여자-관리) 참조 +- AI 메모 저장: "저장" 클릭 → "N개 메모 저장됨" 토스트 +- 용어 검색: 실시간 필터링 +- 회의 종료: 확인 다이얼로그 → 07-회의종료 -1. **탭 전환** - - **참여자 탭**: 현재 회의 참여자 목록 표시 (4명) 및 참여자 추가 기능 - - **참여자 추가 폼** (상단): - - 이메일 입력 필드 (form-control 스타일, placeholder: "이메일 주소 입력") - - "초대" 버튼 (btn btn-primary btn-sm) - - 이메일 입력 후 "초대" 클릭 시: - 1. 이메일 유효성 검증 (정규식: /^[^\s@]+@[^\s@]+\.[^\s@]+$/) - 2. 빈 값 체크: 빈 값이면 "이메일 주소를 입력해주세요" 경고 토스트 - 3. 잘못된 형식: "올바른 이메일 형식이 아닙니다" 오류 토스트 - 4. 유효한 이메일: "{email}에게 초대 링크가 전송되었습니다" 성공 토스트 - 5. 입력창 초기화 (value = '') - 6. 실제 구현 시 서버 API 호출 (/api/meetings/invite) - - **참여자 목록** (하단): - - 각 참여자: 아바타 + 이름 - - 상태 표시 없음 (발언 중/온라인 등 제거) - - 참여자 수 동적 업데이트 (초대 성공 시) +#### 데이터 +- **입력**: 회의 ID, 오디오 스트림, 참여자 이메일 +- **출력**: STT 텍스트, AI 주요 내용, 개인 메모, 용어 사전, 관련 회의록 +- **연동**: STT, AI, RAG, PARTICIPANT 서비스 - - **AI 기반 메모 탭** (UFR-PART-020): AI가 감지한 주요 내용을 참여자가 선택하여 개인 메모로 저장 - - **메모 작성 및 저장**: - - 메모 입력창에 자유롭게 메모 작성 가능 - - "저장" 버튼 클릭 시 개인 메모로 저장 (각 참여자별 개별 저장) - - 저장 성공 시 "{n}개의 메모가 저장되었습니다" 성공 토스트 - - 저장 실패 시 "메모 저장에 실패했습니다" 오류 토스트 - - **AI가 감지한 주요 내용**: - - 음성→텍스트 변환 후 AI가 실시간으로 회의 내용 분석 - - **중요한 내용으로 판단된 경우에만** 주요 내용 항목 표시 - - 각 항목: "[시간] 주요 내용 텍스트" 형식 (예: "[15:32] 예산 책정 관련 결정") - - 실시간 업데이트: 새로운 항목은 하단에 추가 - - 항목 클릭 시: - 1. 메모 입력창에 "[시간] 내용" 형식으로 자동 추가 - 2. 기존 메모가 있으면 줄바꿈 후 추가 - 3. 입력된 메모는 수정 가능 (자동/수동 구분 표시) - 4. 저장 버튼 활성화 - - **정책**: - - 메모는 회의 종료 전까지만 표시/편집 가능 - - 각 참여자의 메모는 다른 참여자에게 보이지 않음 - - 회의 종료 시 AI가 모든 참여자의 메모를 참조하여 회의록 생성 - - - **용어 사전 탭**: 회의에서 언급된 전문용어 설명 - - **용어 검색 기능**: - - 검색 입력창 (placeholder: "용어 검색...", form-control 스타일) - - 검색 버튼 (btn btn-primary btn-sm) - - Enter 키 지원 - - 검색 동작: - 1. 용어명과 정의 모두 검색 - 2. 일치하는 용어만 표시, 나머지는 숨김 - 3. 검색 결과에 하이라이트 효과 적용 - 4. 검색 결과 없으면 전체 목록 다시 표시 - 5. 입력창이 비어있으면 전체 목록 표시 - - 용어 카드: 용어명 + 카테고리 배지 + 간단한 정의 - - 카드 클릭 → 확장하여 상세 설명 표시 - - 상세 설명: 이 회의에서의 의미, 관련 회의록 링크 - - - **관련 자료 탭**: AI가 찾은 관련 회의록 (32건) - - 회의록 링크 클릭 → **새 탭(target="_blank")에서 해당 회의록 열기** - - **녹음 중인 페이지 이탈 방지**: 모든 링크는 새 탭으로 열림 - - 관련도 표시: 퍼센트 또는 별점으로 시각화 - -2. **회의 종료** - - 헤더의 "회의 종료" 버튼 클릭 - - 확인 다이얼로그 표시: "회의를 종료하시겠습니까?" - - 확인 → 회의 종료 처리 및 07-회의종료.html로 이동 - -3. **실시간 업데이트** - - STT 음성 인식 결과 실시간 반영 (3-5초 주기) - - AI 제안 실시간 업데이트 - - 용어 사전 자동 업데이트 (새로운 전문용어 감지 시) - - 관련 회의록 목록 동적 갱신 - -#### 데이터 요구사항 -- **입력**: - - 회의 ID - - 오디오 스트림 (실시간 STT용) - - 참여자 초대 이메일 -- **출력**: - - 실시간 텍스트 변환 결과 (STT) - - **AI가 감지한 주요 내용 목록** (시간 + 내용) - - **개인 메모** (각 참여자별 개별 저장) - - **전문용어 및 설명** (용어 사전) - - **관련 회의록 목록** (32건, 관련도 포함) - - 참여자 목록 -- **연동**: - - STT 서비스 (UFR-AI-010) - - AI 서비스 (주요 내용 감지, UFR-AI-040) - - RAG 서비스 (관련 회의록 검색, 전문용어 자동 감지) - - PARTICIPANT 서비스 (메모 저장, UFR-PART-020) - -#### 에러 처리 -- **마이크 권한 거부**: "마이크 권한이 필요합니다" 토스트 + 설정 안내 링크 -- **STT 실패**: "음성 인식에 실패했습니다" 토스트 + 재시도 안내 -- **AI 주요 내용 감지 실패**: "AI 주요 내용 감지에 실패했습니다" 토스트 (회의 계속 진행 가능) -- **메모 저장 실패**: "메모 저장에 실패했습니다" 토스트 + 재시도 버튼 -- **용어 사전 로드 실패**: "용어 사전을 불러올 수 없습니다" 메시지 표시 -- **관련 자료 검색 실패**: "관련 회의록을 찾을 수 없습니다" 메시지 표시 -- **참여자 초대 실패**: "초대 링크 전송에 실패했습니다" 토스트 + 재시도 버튼 -- **회의 종료 실패**: "회의 종료 중 오류가 발생했습니다" 토스트 + 재시도 버튼 +#### 에러 +- 마이크 권한 거부: "마이크 권한 필요" + 설정 안내 +- STT 실패: "음성 인식 실패" + 재시도 +- 메모 저장 실패: "메모 저장 실패" + 재시도 +- 용어/자료 로드 실패: 빈 상태 메시지 --- ### 07-회의종료 #### 개요 -- **목적**: 회의 종료 후 AI 요약 내용 확인 및 다음 단계 선택 +- **목적**: AI 요약 확인 및 다음 단계 선택 - **관련 유저스토리**: UFR-MEET-040, UFR-MEET-050, UFR-AI-010, UFR-AI-020, UFR-AI-036 -- **비즈니스 중요도**: 높음 -- **접근 경로**: 회의진행 → "회의 종료" 버튼 +- **접근 경로**: 회의진행 → "회의 종료" - **권한**: 회의 생성자 전용 -- **화면 정책**: **확인 전용 화면 (편집 불가)** - - 모든 내용은 읽기 전용 - - 안건 내용 수정 불가 - - Todo 수정 불가 - - 확인 후 다음 단계 선택만 가능 +- **정책**: 확인 전용 화면 (편집 불가) -#### 주요 기능 -1. 회의 통계 표시 (시간, 참여자, 발언 횟수 등) -2. 주요 키워드 클라우드 -3. **안건별 AI 요약 전체 표시** (신규) - - 안건별 AI 한줄 요약 (30자 이내, 편집 불가) - - 안건별 상세 요약 정리 - - 안건별 Todo 자동 추출 결과 -4. **3가지 선택 옵션 제공** (신규) - - 옵션 1: 회의록 수정 화면으로 이동 - - 옵션 2: 바로 최종 확정 - - 옵션 3: 대시보드로 이동 +#### 고유 기능 +1. 회의 통계 (시간, 참여자, 키워드) +2. **안건별 AI 요약 전체 표시** + - AI 한줄 요약 (30자, 읽기 전용, 🔒) + - 상세 요약 정리 + - Todo 자동 추출 결과 +3. **3가지 선택 옵션** + - 회의록 수정 (11번 화면) + - 바로 최종 확정 (모든 안건 자동 검증완료) + - 대시보드로 이동 (작성중 상태 유지) -#### UI 구성요소 - -**Mobile (320px~768px)** -- **헤더** - - "회의가 종료되었습니다" 메시지 - - 회의 제목 - -- **통계 카드** - - 회의 총 시간 - - 참여자 수 - - 주요 키워드 (태그 클라우드) - -- **안건별 AI 요약 섹션** (신규) - - **안건 카드** (안건 개수만큼 반복): - - **안건 제목** (H4, Bold) - - **AI 한줄 요약** (읽기 전용, 회색 배경 박스) - - 30자 이내 간결한 표현 - - 🔒 "편집 불가" 아이콘 표시 - - 민트 그린 좌측 액센트 라인 - - **상세 요약 정리** (읽기 전용) - - 발언자별 의견 - - 결정 사항 - - 보류 사항 - - **Todo 자동 추출 결과** (있는 경우) - - Todo 항목 리스트 - - 담당자, 마감일, 우선순위 표시 - - 읽기 전용 (체크박스 비활성화) - -- **3가지 선택 옵션** (하단 액션 바) - - **옵션 1**: "회의록 수정" 버튼 (Secondary) - - 회의록 수정 화면(11-회의록수정)으로 이동 - - 회의록 상태: 작성중 - - **옵션 2**: "바로 최종 확정" 버튼 (Primary, 강조) - - 확인 다이얼로그: "AI가 정리한 내용 그대로 최종 확정하시겠습니까?" - - 모든 안건 자동 검증 완료 처리 - - 회의록 상태: 확정완료 - - 참여자에게 확정 알림 발송 - - **옵션 3**: "대시보드로 이동" 버튼 (Ghost) - - 회의록 상태: 작성중 (추후 편집 가능) - - 대시보드로 이동 - -**Tablet/Desktop (768px+)** -- 상단: 통계 카드 (Grid Layout) -- 중앙: 안건별 AI 요약 섹션 (2열 그리드) -- 하단: 3가지 선택 옵션 버튼 (가로 배치) +#### UI 구성 +- **헤더**: "회의가 종료되었습니다" + 회의 제목 +- **통계 카드**: 회의 시간, 참여자, 키워드 클라우드 +- **안건 카드**: 제목 + AI 한줄 요약(회색 배경, 민트 그린 액센트) + 상세 요약 + Todo +- **액션 바**: "회의록 수정"(Secondary), "바로 최종 확정"(Primary), "대시보드로 이동"(Ghost) #### 인터랙션 -1. **통계 표시** - - 애니메이션 효과로 숫자 카운트업 - - 차트는 페이드인 효과 +- 안건 카드 확장/축소 +- AI 한줄 요약 호버 → "편집 불가" 툴팁 +- **옵션 1**: 11-회의록수정 이동 (작성중 상태) +- **옵션 2**: 확인 다이얼로그 → 모든 안건 검증완료 처리 → 확정완료 → 10-회의록상세조회 +- **옵션 3**: 대시보드 이동 (작성중 상태) -2. **안건별 AI 요약 확인** (읽기 전용) - - **안건 카드 확장/축소**: - - 초기: 안건 제목 + AI 한줄 요약만 표시 - - 클릭 시: 상세 요약 + Todo 전체 펼침 - - **편집 불가 안내**: - - AI 한줄 요약 영역에 🔒 아이콘 표시 - - 호버 시: "이 내용은 편집할 수 없습니다" 툴팁 - - **Todo 확인**: - - 체크박스 비활성화 (disabled) - - 읽기 전용 표시 - -3. **다음 단계 선택** - - **옵션 1: 회의록 수정** - - 11-회의록수정.html로 이동 - - URL 파라미터: meetingId - - 회의록 상태: 작성중 - - **옵션 2: 바로 최종 확정** (UFR-MEET-050 시나리오 2) - - 확인 다이얼로그 표시: "바로 최종 확정하시겠습니까? AI가 정리한 내용 그대로 확정됩니다." - - 확인 시: - - 모든 안건 검증률 100% 자동 설정 - - 안건별 검증완료 처리 - - 회의록 상태: "작성중" → "확정완료"로 변경 - - 확정 시간 기록 - - 참여자에게 확정 알림 발송 - - 성공 토스트: "회의록이 최종 확정되었습니다" - - 10-회의록상세조회.html로 이동 - - **시나리오 2 특징 (바로 확정)**: - - 회의록 수정 단계를 건너뜀 - - AI 생성 내용을 그대로 확정 - - 모든 안건이 자동으로 검증완료 처리됨 - - 확정 후에도 회의 생성자는 수정 가능 (잠금 해제 필요) - - **옵션 3: 대시보드로 이동** - - 회의록 상태: 작성중 - - 02-대시보드.html로 이동 - - 추후 회의록 목록에서 편집 가능 - -#### 데이터 요구사항 +#### 데이터 - **입력**: 회의 ID -- **출력**: - - 회의 통계 (시간, 참여자 수, 발언 통계, 키워드) - - **안건별 AI 요약 데이터**: - - 안건 제목 - - AI 한줄 요약 (30자 이내) - - 상세 요약 정리 (논의 주제, 발언자별 의견, 결정 사항, 보류 사항) - - 안건별 Todo 목록 (제목, 담당자, 마감일, 우선순위) - - 회의록 상태 (작성중/확정완료) -- **연동**: Meeting 서비스, AI 서비스 +- **출력**: 통계, 안건별 AI 요약(한줄 + 상세), Todo 목록, 회의록 상태 +- **연동**: Meeting, AI 서비스 -#### 에러 처리 -- **통계 생성 실패**: "통계를 생성할 수 없습니다" + 건너뛰기 옵션 -- **AI 요약 생성 실패**: "AI 요약을 생성할 수 없습니다. 회의록 수정 화면에서 직접 작성해주세요" -- **바로 확정 실패**: "회의록 확정에 실패했습니다. 다시 시도해주세요" -- **네트워크 오류**: 자동 재시도 3회, 실패 시 재시도 버튼 제공 +#### 에러 +- 통계 생성 실패: "건너뛰기" 옵션 +- AI 요약 실패: "회의록 수정 화면에서 직접 작성해주세요" +- 바로 확정 실패: "다시 시도" 버튼 +- [네트워크 오류](#네트워크-오류) 참조 (자동 재시도 3회) --- ### 10-회의록상세조회 #### 개요 -- **목적**: 지난 회의록의 전체 내용 및 상세 정보 확인 +- **목적**: 회의록 전체 내용 및 상세 정보 확인 - **관련 유저스토리**: UFR-MEET-047, UFR-AI-040, UFR-MEET-048 -- **비즈니스 중요도**: 중간 -- **접근 경로**: 대시보드 → "내 회의록" 항목 클릭 -- **권한**: 모든 회의 참여자 (조회 전용) +- **접근 경로**: 대시보드 → "내 회의록" 클릭 +- **권한**: 모든 참여자 (조회 전용) -#### 주요 기능 (MVP 스코프 축소 v1.5.0) -1. 회의 기본 정보 표시 -2. **안건별 AI 요약 표시** (안건 최상단) -3. 안건별 상세 내용 표시 -4. **참고자료 표시** (안건 하단) -5. **Todo 단순 조회** (UFR-MEET-047): 제목, 담당자만 표시 (D-day, 우선순위 라벨 제거) -6. 첨부파일 다운로드 -7. 회의록 수정/공유 액션 +#### 고유 기능 +1. 회의 기본 정보 + 상태 배지 +2. **2개 탭 구조**: 대시보드 / 회의록 +3. **대시보드 탭**: 핵심내용, 결정사항, Todo, 참고자료 요약 +4. **회의록 탭**: 안건별 구조 (AI 요약 + 내용 + 참고자료) -**변경사항 (v1.5.0)**: -- ❌ 제거: Todo 관리 화면 연동 링크 (화면 자체가 제거됨) -- ❌ 제거: Todo D-day 라벨, 우선순위 배지 표시 -- ✅ 변경: Todo는 단순 조회만 가능 (제목 + 담당자 + 마감일만 표시) -- ✅ 변경: "수정" 버튼을 회의 제목 우측으로 이동 +#### UI 구성 +- **헤더**: 뒤로가기, 회의 제목, "수정"(우측), 메뉴 +- **기본 정보 카드**: 일시, 참여자, 장소, 상태, 작성자 +- **탭 네비게이션**: 대시보드 (기본) / 회의록 -#### UI 구성요소 +**대시보드 탭**: +- 핵심내용 (4-5개 포인트, 키워드 클라우드, 통계) +- 결정사항 (카드 리스트) +- Todo 진행상황 (제목 + 담당자 + 마감일만, D-day/우선순위 제거) +- 참고자료 (관련 회의록/문서, 관련도 배지) -**Mobile (320px~768px)** -- **헤더** - - 뒤로가기 버튼 - - 회의 제목 - - "수정" 버튼 (회의 제목 우측, 아이콘 또는 텍스트 버튼) - - 메뉴 버튼 (삭제, 공유 등) - -- **기본 정보 카드** - - 회의 일시 - - 참여자 아바타 및 이름 (역할 구분) - - 회의 장소 - - 회의록 상태 배지 (작성중/확정완료) - - 작성자 및 최종 수정 시간 - -- **탭 네비게이션** (상단, Fixed) - - "대시보드" 탭 (기본 활성) - - "회의록" 탭 - -- **회의록 탭 콘텐츠** (안건별 구조) - - 각 안건: - - 안건 제목 - - 검증 완료 배지 (검증된 경우) - - **AI 회의 내용 요약 영역** (안건 최상단, 강조 박스) - - 요약 아이콘 (💡) - - AI 자동 생성 요약 (2-3문장) - - 요약 생성/수정 시간 - - "수정" 버튼 (권한 있는 경우) - - 안건 내용 (마크다운 렌더링) - - **참고자료 영역** (안건 하단, 별도 영역) - - "참고자료" 라벨 - - 관련 회의록 링크 리스트 (최대 3개): - - 링크 아이콘 (📄) - - 회의 제목 (클릭 가능) - - 회의 날짜 - - 관련도 표시 (퍼센트, 색상 코딩) - - 1-2줄 요약 - - "더보기" 버튼 (3개 초과 시) - - 접기/펼치기 버튼 (선택) - -- **대시보드 탭 콘텐츠** (11-회의록대시보드.html 구조 참조) - - **핵심내용 섹션** (💡) - - 번호 매김된 핵심 포인트 (4-5개) - - 주요 키워드 태그 클라우드 - - 회의 통계 (참여자 수, 시간, 발언 횟수, 주요 의제 수) - - - **결정사항 섹션** (✅) - - 결정사항 카드 리스트 - - 각 카드: 결정 내용 + 결정자 + 시간 + 배경 설명 - - - **Todo 진행상황 섹션** (📋) - MVP 스코프 축소 - - **단순 조회만 제공** (UFR-MEET-047) - - Todo 리스트: - - 각 Todo: 제목 + 담당자 + 마감일만 표시 - - ❌ 제거: D-day 라벨, 우선순위 배지, 진행률 바, 상태별 필터 - - ❌ 제거: Todo 관리 화면 연동 (클릭 액션 없음) - - - **참고자료 섹션** (📚) - - 참고자료 탭 (관련 회의록/프로젝트 문서/이슈 트래커/위키 페이지) - - 각 참고자료 카드: - - 아이콘 + 제목 + 메타정보 (날짜, 작성자) - - 관련도 점수 배지 (92%, 88% 등) - - 2-3줄 요약 - - - **Todo 섹션** (단순 조회) - MVP 스코프 축소 - - Todo 항목 리스트: - - Todo 내용 (제목) - - 담당자 이름 - - 마감일 - - ❌ 제거: 체크박스, 우선순위 배지, D-day 라벨 - - - **첨부파일 섹션** - - 파일 아이콘 + 파일명 - - 다운로드 버튼 - -- **하단 액션 바** (Fixed) - MVP 스코프 축소 - - "공유" 버튼 - - ❌ 제거: "수정" 버튼 (헤더로 이동) - -**Tablet/Desktop (768px+)** -- **상단**: 탭 네비게이션 - - 대시보드 (기본 활성) - - 회의록 -- **메인 영역**: - - 회의록 탭: 전체 회의록 내용 (안건별 구조) - - 대시보드 탭: 핵심내용, 결정사항, Todo 진행상황, 참고자료 (11-회의록대시보드.html 구조 참조) +**회의록 탭**: +- 각 안건: 제목 + 검증 배지 + AI 요약(강조 박스) + 내용 + 참고자료(링크 리스트) #### 인터랙션 -1. **탭 전환** - - "회의록" 탭: 전체 회의록 내용 표시 (안건별 구조) - - "대시보드" 탭: 핵심내용, 결정사항, Todo, 참고자료 요약 표시 - - 탭 전환 시 URL 변경 없이 클라이언트 사이드 렌더링 +- 탭 전환: 클라이언트 사이드 렌더링 +- 안건 네비게이션: 제목 클릭 → 스크롤 +- AI 요약 편집: "수정" → 인라인 편집 (권한 있는 경우) +- 참고자료 링크: 새 탭 열기, 관련도 색상 코딩 +- "수정" 버튼: 11-회의록수정 +- "공유" 버튼: 회의록공유 화면 -2. **회의록 탭 인터랙션** - - **안건 네비게이션**: 안건 제목 클릭 → 해당 안건으로 스크롤 - - **접기/펼치기**: 긴 내용은 초기 접힌 상태, 클릭으로 펼침 - - **AI 요약 편집**: - - "수정" 버튼 클릭 (권한 있는 경우) → 인라인 편집 모드 - - 수정 내용 자동 저장 (30초 간격) - - 실시간 동기화 - - **참고자료 링크**: - - 회의록 링크 클릭 → 새 탭에서 해당 회의록 열기 - - 관련도 색상 코딩: 90%+ (초록), 70-89% (노랑), 70% 미만 (회색) - - "더보기" 클릭 → 전체 참고자료 목록 모달 - -3. **대시보드 탭 인터랙션** - MVP 스코프 축소 - - **핵심내용 섹션**: - - 키워드 태그 클릭 → 해당 키워드 관련 안건으로 스크롤 - - 통계 항목 클릭 → 상세 정보 툴팁 표시 - - **결정사항 섹션**: - - 결정사항 카드 클릭 → 회의록 탭의 해당 안건으로 이동 - - 배경 설명 접기/펼치기 - - **Todo 진행상황** (단순 조회만): - - ❌ 제거: 필터 탭, 진행률 바, Todo 관리 화면 연동 - - Todo는 읽기 전용으로만 표시 (클릭 액션 없음) - - **참고자료 섹션**: - - 탭 전환 (관련 회의록/프로젝트 문서/이슈 트래커/위키 페이지) - - 참고자료 카드 클릭 → 해당 문서로 이동 - - 관련도 점수: 배지로 표시 (92%, 88% 등) - -4. **Todo 인터랙션** - MVP 스코프 축소 - - ❌ 제거: Todo 체크박스, Todo 관리 화면 연동 - - Todo는 단순 조회만 가능 (클릭 액션 없음) - -5. **첨부파일 다운로드** - - 파일명 클릭: 다운로드 시작 - - 진행 상황 표시 - -6. **수정 및 공유** - - "수정" 버튼: 회의록수정 화면으로 이동 - - "공유" 버튼: 회의록공유 화면으로 이동 - -#### 데이터 요구사항 -- **입력**: 회의록 ID, 활성 탭 (회의록/대시보드/타임라인) +#### 데이터 +- **입력**: 회의록 ID, 활성 탭 - **출력**: - - **회의 기본 정보**: 제목, 일시, 참여자, 장소, 상태, 작성자, 수정 시간 - - **안건별 AI 요약**: 자동 생성 요약, 수정 이력 - - **안건별 내용**: 마크다운 형식 - - **참고자료 목록**: - - 관련 회의록 (제목, 날짜, 관련도, 요약) - - 프로젝트 문서 (제목, 작성자, 관련도) - - 이슈 트래커 링크 - - 위키 페이지 링크 - - **대시보드 데이터** (대시보드 탭 선택 시): - - 핵심내용 (4-5개 포인트) - - 주요 키워드 - - 회의 통계 (참여자 수, 시간, 발언 횟수, 의제 수) - - 결정사항 리스트 (결정 내용, 결정자, 시간, 배경) - - Todo 진행상황 (담당자별 그룹, 진행률) - - **Todo 목록 및 진행 상황** - - **첨부파일 목록** -- **연동**: Meeting 서비스, AI 서비스 (UFR-AI-040) + - 회의 기본 정보, 안건별 AI 요약, 안건별 내용 + - 참고자료 (회의록/문서, 관련도) + - 대시보드 데이터 (핵심내용, 결정사항, Todo, 통계) +- **연동**: Meeting, AI 서비스 -#### 에러 처리 -- **회의록 로딩 실패**: "회의록을 불러올 수 없습니다" + 재시도 버튼 -- **AI 요약 로딩 실패**: "요약을 불러올 수 없습니다" (안건 내용은 정상 표시) -- **참고자료 로딩 실패**: "참고자료를 불러올 수 없습니다" (빈 상태 표시) -- **대시보드 데이터 로딩 실패**: "대시보드를 불러올 수 없습니다" + 재시도 버튼 -- **권한 없음**: "수정" 버튼 비활성화, "조회 권한만 있습니다" 메시지 -- **첨부파일 다운로드 실패**: "파일 다운로드에 실패했습니다" +#### 에러 +- 회의록 로딩 실패: "다시 시도" +- AI 요약 로딩 실패: 안건 내용은 정상 표시 +- 참고자료 로딩 실패: 빈 상태 +- 대시보드 로딩 실패: "다시 시도" +- 권한 없음: "수정" 비활성화 --- ### 11-회의록수정 #### 개요 -- **목적**: 지난 회의록 조회 및 수정 +- **목적**: 회의록 조회 및 수정 - **관련 유저스토리**: UFR-MEET-055, UFR-AI-040, UFR-COLLAB-030 -- **비즈니스 중요도**: 중간 -- **접근 경로**: 10-회의록상세조회 → 하단 액션 바 "수정" 버튼 클릭 +- **접근 경로**: 10-회의록상세조회 → "수정" 버튼 - **권한 제어**: - - **검증완료 전**: 모든 참여자가 수정 가능 - - **검증완료 후**: 회의 생성자만 수정 가능 (참여자는 "수정" 버튼 비활성화) + - 검증완료 전: 모든 참여자 수정 가능 + - 검증완료 후: 회의 생성자만 수정 가능 -#### 주요 기능 (MVP 스코프 축소 v1.5.2) -1. 회의 기본 정보 표시 및 수정 - - 회의 제목: 수정 가능 - - 회의 일시/장소: 읽기 전용 (회의 예약 화면에서만 변경 가능) - - 참여자 관리: 회의 생성자만 추가/삭제 가능 -2. **회의록 내용 수정 (안건별)** - 용어 변경: 섹션 → 안건 -3. **AI 요약 표시 및 재생성 (안건별, UFR-AI-036)** - - AI 한줄 요약 표시 (30자 이내, 읽기 전용) - - 텍스트 편집 영역에서 안건 내용 수정 가능 - - "AI 재생성" 버튼: 텍스트 편집 영역 내용 기반으로 한줄 요약만 재생성 (2-5초 처리) - - 재생성된 한줄 요약은 회의록 상세조회 화면의 대시보드 및 회의록 탭에 즉시 반영 -4. **참고자료 편집** (추가/제거) -5. **Todo 단순 조회** (제목 + 담당자 + 마감일만 표시) -6. **안건별 검증 완료 체크박스 (UFR-COLLAB-030)** - - 회의 생성자: 검증 완료 체크박스 활성화, 잠금 해제 후 수정 가능 - - 참여자: 검증완료 안건은 읽기 전용 -7. 자동 저장 (30초 간격) -8. 수정 이력 관리 -9. 상태 변경 (검증완료 → 작성중으로 자동 변경) +#### 고유 기능 +1. 회의 기본 정보 수정 + - 제목: 수정 가능 + - 일시/장소: 읽기 전용 + - 참여자: 생성자만 추가/삭제 +2. **안건별 편집** + - AI 요약 (한줄, 30자, 읽기 전용) + - 텍스트 편집 영역 (안건 내용 자유 작성) + - "AI 재생성" 버튼 (한줄 요약 재생성, 2-5초) + - 참고자료 추가/제거 +3. **Todo 단순 조회** (제목 + 담당자 + 마감일만) +4. **안건별 검증 완료 체크박스** + - 생성자: 체크박스 활성, 잠금 해제 가능 + - 참여자: 검증완료 안건 읽기 전용 +5. 자동 저장 (30초 간격) +6. 상태 변경 (확정완료 → 작성중) -**변경사항 (v1.5.2)**: -- ✅ 명칭 변경: "AI 상세 요약" → "AI 요약" -- ✅ 기능 통합: AI 재생성 버튼 클릭 시 텍스트 편집 영역 내용 기반으로 한줄 요약 생성 (UFR-AI-036) -- ❌ 제거: AI 상세 요약 및 한줄 요약 분리 표시 (한줄 요약만 표시) -- ❌ 제거: 실시간 협업 표시 ("편집 중" 표시 제거) -- ❌ 제거: Todo 편집 기능 (체크박스, 담당자/마감일/우선순위 변경, 추가/삭제) -- ❌ 제거: 검증률 표시 및 최종 확정 버튼 -- ✅ 정책: Last Write Wins (마지막 저장 우선) 적용 - -#### UI 구성요소 - -**Mobile (320px~768px)** -- **헤더** - - 뒤로가기 버튼 (10-회의록상세조회로 이동) - - "회의록 수정" 타이틀 - - "저장" 버튼 (Primary) - - 자동 저장 인디케이터 ("저장됨", "저장 중...") - -- **회의 기본 정보 영역** - - 회의 제목: 편집 가능 (텍스트 필드) - - 회의 일시: 읽기 전용 (📅 아이콘 + 날짜/시간 표시) - - 회의 장소: 읽기 전용 (📍 아이콘 + 장소명) - - 참여자 목록: - - 회의 생성자: 추가/삭제 가능 (05-회의진행 화면과 동일한 UI) - - 참여자: 읽기 전용 표시 - - 각 참여자: 아바타 + 이름, 삭제(×) 버튼 (생성자는 삭제 불가) - - "참여자 추가" 버튼 (이메일 입력 + 초대) - - 회의록 상태 배지 (자동 관리) - -- **편집 화면** (MVP 스코프 축소) - - **안건별 편집 영역** (용어 변경: 섹션 → 안건) - - 각 안건: - - **안건 헤더** - - 안건 제목 (H4, Bold) - - 검증 상태 배지 (검증완료/미검증) - - ❌ 제거: "편집 중" 표시 (실시간 협업 기능 제거) - - **AI 요약** (읽기 전용, UFR-AI-036) - - 💡 "AI 요약" 레이블 - - AI 한줄 요약 표시 (30자 이내) - - 읽기 전용 영역 (회색 배경, 민트 그린 좌측 액센트 라인) - - 호버 시: "이 내용은 편집할 수 없습니다" 툴팁 - - **텍스트 편집 영역** - - 안건 내용 편집 필드 (textarea) - - 논의 주제, 발언자별 의견, 결정 사항, 보류 사항 등 자유 작성 - - "AI 재생성" 버튼: 텍스트 편집 영역 내용 기반으로 AI 요약의 한줄 요약 재생성 - - 마지막 수정 시간 표시 - - **참고자료 편집 영역** - - 기존 참고자료 목록 (제거 버튼 포함) - - "참고자료 추가" 버튼 - - 회의록 검색 및 선택 UI - - **Todo 섹션 단순 조회** (편집 불가) - - Todo 목록 표시 (읽기 전용) - - 각 Todo 항목: - - Todo 제목 - - 담당자 - - 마감일 - - ❌ 제거: 체크박스, 우선순위 배지, D-day 라벨, 편집/삭제 버튼 - - **안건별 검증 영역** (UFR-COLLAB-030) - - **회의 생성자 화면**: - - 검증 완료 체크박스 (활성화) - - "잠금 해제" 버튼 (검증완료 안건만 표시) - - **참여자 화면**: - - 🔒 "읽기 전용" 배지 (검증완료 안건) - - 안내 텍스트: "(잠금됨 · 회의 생성자만 수정 가능)" - - 자동 저장 상태 표시 ("저장됨", "저장 중...") - -**Tablet/Desktop (768px+)** -- **헤더**: Mobile과 동일 (뒤로가기, 타이틀, 저장 버튼, 자동 저장 인디케이터) -- **메인 영역**: - - 회의 기본 정보 영역 (Mobile과 동일) - - 편집 화면 (안건별 편집, AI 한줄/상세 요약, 참고자료, Todo, 안건별 검증) -- **우측 패널** (선택사항): - - 수정 이력 (v2.0 고도화 예정) - - 미리보기 +#### UI 구성 +- **헤더**: 뒤로가기, "회의록 수정", "저장", 자동 저장 인디케이터 +- **기본 정보**: 제목(편집), 일시(읽기), 장소(읽기), 참여자(생성자만 편집) +- **안건 편집**: + - 헤더 (제목 + 검증 배지) + - AI 요약 (읽기 전용, 회색 배경, 민트 액센트) + - 텍스트 편집 (textarea) + "AI 재생성" + - 참고자료 편집 ("참고자료 추가") + - Todo 섹션 (읽기 전용) + - 검증 영역 (체크박스 + "잠금 해제") #### 인터랙션 -1. **화면 진입** - - 10-회의록상세조회 → "수정" 버튼 클릭 - - 권한 확인: 검증완료 후에는 회의 생성자만 접근 가능 - - 바로 편집 모드로 시작 +- 화면 진입: 권한 확인 (검증완료 후 생성자만) +- 내용 수정: 자동 저장 30초, "저장" 수동 +- **AI 한줄 요약**: 읽기 전용, 호버 → "편집 불가" 툴팁 +- **AI 재생성**: 텍스트 편집 내용 기반으로 한줄 요약 재생성 +- **안건별 검증**: + - 생성자: 체크박스 클릭 → 검증완료/미검증 토글 + - 생성자: "잠금 해제" → 확인 다이얼로그 → 편집 가능 + - 참여자: 검증완료 안건 모든 필드 disabled +- **참고자료 편집**: [참고자료 관리 패턴](#참고자료-관리) 참조 +- **저장 로직**: 검증완료 안건 스킵, "N개 안건 저장, M개 스킵" 알림 +- **충돌 방지**: Last Write Wins (안건별 독립) -2. **내용 수정** - - 텍스트 영역 클릭: 포커스 및 편집 가능 - - 자동 저장: 30초 간격, 인디케이터 표시 - - 수동 저장: "저장" 버튼 클릭 +#### 데이터 +- **입력**: 회의록 ID, 수정 내용, AI 요약 수정, 참고자료 변경, 안건별 검증 상태 +- **출력**: 수정 결과, AI 한줄 요약(읽기), AI 상세 요약 재생성 결과, 수정 이력 +- **연동**: Meeting, AI(UFR-AI-036, UFR-AI-040), COLLAB 서비스 -3. **AI 한줄 요약 확인 (UFR-AI-036)** - MVP 스코프 축소 - - **읽기 전용 표시**: - - 🔒 아이콘으로 편집 불가 명시 - - 회색 배경 + 민트 그린 좌측 액센트 라인 - - **호버 인터랙션**: - - 툴팁 표시: "이 내용은 편집할 수 없습니다. 회의 종료 시 1회만 생성됩니다." - - **위치**: 각 안건 최상단 (안건 제목 바로 아래) - - ❌ 제거: "AI 재생성" 버튼 (한줄 요약은 회의 종료 시 1회만 생성) - -4. **AI 상세 요약 편집** - MVP 스코프 축소 - - 요약 텍스트 필드 클릭: 직접 수정 가능 - - "AI 재생성" 버튼 클릭: - - 현재 안건 내용 기반으로 **상세 요약만** 재생성 (한줄 요약 제외) - - 로딩 인디케이터 표시 - - 생성 완료 시 자동 업데이트 - - 자동 저장 (30초 간격) - -5. **안건별 검증 완료 체크박스 (UFR-COLLAB-030)** - MVP 스코프 축소 - - **회의 생성자 권한**: - - 검증 완료 체크박스 클릭: - - 체크: 안건 검증 완료 처리 (배지 "검증완료"로 변경) - - 언체크: 미검증 상태로 변경 - - "잠금 해제" 버튼 클릭 (검증완료 안건만 표시): - - 확인 다이얼로그: "이 안건의 잠금을 해제하시겠습니까?" - - 확인 시: 안건 검증 완료 체크 해제 → 편집 가능 상태로 변경 - - **참여자 화면**: - - 검증완료 안건: 🔒 "읽기 전용" 배지 표시 - - 안내 텍스트: "(잠금됨 · 회의 생성자만 수정 가능)" - - 모든 입력 필드 비활성화 (disabled) - - ❌ 제거: 검증률 계산 및 표시, "최종 확정" 버튼 - -6. **참고자료 편집** - - "참고자료 추가" 버튼 클릭: - - 회의록 검색 모달 표시 - - 제목, 날짜, 키워드로 검색 - - 선택된 회의록 추가 - - 제거 버튼 (X): 참고자료 목록에서 제거 - - 순서 변경: 드래그하여 순서 조정 (선택) - -7. **Todo 섹션 단순 조회** - MVP 스코프 축소 - - ❌ 제거: Todo 편집/추가/삭제 기능 전체 제거 - - Todo는 읽기 전용으로만 표시 (제목 + 담당자 + 마감일) - - 모든 사용자 (생성자 포함)에게 조회만 가능 - -8. **상태 변경** - MVP 스코프 축소 - - 확정완료 회의록 수정 시: 자동으로 "작성중" 상태로 변경 - - ❌ 제거: "확정완료"로 변경 제안 (검증률 기능 제거로 인해) - -9. **저장 로직** - MVP 스코프 축소 - - **"저장" 버튼 클릭 시**: - - 검증완료된 안건: 저장 스킵 - - 미검증 안건: 저장 진행 - - **저장 결과 알림**: - - "N개 안건이 저장되었습니다" - - "M개 안건은 검증완료 상태로 저장되지 않았습니다" - - 저장 불가 안건 목록 표시 - - **자동 저장** (30초 간격): - - 미검증 안건만 자동 저장 - - 검증완료 안건은 자동 저장 스킵 - -10. **안건 기반 충돌 방지 (UFR-COLLAB-030)** - MVP 스코프 축소 - - **안건 기반 충돌 방지 메커니즘**: - - **다른 안건 동시 편집**: 충돌 없음 - - 참여자 A가 안건 1 편집 - - 참여자 B가 안건 2 편집 가능 - - 양쪽 모두 정상 저장 - - - **동일 안건 검증 완료 체크로 충돌 방지**: - - 검증완료된 안건: 편집 불가 (회의 생성자만 잠금 해제 가능) - - 미검증 안건: Last Write Wins (마지막 저장 우선) - - - **동일 필드 동시 수정**: Last Write Wins - - 마지막에 저장된 변경 사항이 적용 - - 별도 경고 없이 덮어쓰기 - - - ❌ 제거: 실시간 "편집 중" 표시 - - ❌ 제거: 충돌 경고 모달 및 선택 옵션 - -#### 데이터 요구사항 (MVP 스코프 축소) -- **입력**: - - 회의록 ID (조회) - - 수정 내용 (안건 ID, 내용) - 용어 변경: 섹션 → 안건 - - **AI 한줄 요약** (읽기 전용, 입력 불가) - - **AI 상세 요약 수정** (안건 ID, 요약 내용) - - **참고자료 변경** (추가/제거할 회의록 ID) - - **안건별 검증 상태** (안건 ID, 검증 여부) -- **출력**: - - 회의록 목록 (필터/정렬/검색 결과) - - 수정 결과 (성공/실패) - - **AI 한줄 요약** (회의 종료 시 생성, 편집 불가) - - **AI 상세 요약 재생성 결과** (한줄 요약 제외) - - 수정 이력 (누가, 언제, 무엇을) - - ❌ 제거: 검증률 출력 -- **연동**: Meeting 서비스, AI 서비스 (UFR-AI-010, UFR-AI-036, UFR-AI-040), COLLAB 서비스 (UFR-COLLAB-030) - -#### 에러 처리 (MVP 스코프 축소) -- **권한 없음**: "본인이 작성한 회의록만 수정할 수 있습니다" -- **자동 저장 실패**: "네트워크 연결을 확인해주세요. 로컬에 임시 저장됩니다" -- **AI 요약 재생성 실패**: "요약 생성에 실패했습니다. 수동으로 작성해주세요" -- **참고자료 검색 실패**: "회의록을 검색할 수 없습니다" -- **검증완료 안건 저장 시도**: - - 저장 결과 알림: "N개 안건이 저장되었습니다. M개 안건은 검증완료 상태로 저장되지 않았습니다" - - 저장 불가 안건 목록 표시 -- **삭제 실패**: "회의록 삭제에 실패했습니다" -- ❌ 제거: 충돌 경고 모달 (Last Write Wins 적용으로 인해) +#### 에러 +- 권한 없음: "본인이 작성한 회의록만 수정 가능" +- 자동 저장 실패: "네트워크 확인, 로컬 임시 저장" +- AI 재생성 실패: "수동 작성해주세요" +- 참고자료 검색 실패: "회의록 검색 불가" +- 검증완료 저장 시도: 스킵 알림 + 목록 표시 --- ### 12-회의록목록조회 #### 개요 -- **목적**: 회의록 목록 조회 및 필터링/정렬/검색 기능 제공 -- **관련 유저스토리**: UFR-MEET-046 (회의록목록조회) -- **비즈니스 중요도**: 높음 -- **프로토타입**: design/uiux/prototype/12-회의록목록조회.html -- **데이터 소스**: common.js → SAMPLE_MINUTES 배열 (30개 샘플 데이터) -- **접근 경로**: - - 대시보드 → "내 회의록" 전체 보기 - - 하단 네비게이션 → "회의록" 메뉴 -- **권한**: 모든 회의 참여자 (본인이 참여한 회의록만 조회) +- **목적**: 회의록 목록 조회 및 필터링/정렬/검색 +- **관련 유저스토리**: UFR-MEET-046 +- **접근 경로**: 대시보드 → "전체 보기" 또는 하단 네비게이션 → "회의록" +- **권한**: 모든 참여자 (본인 참여 회의록만) -#### 데이터 아키텍처 -- **데이터 레이어**: common.js의 SAMPLE_MINUTES 배열 - - 총 30개 샘플 데이터 (작성중 13개, 확정완료 17개) - - 각 회의록 객체 구조: id, meetingId, title, date, time, status, participants, participantCount, lastUpdated, sections, todos, completionRate -- **뷰 레이어**: 12-회의록목록조회.html - - JavaScript 기반 동적 렌더링 - - renderMeetings() 함수: 필터링/정렬/검색 로직 처리 후 목록 생성 - - createMeetingCard() 함수: 개별 회의록 카드 HTML 생성 -- **렌더링 방식**: - - 페이지 로드 시: DOMContentLoaded 이벤트에서 renderMeetings() 호출 - - 초기 표시: 10개 회의록 (displayedCount 변수로 관리) - - 추가 로딩: "10개 더보기" 버튼 클릭 시 10개씩 증가 - - 필터/정렬/검색 시: 즉시 renderMeetings() 재호출하여 목록 갱신 +#### 고유 기능 +1. **필터링**: 참여 유형 (전체/참여/생성), 상태 (전체/작성중/확정완료) +2. **정렬**: 최근수정순 (기본), 최근회의순, 제목순 +3. **검색**: 제목, 참여자, 키워드 통합 검색 (실시간) +4. **페이지네이션**: 초기 10개, "10개 더보기" -#### 주요 기능 -1. **회의록 목록 조회** (참여/생성한 회의록) -2. **필터링 기능**: - - 참여 유형: 참여한 회의, 생성한 회의 - - 상태: 전체, 작성중, 확정완료 -3. **정렬 기능**: - - 최근수정순 (수정 일시 기준, 최근 순) - 기본값 - - 최근회의순 (회의 일시 기준, 최근 순) - - 제목순 (가나다순) -4. **검색 기능**: - - 제목, 참여자, 키워드로 통합 검색 - - 실시간 검색 결과 업데이트 -5. **페이지네이션**: - - 초기 10개 회의록 표시 - - "10개 더보기" 버튼으로 추가 로딩 -6. 회의록 상세 조회 (항목 클릭 시) - -#### UI 구성요소 - -**Mobile (320px~768px)** -- **헤더** (Fixed, 상단) - - 뒤로가기 버튼 - - "내 회의록" 타이틀 - - 검색 아이콘 (검색창 포커스) - -- **필터 및 정렬** (상단, 스크롤 가능) - - **필터 행 1** (2컬럼 그리드): - - 상태 필터 (Select) - - 옵션: 전체, 작성중, 확정완료 - - 기본값: 전체 - - 정렬 (Select) - - 옵션: 최신순, 회의일시순, 제목순 - - 기본값: 최신순 - - - **참여 유형 필터** (탭 형식, 선택): - - 전체 (기본 선택) - - 참여한 회의 - - 생성한 회의 - -- **검색 영역** - - 검색 입력 필드 - - Placeholder: "회의 제목, 참여자, 키워드 검색" - - 실시간 검색 (입력 시 즉시 필터링) - -- **통계 정보** (카드, 선택) - - 3컬럼 그리드: - - 전체: {count}개 - - 작성중: {count}개 - - 확정완료: {count}개 - - 구분선으로 시각적 분리 - -- **회의록 목록** (스크롤 가능) - - 각 회의록 항목 (meeting-item): - - **좌측 영역**: - - 회의 제목 (H5, 볼드) - - **생성자 표시**: 현재 사용자가 회의 생성자인 경우 👑 아이콘 표시 (16px, title="생성자") - - 메타정보 (Caption, 회색): - - 회의 일시 (날짜 + 시간) · 참여자 수 - - 검증완료율 (작성중 상태일 때만): "✓ {completionRate}% 검증완료" 배지 - - 최종 수정 시간 (Caption, 회색): - - 상대 시간 표시 ("1시간 전", "어제", "3일 전") - - **우측 영역**: - - 상태 배지: - - "확정완료" (초록색 배지) - - "작성중" (노란색 배지) - - 조회 권한 표시 (조회 전용인 경우): - - "조회 전용" (Caption, 회색) - - 빈 상태: - - 검색 결과 없음: "검색 결과가 없습니다" - - 회의록 없음: "회의록이 없습니다" - -**Mobile (320px~768px)** -- **하단 네비게이션**: [Mobile 하단 네비게이션](#mobile-하단-네비게이션-320px768px) 참조 (회의록 활성) - -**Tablet/Desktop (768px+)** -- **좌측 사이드바**: [Desktop 좌측 사이드바](#desktop-좌측-사이드바-768px) 참조 (회의록 활성) - -- **메인 콘텐츠** (중앙) - - 필터 및 정렬 (상단, 가로 배치) - - 참여 유형 필터 (탭 또는 버튼 그룹) - - 검색 영역 - - 통계 정보 (3컬럼 카드) - - 회의록 목록 (Grid 또는 List Layout) - - 각 카드: 호버 시 그림자 증가, 약간 상승 +#### UI 구성 +- **헤더**: 뒤로가기, "내 회의록", 검색 아이콘 +- **필터/정렬**: + - 필터 행 (2컬럼): 상태 Select + 정렬 Select + - 참여 유형 탭 (선택): 전체/참여/생성 +- **검색**: "회의 제목, 참여자, 키워드 검색" placeholder +- **통계 카드** (3컬럼): 전체, 작성중, 확정완료 개수 +- **회의록 목록**: + - 각 항목: 제목 + 생성자(👑) + 일시/참여자 + 검증완료율(작성중만) + 수정시간 + 상태 배지 + - 빈 상태: "검색 결과 없음" / "회의록 없음" +- **네비게이션**: [하단 네비게이션](#mobile-하단-네비게이션-320px768px) / [사이드바](#desktop-좌측-사이드바-768px) 참조 #### 인터랙션 +- 필터/정렬 변경 → 즉시 재렌더링 +- 검색 입력 → 실시간 (debounce 300ms) +- 회의록 클릭 → 10-회의록상세조회 +- 통계 자동 갱신 (필터/검색 적용 시) -1. **필터링** - - 상태 필터 변경 → 즉시 목록 재렌더링 - - 참여 유형 탭 선택 → 해당 유형 회의록만 표시 - - 필터 조합 가능 (상태 + 참여 유형) +#### 데이터 +- **입력**: 사용자 ID, 필터(참여 유형, 상태), 정렬, 검색어 +- **출력**: 회의록 목록 (회의 기본 정보 + 생성자 ID + 조회 권한), 통계 (전체/작성중/확정완료 개수) +- **연동**: Meeting 서비스 -2. **정렬** - - 정렬 옵션 선택 → 즉시 목록 재정렬 - - 정렬 기준: - - 최신순: `updatedAt DESC` - - 회의일시순: `meetingDate DESC` - - 제목순: `title ASC` (한글 가나다순) - -3. **검색** - - 검색 아이콘 클릭 → 검색 입력 필드에 포커스 - - 텍스트 입력 → 실시간 검색 (debounce 300ms) - - 검색 범위: - - 회의 제목 (부분 일치) - - 참여자 이름 (부분 일치) - - 키워드 (태그, 내용에서 추출된 키워드) - - 검색어 지우기: X 버튼 (검색어 입력 시 표시) - -4. **회의록 조회** - - 회의록 항목 클릭 → 회의록 상세 화면으로 이동 - - 전달 데이터: 회의록 ID - - 조회 전용 회의록: 읽기 모드로 표시 - -5. **통계 업데이트** - - 필터/검색 적용 시 → 통계 자동 갱신 - - 전체, 작성중, 확정완료 개수 실시간 반영 - -6. **빈 상태 처리** - - 검색 결과 없음: "검색 결과가 없습니다" 메시지 - - 필터링 결과 없음: 필터 조건에 맞는 회의록 없음 안내 - - 회의록 없음: "회의록이 없습니다" + 회의 시작 유도 메시지 - -#### 데이터 요구사항 - -- **입력**: - - 사용자 ID (현재 로그인 사용자) - - 필터 조건: - - 참여 유형: `all` | `shared` | `attended` | `created` - - 상태: `all` | `draft` | `confirmed` - - 정렬 기준: `recent` | `date` | `title` - - 검색어 (선택) - -- **출력**: - - 회의록 목록: - - 회의 ID - - 제목 - - 회의 일시 - - 참여자 목록 (또는 참여자 수) - - 상태 (`draft` | `confirmed`) - - 생성자 ID - - 생성일시 (`createdAt`) - - 수정일시 (`updatedAt`) - - 조회 권한 (편집 가능 여부) - - 통계: - - 전체 개수 - - 작성중 개수 - - 확정완료 개수 - -- **연동**: - - Meeting 서비스 (회의록 목록 조회 API) - - Share 서비스 (공유 정보 조회) - -#### 에러 처리 - -- **데이터 로딩 실패**: - - "회의록을 불러오는 중 오류가 발생했습니다." 메시지 - - "다시 시도" 버튼 제공 - -- **검색 실패**: - - "검색 중 오류가 발생했습니다." 토스트 메시지 - - 기존 목록 유지 - -- **네트워크 오류**: - - "네트워크 연결을 확인해주세요." 토스트 메시지 - - 자동 재시도 (최대 3회, exponential backoff) - -- **권한 없음**: - - 접근 권한 없는 회의록 클릭 시: - - "접근 권한이 없습니다" 토스트 메시지 - - 목록으로 복귀 - -- **빈 상태**: - - 검색 결과 없음: "검색 결과가 없습니다" - - 필터링 결과 없음: "조건에 맞는 회의록이 없습니다" - - 전체 회의록 없음: "회의록이 없습니다. 첫 회의를 시작해보세요!" + 회의 시작 버튼 +#### 에러 +- 데이터 로딩 실패: "다시 시도" 버튼 +- 검색 실패: 토스트, 기존 목록 유지 +- [네트워크 오류](#네트워크-오류) 참조 (자동 재시도 3회) +- 권한 없음: 클릭 시 "접근 권한 없음" 토스트 +- 빈 상태: "검색 결과 없음" / "조건에 맞는 회의록 없음" / "회의록 없음 + 회의 시작 버튼" [↑ 목차로 돌아가기](#목차) @@ -1640,57 +599,68 @@ graph TD ### 네비게이션 -#### Mobile 하단 네비게이션 (320px~768px) - **v1.5.0 변경** -- **위치**: Fixed, 하단 (height: 64px) -- **배경**: 흰색, 상단 테두리 (1px solid #E5E7EB) -- **그림자**: 0 -2px 8px rgba(0, 0, 0, 0.08) -- **구성**: 2개 항목 (균등 분할) - - **홈** (대시보드) - - 아이콘: 🏠 (24px) - - 텍스트: "홈" (12px) - - 활성 상태: 민트 그린 (#4DD5A7) - - 비활성 상태: 회색 (#6B7280) - - **회의록** (회의록 목록) - - 아이콘: 📋 (24px) - - 텍스트: "회의록" (12px) - - ~~**Todo** (Todo 관리)~~ (MVP v2.4.0에서 제거됨) - - ~~아이콘: ✅ (24px)~~ - - ~~텍스트: "Todo" (12px)~~ -- **사용 화면**: 02-대시보드, 12-회의록목록조회 -- **참고**: 프로필 메뉴는 프로토타입에서 제거됨 (Desktop 사이드바의 사용자 정보 영역으로 통합) +#### Mobile 하단 네비게이션 (320px~768px) +- **위치**: Fixed, 하단 (64px) +- **구성**: 2개 항목 균등 분할 + - 홈 (🏠, "홈", 대시보드) + - 회의록 (📋, "회의록", 회의록 목록) +- **활성 상태**: 민트 그린 (#4DD5A7) +- **비활성**: 회색 (#6B7280) -#### Desktop 좌측 사이드바 (768px+) - **v1.5.0 변경** -- **위치**: Fixed, 좌측 (width: 240px) -- **배경**: 흰색, 우측 테두리 (1px solid #E5E7EB) +#### Desktop 좌측 사이드바 (768px+) +- **위치**: Fixed, 좌측 (240px) - **구성**: - - **상단 영역**: - - 서비스 로고 (32px) - - 서비스명 (16px Bold) - - **메인 메뉴**: - - 대시보드 - - 내 회의록 - - ~~Todo~~ (MVP v2.4.0에서 제거됨) - - **하단 영역**: - - 사용자 정보 (아바타 + 이름) - - 로그아웃 버튼 (btn-ghost btn-sm) -- **사용 화면**: 02-대시보드, 12-회의록목록조회 + - 상단: 로고 + 서비스명 + - 메인 메뉴: 대시보드, 내 회의록 + - 하단: 사용자 정보 + 로그아웃 #### 상단 헤더 (공통) - **위치**: Sticky, 상단 -- **배경**: 흰색, 하단 테두리 (1px solid #E5E7EB) -- **구성**: - - 좌측: 뒤로가기 버튼 (화면별 조건부) - - 중앙: 페이지 타이틀 (18px Bold) - - 우측: 액션 버튼 (저장, 메뉴 등) -- **Mobile 전용 (768px 미만)**: - - 우측 상단에 프로필 아이콘 버튼 추가 (👤, 24px) - - 클릭 시 드롭다운 메뉴 표시: - - 사용자 이름 (14px Bold) - - 로그아웃 버튼 (btn-ghost btn-sm) - - 드롭다운 위치: 우측 상단 기준 아래로 펼침 - - 배경: 흰색, 그림자: var(--shadow-md) -- **Desktop (768px+)**: - - 프로필 아이콘 숨김 (사이드바 하단 영역 사용) +- **구성**: 뒤로가기(조건부), 타이틀, 액션 버튼 +- **Mobile 전용**: 우측 프로필 아이콘(👤) → 드롭다운 (이름 + 로그아웃) +- **Desktop**: 프로필 숨김 (사이드바 사용) + +[↑ 목차로 돌아가기](#목차) + +--- + +## 인터랙션 패턴 라이브러리 + +### 폼 검증 +- **실시간 검증**: 입력 시 형식 오류 즉시 표시 +- **제출 검증**: 빈 필드 → 해당 필드로 포커스 +- **오류 표시**: 필드 하단 빨간 텍스트 (14px) + +### 카드 인터랙션 +- **기본**: 배경 흰색, 테두리 회색, 둥글기 8px +- **호버**: 그림자 증가, 약간 상승 (translateY(-2px)) +- **클릭**: 해당 상세 화면으로 이동 + +### 참여자 관리 +- **추가 폼**: 이메일 입력 + "초대" 버튼 +- **유효성 검증**: 이메일 정규식 체크 +- **성공**: "{email}에게 초대 링크 전송" 토스트 +- **참여자 목록**: 아바타 + 이름, 삭제(×) 버튼 + +### 참고자료 관리 +- **추가**: "참고자료 추가" → 회의록 검색 모달 → 선택 추가 +- **제거**: X 버튼 클릭 +- **순서 변경**: 드래그 앤 드롭 (선택) + +### 드래그 앤 드롭 +- **터치**: 길게 누르기 → 드래그 시작 +- **마우스**: 클릭 드래그 +- **피드백**: 드래그 중 반투명, 드롭 위치 표시 + +### 모달 표시 +- **Mobile**: 바텀시트 (하단 슬라이드 업) +- **Desktop**: 중앙 모달 +- **닫기**: Esc 키, 배경 클릭, X 버튼 + +### 로딩 상태 +- **스켈레톤 UI**: 리스트 로딩 중 표시 +- **로딩 인디케이터**: 버튼 클릭 시 스피너 +- **프로그레스 바**: 파일 업로드/다운로드 [↑ 목차로 돌아가기](#목차) @@ -1700,38 +670,33 @@ graph TD ### 네트워크 오류 - **메시지**: "네트워크 연결을 확인해주세요" -- **재시도**: 자동 재시도 최대 3회 (exponential backoff: 1s, 2s, 4s) -- **UI**: 오류 토스트 (빨강) + "다시 시도" 버튼 -- **적용 화면**: 전체 +- **재시도**: 자동 3회 (1s, 2s, 4s exponential backoff) +- **UI**: 빨강 토스트 + "다시 시도" 버튼 ### 데이터 로딩 실패 - **메시지**: "일시적으로 데이터를 불러올 수 없습니다" - **UI**: 빈 상태 화면 + "다시 시도" 버튼 -- **적용 화면**: 전체 ### 권한 오류 - **메시지**: "접근 권한이 없습니다" -- **액션**: 3초 후 자동으로 이전 화면 또는 대시보드로 복귀 -- **UI**: 경고 토스트 (주황) -- **적용 화면**: 회의록 상세, 회의록 수정 +- **액션**: 3초 후 이전 화면 또는 대시보드 복귀 +- **UI**: 주황 토스트 ### 인증 오류 - **메시지**: "로그인이 필요합니다" -- **액션**: 로그인 화면으로 리다이렉트 -- **UI**: 정보 토스트 (파랑) -- **적용 화면**: 전체 (인증 필요 화면) +- **액션**: 로그인 화면 리다이렉트 +- **UI**: 파랑 토스트 ### 입력 검증 오류 -- **이메일 형식 오류**: "올바른 이메일 형식이 아닙니다" -- **필수 입력 누락**: "필수 항목을 입력해주세요" -- **날짜 형식 오류**: "올바른 날짜 형식이 아닙니다 (YYYY-MM-DD)" -- **UI**: 입력 필드 하단 오류 메시지 (빨강, 14px) +- 이메일: "올바른 이메일 형식이 아닙니다" +- 필수 입력: "필수 항목을 입력해주세요" +- 날짜: "올바른 날짜 형식이 아닙니다 (YYYY-MM-DD)" +- **UI**: 입력 필드 하단 빨강 메시지 ### 서버 오류 - **메시지**: "서버에 일시적인 문제가 발생했습니다" -- **UI**: 오류 토스트 (빨강) + "다시 시도" 버튼 -- **로깅**: 오류 상세 정보를 서버로 전송 (Sentry) -- **적용 화면**: 전체 +- **UI**: 빨강 토스트 + "다시 시도" 버튼 +- **로깅**: Sentry로 오류 전송 [↑ 목차로 돌아가기](#목차) @@ -1740,31 +705,19 @@ graph TD ## 화면 간 전환 및 네비게이션 ### 네비게이션 구조 - -#### Mobile (320px~768px) -- **Primary Navigation**: [Mobile 하단 네비게이션](#mobile-하단-네비게이션-320px768px) 참조 - -- **Secondary Navigation**: [상단 헤더](#상단-헤더-공통) 참조 - -#### Tablet/Desktop (768px+) -- **Primary Navigation**: [Desktop 좌측 사이드바](#desktop-좌측-사이드바-768px) 참조 - - 설정 - - 프로필 - -- **Breadcrumbs**: 상단 (선택) - - 현재 위치 경로 표시 - - 클릭하여 상위 페이지로 이동 +- **Mobile**: [하단 네비게이션](#mobile-하단-네비게이션-320px768px) + [상단 헤더](#상단-헤더-공통) +- **Desktop**: [좌측 사이드바](#desktop-좌측-사이드바-768px) + Breadcrumbs(선택) ### 전환 애니메이션 -- **화면 전환**: 페이드 또는 슬라이드 (200-300ms) -- **모달 표시**: 페이드 인 + 스케일 (150ms) +- **화면 전환**: 페이드/슬라이드 (200-300ms) +- **모달**: 페이드 인 + 스케일 (150ms) - **탭 전환**: 페이드 (100ms) -- **리스트 로딩**: 스켈레톤 UI 표시 후 페이드 인 +- **리스트 로딩**: 스켈레톤 UI → 페이드 인 -### 딥 링크 지원 -- 특정 회의록 직접 접근: `/minutes/{minuteId}` -- 특정 Todo 직접 접근: `/todo/{todoId}` -- 회의록 공유 링크: `/share/{shareToken}` +### 딥 링크 +- 회의록: `/minutes/{minuteId}` +- Todo: `/todo/{todoId}` +- 공유: `/share/{shareToken}` [↑ 목차로 돌아가기](#목차) @@ -1775,49 +728,22 @@ graph TD ### 브레이크포인트 - **Mobile**: 320px ~ 767px - **Tablet**: 768px ~ 1023px -- **Desktop**: 1024px 이상 +- **Desktop**: 1024px+ ### 레이아웃 전략 +1. **320px 기준**: 단일 컬럼, 필수 기능만, 하단 네비게이션 +2. **768px 확장**: 2컬럼, 추가 정보, 사이드바 도입 +3. **1024px 최적화**: 3컬럼, 좌측 사이드바, 마우스/키보드 강화 -#### Mobile First 접근 -1. **320px (Small Mobile) 기준 설계** - - 단일 컬럼 레이아웃 - - 필수 기능만 표시 - - 터치 친화적 UI (최소 44px 터치 영역) - - 하단 네비게이션 - -2. **768px (Tablet) 확장** - - 2컬럼 레이아웃 (일부 화면) - - 추가 정보 표시 (통계, 위젯) - - 사이드바 도입 (선택) - -3. **1024px (Desktop) 최적화** - - 3컬럼 레이아웃 (대시보드, 회의진행) - - 좌측 고정 사이드바 - - 마우스/키보드 인터랙션 강화 - - 추가 기능 노출 (단축키, 고급 필터 등) - -### 컴포넌트별 반응형 전략 - -#### 폼 (Form) -- Mobile: 단일 컬럼, 전체 너비 -- Tablet: 2컬럼 (관련 필드 그룹화) -- Desktop: 2컬럼 + 미리보기 패널 - -#### 리스트 (List) -- Mobile: 카드 형태, 스택 레이아웃 -- Tablet: 2컬럼 그리드 -- Desktop: 3컬럼 그리드 또는 마스터-디테일 - -#### 테이블 (Table) -- Mobile: 카드 형태로 변환, 중요 정보만 표시 -- Tablet: 스크롤 가능한 테이블 -- Desktop: 고정 헤더 테이블, 모든 컬럼 표시 +### 컴포넌트별 반응형 +- **폼**: Mobile 단일 → Desktop 2컬럼 + 미리보기 +- **리스트**: Mobile 스택 → Tablet 2컬럼 → Desktop 3컬럼 그리드 +- **테이블**: Mobile 카드 변환 → Desktop 고정 헤더 테이블 ### 이미지 및 미디어 -- Responsive Images: srcset 활용 -- Lazy Loading: 뷰포트 진입 시 로딩 -- 최적화: WebP 포맷, 적절한 압축 +- Responsive Images: srcset +- Lazy Loading: Intersection Observer +- 최적화: WebP, 압축 [↑ 목차로 돌아가기](#목차) @@ -1827,36 +753,31 @@ graph TD ### WCAG 2.1 Level AA 준수 -#### 1. Perceivable (인식 가능) -- **텍스트 대안**: 모든 이미지에 alt 텍스트 제공 -- **색상 대비**: 최소 4.5:1 대비율 (일반 텍스트), 3:1 (대형 텍스트) -- **텍스트 크기 조절**: 200%까지 확대 가능, 레이아웃 깨지지 않음 -- **색상만으로 정보 전달 금지**: 아이콘, 텍스트와 함께 사용 +#### 1. Perceivable +- **텍스트 대안**: 모든 이미지 alt +- **색상 대비**: 4.5:1 (일반), 3:1 (대형) +- **텍스트 크기**: 200% 확대 가능 +- **색상 독립**: 아이콘/텍스트 병행 -#### 2. Operable (조작 가능) -- **키보드 접근성**: 모든 기능 키보드로 조작 가능 - - Tab: 다음 요소로 포커스 이동 - - Shift + Tab: 이전 요소로 포커스 이동 - - Enter/Space: 버튼 활성화 - - Esc: 모달 닫기 -- **포커스 표시**: 명확한 포커스 인디케이터 (2px 파란색 테두리) -- **터치 영역**: 최소 44x44px (모바일) -- **시간 제한 없음**: 자동 저장으로 세션 만료 방지 +#### 2. Operable +- **키보드**: Tab, Shift+Tab, Enter/Space, Esc +- **포커스**: 2px 파란 테두리 +- **터치 영역**: 최소 44x44px +- **시간 제한**: 자동 저장으로 방지 -#### 3. Understandable (이해 가능) -- **명확한 레이블**: 모든 입력 필드에 레이블 제공 -- **오류 식별 및 안내**: 오류 발생 시 명확한 설명 및 해결 방법 제공 -- **일관된 UI**: 동일한 기능은 동일한 위치, 동일한 아이콘/텍스트 +#### 3. Understandable +- **명확한 레이블**: 모든 입력 필드 +- **오류 안내**: 명확한 설명 + 해결 방법 +- **일관된 UI**: 동일 기능 = 동일 위치/아이콘 -#### 4. Robust (견고함) -- **시맨틱 HTML**: 적절한 HTML 태그 사용 (header, nav, main, aside, footer) -- **ARIA 레이블**: 스크린 리더를 위한 ARIA 속성 - - role, aria-label, aria-describedby, aria-live -- **호환성**: 최신 브라우저 및 보조 기술 지원 +#### 4. Robust +- **시맨틱 HTML**: header, nav, main, aside, footer +- **ARIA**: role, aria-label, aria-describedby, aria-live +- **호환성**: 최신 브라우저 + 보조 기술 -### 접근성 테스트 -- 자동 테스트: Lighthouse, axe DevTools -- 수동 테스트: 키보드 네비게이션, 스크린 리더 (NVDA, JAWS, VoiceOver) +### 테스트 +- 자동: Lighthouse, axe DevTools +- 수동: 키보드, 스크린 리더 (NVDA, JAWS, VoiceOver) [↑ 목차로 돌아가기](#목차) @@ -1865,51 +786,34 @@ graph TD ## 성능 최적화 방안 ### 1. 로딩 성능 -- **Code Splitting**: 라우트별 청크 분리 -- **Lazy Loading**: - - 이미지: Intersection Observer - - 컴포넌트: React.lazy, dynamic import -- **Pre-fetching**: 다음 화면 리소스 미리 로딩 -- **CDN 활용**: 정적 리소스 CDN 배포 +- **Code Splitting**: 라우트별 청크 +- **Lazy Loading**: 이미지(Intersection Observer), 컴포넌트(React.lazy) +- **Pre-fetching**: 다음 화면 리소스 +- **CDN**: 정적 리소스 배포 ### 2. 렌더링 성능 -- **Virtual Scrolling**: 긴 리스트 (회의록, Todo) -- **Debounce/Throttle**: - - 검색 입력: 300ms debounce - - 스크롤 이벤트: 100ms throttle +- **Virtual Scrolling**: 긴 리스트 +- **Debounce/Throttle**: 검색(300ms), 스크롤(100ms) - **Memoization**: React.memo, useMemo, useCallback -- **CSS 애니메이션**: JavaScript 대신 CSS transition 사용 +- **CSS 애니메이션**: JavaScript 대신 ### 3. 네트워크 최적화 -- **API 요청 최적화**: - - 필요한 데이터만 요청 (GraphQL 또는 필드 선택) - - 배치 요청: 여러 API를 하나로 통합 -- **캐싱 전략**: - - 브라우저 캐시: Cache-Control 헤더 - - Service Worker: 오프라인 지원 - - 메모리 캐시: React Query, SWR +- **API**: 필요 데이터만, 배치 요청 +- **캐싱**: Cache-Control, Service Worker, React Query - **압축**: Gzip, Brotli -### 4. 실시간 동기화 최적화 -- **WebSocket 최적화**: - - Delta 전송: 전체 데이터가 아닌 변경 부분만 전송 - - 배치 업데이트: 여러 변경 사항을 묶어서 전송 - - 재연결 전략: 지수 백오프 -- **Conflict Resolution**: Operational Transformation 또는 CRDT +### 4. 실시간 동기화 +- **WebSocket**: Delta 전송, 배치 업데이트, 지수 백오프 +- **Conflict Resolution**: OT 또는 CRDT ### 5. 성능 모니터링 -- **Core Web Vitals**: - - LCP (Largest Contentful Paint): < 2.5s - - FID (First Input Delay): < 100ms - - CLS (Cumulative Layout Shift): < 0.1 -- **실시간 모니터링**: Sentry, Google Analytics +- **Core Web Vitals**: LCP <2.5s, FID <100ms, CLS <0.1 +- **모니터링**: Sentry, Google Analytics -### 성능 목표 -- **First Contentful Paint**: < 1.5s -- **Time to Interactive**: < 3.5s -- **Page Load (3G)**: < 5s -- **STT 지연 시간**: < 1s -- **실시간 동기화 지연**: < 500ms +### 목표 +- FCP: <1.5s, TTI: <3.5s +- Page Load (3G): <5s +- STT: <1s, 실시간 동기화: <500ms [↑ 목차로 돌아가기](#목차) @@ -1917,37 +821,26 @@ graph TD ## 변경 이력 -| 버전 | 날짜 | 작성자 | 변경 내용 | -|------|------|--------|----------| -| 1.0 | 2025-10-21 | 이미준 | 최초 작성 - 11개 화면 설계 완료 | -| 1.1.x | 2025-10-21 | 이미준 | **주요 변경**: AI 요약 및 참고자료 기능, 회의록 상세 화면 개선, 대시보드 UI 개선
- 1.1.0: AI 요약/참고자료 기능 추가 (05, 10, 11 화면), UFR-AI-040 관련 회의록 자동 연결
- 1.1.1: 회의록 상세 탭 구조 개선 (회의록/대시보드), 참고자료 관련도 점수 표시
- 1.1.2: 대시보드 예정 회의 카드/Todo 정렬 개선, 12-회의록목록조회 신규 추가 (필터/정렬/검색) | -| 1.2.x | 2025-10-21 | 이미준, 최유진 | **주요 변경**: 대시보드 역할 기반 접근 제어, 회의진행 화면 개선, 스타일 가이드 신규 작성
- 1.2.0: 진행중 회의 표시 기능 (배지, 참여하기 버튼, 에러 처리)
- 1.2.1: 예정 회의 생성자/참여자 권한 차별화 (수정 버튼, 참여 시간 제한, 타이머)
- 1.2.2: 참고자료 새 탭 열기, 참여자 추가 초대, 스타일 가이드 신규 작성 (민트 그린 컬러 시스템)
- 1.2.3: 설정 메뉴 제거, Todo 클릭 시 회의록 상세로 이동 (URL 파라미터 전달) | -| 1.3.x | 2025-10-21 | 이미준, 도그냥 | **주요 변경**: 반응형 네비게이션 구조, 회의진행 화면 전면 개편, 공통 UI 컴포넌트 표준화
- 1.3.0: 반응형 네비게이션 (Mobile 하단 3개, Desktop 사이드바), 05-회의진행 2열 구조 재설계, 10-회의록상세조회 타임라인 탭 제거
- 1.3.1: AI 제안 탭 3가지 유형 상세화 (논의사항/결정사항/액션아이템), 디자인 통일성 개선
- 1.3.2: 참여자 추가 폼 + 이메일 유효성 검증, 버튼/검색창 스타일 통일
- 1.3.3: 공통 UI 컴포넌트/에러 메시지 섹션 신규 작성, 중복 내용 참조 링크 교체 (파일 크기 8~10% 감소) | -| 1.4.x | 2025-10-22~25 | 이미준, 강지수, 도그냥 | **주요 변경**: Todo 관리 기능 대폭 강화, 화면 번호 재정렬, 회의록 공유 기능 제거, 유저스토리 v2.3.0 반영
- 1.4.0~1.4.5: 네비게이션 사양 통일, 대시보드 모바일 최적화, 공유 기능 제거, 화면 번호 통일, 로그아웃 기능 추가
- 1.4.6~1.4.10: 검증완료 섹션 잠금 정책, Todo 관리 확장 (통계/필터/편집), 회의록 상세 탭 순서 변경, Todo 카드 디자인 전면 개선, 공통 스타일 관리
- 1.4.11~1.4.13: 회의진행 액션아이템 탭 개선, Todo 카드 HTML/CSS 완전 통일 (3개 화면), D-day 배지 정책 (회의 중 숨김)
- 1.4.14~1.4.16: 12-회의록목록조회 데이터 아키텍처 문서화, 06-검증완료 화면 삭제, 사용자 역할 용어 통일 (생성자/참여자)
- 1.4.17~1.4.20: STT 화자 식별 불가 반영, 05-회의진행 프로토타입 기준 전면 수정, 유저스토리 v2.3.0 반영 (충돌 방지 정책 강화) | -| 1.5.1 | 2025-10-27 | 강지수 | MVP 스코프 축소 v2.4.0 반영 (4개 화면 수정)
- **02-대시보드**: Todo 위젯 및 통계 제거 (UFR-USER-020 반영)
- Todo 위젯 전체 제거 (나의 Todo 섹션 삭제)
- 통계 카드: "나의 Todo" 제거, "작성중 회의록" 유지 (2개 항목)
- 네비게이션: 하단 네비게이션 및 사이드바에서 Todo 관리 메뉴 제거
- Desktop 통계 그리드: 2개 항목만 표시
- **05-회의진행**: "AI 제안" 탭 → "AI 기반 메모" 탭 기능 변경
- 메모 입력창 + 저장 버튼 추가
- AI가 감지한 주요 내용 리스트 표시 (시간 + 내용)
- 각 참여자별 개별 저장, 다른 참여자 메모 볼 수 없음
- 메모는 회의 종료 전까지만 표시/편집 가능
- 에러 처리: AI 주요 내용 감지 실패, 메모 저장 실패 추가
- **10-회의록상세조회**: Todo 단순 조회 기능으로 변경
- Todo는 제목 + 담당자 + 마감일만 표시
- D-day 라벨, 우선순위 배지, 진행률 바, 상태별 필터 제거
- Todo 관리 화면 연동 링크 제거 (화면 자체가 제거됨)
- "수정" 버튼을 헤더로 이동
- **11-회의록수정**: 실시간 협업 기능 제거, 안건 기반 충돌 방지 강화
- "편집 중" 표시 제거 (실시간 협업 기능 제거)
- Todo 편집/추가/삭제 기능 전체 제거 (단순 조회만 가능)
- AI 한줄 요약 재생성 불가 (회의 종료 시 1회만 생성)
- 검증률 표시 및 최종 확정 버튼 제거
- 저장 로직 추가: 검증완료 안건 저장 스킵, 저장 결과 알림
- 안건별 검증 완료 체크박스로 충돌 방지 (Last Write Wins 적용)
- 에러 처리: 충돌 경고 모달 제거 (LWW로 인해) | -| 1.5.2 | 2025-10-27 | 강지수 | AI 요약 기능 통합 및 단순화 (유저스토리 v2.4.0 반영)
- **11-회의록수정**: AI 요약 기능 통합
- 명칭 변경: "AI 상세 요약" → "AI 요약"
- AI 요약 영역: AI 한줄 요약만 표시 (30자 이내, 읽기 전용)
- 텍스트 편집 영역: 안건 내용 자유 작성 (논의 주제, 발언자별 의견, 결정 사항 등)
- "AI 재생성" 버튼: 텍스트 편집 영역 내용 기반으로 AI 요약의 한줄 요약 재생성 (2-5초 처리)
- 재생성된 한줄 요약은 회의록 상세조회 화면의 대시보드 및 회의록 탭에 즉시 반영
- AI 상세 요약 및 한줄 요약 분리 표시 제거
- **프로토타입 UI 개선**:
- AI 재생성 버튼 스타일 통일: btn-secondary → btn-primary (다른 화면과 일관성)
- 안건별 검증완료 UI 단순화: 참여자는 체크박스만, 회의 생성자는 검증완료 시 잠금해제 버튼 표시
- .creator-only CSS 클래스 추가: data-is-creator 속성 기반 표시 제어
- **관련 유저스토리**: UFR-AI-036 (AI 한줄요약 확인 및 재생성), UFR-MEET-055 (안건별 검증), UFR-COLLAB-030 (충돌 방지) | -| 1.5.3 | 2025-10-27 | 강지수 | Todo 추가/편집 권한 정책 명확화 (유저스토리 v2.4.1 반영)
- **10-회의록상세조회**: Todo 추가/편집 권한 정책 추가 (대시보드 탭)
- "추가" 버튼: 모든 회의 참여자에게 노출 (Todo 리스트 우측 상단)
- "편집(✏️)" 버튼: 회의 생성자에게만 노출 (각 Todo 항목 우측)
- Todo 추가 모달: 제목, 담당자, 마감일 입력 (모든 참여자)
- Todo 편집 모달: 제목, 담당자, 마감일 수정 (회의 생성자만)
- 담당자 필드: 추가 시 또는 생성자의 편집 시만 표시
- **프로토타입 UI 개선**: 10-회의록상세조회.html
- Todo 추가/편집 모달 바텀시트 스타일 통일 (모바일: 하단 슬라이드 업, 데스크톱: 중앙 모달)
- .creator-only 클래스 적용하여 편집 버튼 권한별 표시/숨김 처리
- JavaScript initPage() 함수에서 회의 생성자 여부 확인 후 creator-only 요소 제어
- Todo 추가 성공: "담당자에게 알림이 전송되었습니다" → "캘린더가 업데이트되었습니다" 순차 토스트
- Todo 편집 성공: 담당자 변경 시 알림, 마감일 변경 시 캘린더 업데이트 토스트
- **관련 유저스토리**: UFR-MEET-047 (회의록상세조회), Todo 권한 정책 신규 추가 | -| 1.5.4 | 2025-10-28 | 도그냥 | 대시보드 최근 회의 리스트 디자인 간소화 (UFR-USER-020 반영)
- **02-대시보드**: 최근 회의 정렬 기준 명확화 및 디자인 간소화
- **정렬 기준**:
- 1순위: 회의록 미생성 회의 (진행중 + 예정) 우선 표시
- 2순위: 미생성이 3개 미만이면 최근 종료된 회의(회의록 있음)로 나머지 채움
- 각 그룹 내 정렬: 빠른 일시 순 (시작 시간 기준)
- 최대 표시: 3개
- **회의 카드 (클릭 가능 블록)**:
- 상태 라벨 (배지): "진행중", "예정", "작성중", "확정완료"
- 회의 제목 + 생성자 아이콘(👑)
- 회의 일시, 참여자 수, 장소
- 상태 버튼 (표시용): "참여하기", "수정하기", "보기"
- **디자인 간소화**: D-day 표시, 깜박임 애니메이션, 세부 색상 지정 등 제거
- **유저스토리**: UFR-USER-020 (대시보드 조회) 동일하게 수정 | -| 1.5.5 | 2025-10-28 | 도그냥 | 회의예약 화면 임시저장 기능 제거
- **03-회의예약**: 헤더 임시저장 버튼 제거
- 헤더에서 "임시저장" 버튼 완전 제거
- JavaScript 변수 선언 제거 (draftSaveBtn)
- 임시저장 이벤트 리스너 제거
- 사용자는 "예약 완료" 버튼으로만 회의 예약 가능
- **유저스토리**: UFR-MEET-010, UFR-MEET-011 임시저장 관련 출력 항목 제거
- **프로토타입**: design/uiux/prototype/03-회의예약.html 수정 | -| 1.5.6 | 2025-10-28 | 도그냥, 지수 | 02-대시보드 예정 회의 권한 제어 개선 (MVP 일정 최우선)
- **예정 회의 카드 클릭 동작**: 생성자/참여자 역할별 차별화
- 생성자: 카드 클릭 → 회의예약 화면(수정 모드) 진입
- 참여자: 카드 클릭 → 시스템 알럿 표시 ("아직 회의 시간이 되지 않아 참여하실 수 없습니다")
- **버튼 표시 규칙 변경**: 예정 회의에서 "수정하기" 버튼 제거
- 진행중: "참여하기" 버튼 표시
- 예정: 버튼 없음 (카드 클릭으로 처리)
- 완료: "보기" 버튼 표시
- **프로토타입 수정**: design/uiux/prototype/02-대시보드.html
- 권한 체크 로직 추가 (isCreator 확인)
- 시스템 알럿 추가 (참여자 클릭 시)
- **유저스토리 반영**: UFR-USER-020, UFR-MEET-011 예외처리 추가
- **다음 버전 개선 계획**: 참여자용 회의 상세 조회 모달 기능 추가 예정 (회의 정보 제공 + 시작 시간 안내) | -| 1.5.7 | 2025-10-28 | 도그냥, 지수 | UFR-TODO 잔여 참조 제거 (문서 정리)
- **유저스토리 매핑 섹션**: "Todo 서비스" 항목 제거 (96라인)
- **프로토타입 화면 목록**: "09 Todo관리" 화면 취소선 처리 및 제거 표시 추가 (124라인)
- **09-Todo관리 화면**: 제거 안내 추가 (개요 섹션에 경고 메시지 삽입)
- MVP v2.4.0에서 제거됨을 명확히 표시
- Todo 기능은 회의록 상세조회(10번) 화면에서만 제공됨을 안내
- **Todo 편집 섹션**: MVP v2.4.0 제거 표시 추가 (1163라인)
- **관련 유저스토리**: UFR-TODO-010, UFR-TODO-030, UFR-TODO-040 참조 제거 또는 삭제 표시
- **참고**: Todo 관리 독립 화면은 제거되었으나 회의록 내 Todo 기능(추가/편집)은 10번 화면에서 유지됨 | -| 1.5.8 | 2025-10-28 | 지수, 도그냥 | MVP v2.4.5 반영: Todo 관리 및 검증완료 플로우 정리
- **사용자 플로우**: "검증완료" 단계 제거, "회의종료 → 회의록수정" 플로우로 변경
- 시나리오 1: 회의진행 → 회의종료 → 회의록수정 (선택) → 대시보드
- 시나리오 3 (Todo 관리) 제거 표시
- **플로우 다이어그램**: 검증완료 및 Todo 관련 플로우 제거, 회의종료 후 회의록수정 선택 플로우로 단순화
- **02-대시보드**: Todo 항목 클릭 시 회의록 상세 이동 로직 제거, Todo 데이터 요구사항 제거, Todo 관련 빈 상태 제거
- **07-회의종료**: Todo 서비스 연동 제거 (Meeting, AI 서비스만 연동)
- **10-회의록상세조회**: Todo 서비스 연동 제거
- **네비게이션**: 하단 네비게이션 및 Desktop 사이드바에서 Todo 관리 메뉴 제거 표시 (MVP v2.4.0)
- Mobile 하단 네비게이션: 3개 → 2개 항목 (홈, 회의록)
- Desktop 사이드바: Todo 메뉴 제거
- **변경 근거**: 유저스토리 v2.4.5 기준, Todo 관리 독립 화면 제거 및 회의 종료 후 회의록 수정 단계로 간소화 | -| 1.5.9 | 2025-10-28 | 지수, 도그냥 | 용어 통일: "참석자/참석" → "참여자/참여" 변경
- **화면설계서**: 100개 인스턴스 변경 (uiux.md)
- "참석자" → "참여자" (88개)
- "참석" → "참여" (12개): "내가 참석한 회의", "본인이 참석한 회의록", "참석한 회의" 등
- **유저스토리**: 132개 인스턴스 변경 (userstory.md)
- "참석자" → "참여자" (125개)
- "참석" → "참여" (7개): "참석 중인 사용자", "참석 권한", "참석률" 등
- **프로토타입**: 34개 인스턴스 변경 (9개 HTML 파일)
- "참석자" → "참여자" (32개)
- "참석" → "참여" (2개)
- **총 266개 인스턴스 변경**: 사용자 역할 용어 완전 통일 (생성자/참여자 체계) | +| 버전 | 날짜 | 작성자 | 변경 내용 요약 | +|------|------|--------|----------------| +| 1.0 | 2025-10-21 | 이미준 | 최초 작성 - 11개 화면 설계 | +| 1.1.x | 2025-10-21 | 이미준 | AI 요약/참고자료 기능 추가, 대시보드 개선, 회의록 목록 추가 | +| 1.2.x | 2025-10-21 | 이미준, 최유진 | 역할 기반 접근 제어, 회의진행 개선, 스타일 가이드 작성 | +| 1.3.x | 2025-10-21 | 이미준, 도그냥 | 반응형 네비게이션, 회의진행 2열 구조, 공통 컴포넌트 표준화 | +| 1.4.x | 2025-10-22~25 | 이미준, 강지수, 도그냥 | Todo 강화, 화면 재정렬, 검증완료 정책, 용어 통일(생성자/참여자), STT 화자 식별 불가 반영 | +| 1.5.1~1.5.9 | 2025-10-27~28 | 강지수, 도그냥 | MVP v2.4.0~2.4.5 반영: Todo 단순화, AI 메모 기능, 검증완료 강화, 네비게이션 간소화, 용어 통일(참여자/참여) | +| **1.6.0** | 2025-10-29 | 강지수 | **문서 구조 최적화 및 중복 제거 (토큰 효율성 개선)**: 화면 설계 표준 섹션 신규 추가, 인터랙션 패턴 라이브러리 신규 추가, 각 화면 설계 참조 링크 기반으로 간소화, 변경 이력 요약 테이블 형식, 약 35-40% 토큰 절감 | + +**주요 버전 세부 변경 사항**: +- **v1.1**: UFR-AI-040 관련 회의록 자동 연결, AI 요약 기능 추가 +- **v1.2**: 진행중 회의 표시, 예정 회의 권한 차별화 +- **v1.3**: Mobile 하단 네비게이션 3개 → 2개, Desktop 사이드바, AI 제안 탭 상세화 +- **v1.4**: Todo 관리 확장, 검증완료 잠금, 참석자 → 참여자 용어 통일 +- **v1.5**: MVP 스코프 축소 (Todo 단순 조회, AI 메모 기능, 실시간 협업 제거, Last Write Wins 적용) +- **v1.6**: 문서 구조 최적화 (토큰 35-40% 절감) [↑ 목차로 돌아가기](#목차) --- -## 부록 - -### 참고 자료 -- Mobile First 설계 원칙: Luke Wroblewski "Mobile First" -- 접근성 가이드라인: WCAG 2.1 Level AA -- 성능 최적화: Google Web Fundamentals - -### 디자인 시스템 (추후 작성) -- 색상 팔레트 -- 타이포그래피 -- 컴포넌트 라이브러리 -- 아이콘 세트 - +**문서 끝** diff --git a/design/userstory.md b/design/userstory.md index 9a72421..3dbd232 100644 --- a/design/userstory.md +++ b/design/userstory.md @@ -1,4 +1,4 @@ -# AI기반 회의록 작성 및 이력 관리 개선 서비스 - 유저스토리 (v2.4.5) +# AI기반 회의록 작성 및 이력 관리 개선 서비스 - 유저스토리 (v2.5.0) ## 목차 - [1. 프로젝트 개요](#1-프로젝트-개요) @@ -11,8 +11,6 @@ - [2.4 STT 서비스](#24-stt-서비스) - [2.5 Notification 서비스](#25-notification-서비스) - [3. 향후 과제](#3-향후-과제) - - [3.1 v2.4.2 개선 계획](#31-v242-개선-계획) - - [3.2 v2.5.0 이후 고려사항](#32-v250-이후-고려사항) - [문서 이력](#문서-이력) --- @@ -25,35 +23,21 @@ #### 1. 기본 기능 (Hygiene Factors) - **STT(Speech To Text)**: 음성을 텍스트로 변환하는 기본 기능 - - 시장의 대부분 서비스가 제공하는 기능으로 차별화 포인트가 아님 - - 필수 기능이지만 경쟁 우위를 가져다주지 않음 #### 2. 핵심 차별화 포인트 (Differentiators) -- **맥락 기반 용어 설명**: 단순 용어 설명을 넘어, 관련 회의록과 업무이력을 바탕으로 실용적인 정보 제공 -- **섹션 AI 요약 재생성**: 버튼 클릭으로 작성한 섹션 내용을 AI가 요약 (2-3문장, 2-5초 처리) -- **지능형 회의 진행 지원**: 회의 패턴 분석을 통한 안건 추천, 효율성 분석 및 개선 제안 +- **맥락 기반 용어 설명**: 관련 회의록과 업무이력 기반 실용 정보 제공 +- **섹션 AI 요약 재생성**: 버튼 클릭으로 2-3문장 요약 (2-5초 처리) +- **지능형 회의 진행 지원**: 회의 패턴 분석, 안건 추천, 효율성 분석 --- ### 1.2 마이크로서비스 구성 -1. **User** - 사용자 인증 (LDAP 연동, JWT 토큰 발급/검증) -2. **Meeting** - 회의, 회의록, Todo 통합 관리 - - 회의 관리: 회의 예약, 시작, 종료 - - 회의록 관리: 회의록 생성, 수정, 확정 - - 안건별 검증완료 및 잠금 처리 (Last Write Wins 정책) - - 템플릿 관리: 회의록 템플릿 관리 - - 통계 생성: 회의 및 Todo 통계 -3. **STT** - 음성 스트리밍 처리, 실시간 음성-텍스트 변환 (기본 기능) -4. **AI** - AI 기반 회의록 자동화, Todo 추출, 지능형 검색 (RAG 통합) - - LLM 기반 회의록 자동 작성 - - Todo 자동 추출 및 담당자 식별 - - 안건별 AI 요약 재생성 (버튼 클릭 시 한줄 요약 생성) - - 관련 회의록 자동 연결 (벡터 유사도 검색) - - 전문용어 자동 감지 및 맥락 기반 설명 생성 (RAG) - - 과거 회의록 및 사내 문서 검색 - - 업무 이력 통합 -5. **Notification** - 이메일 알림 발송 (회의 시작, 회의록 확정, 참여자 초대) +1. **User** - 사용자 인증 (LDAP, JWT) +2. **Meeting** - 회의, 회의록, Todo 통합 관리, 안건별 검증완료 및 잠금 (Last Write Wins) +3. **STT** - 음성 스트리밍, 실시간 음성-텍스트 변환 +4. **AI** - 회의록 자동화, Todo 추출, 지능형 검색 (RAG 통합), 안건별 AI 요약 +5. **Notification** - 이메일 알림 (회의 시작, 회의록 확정, 참여자 초대) --- @@ -64,86 +48,39 @@ #### UFR-USER-010: 🔴 [로그인] 사용자로서 | 나는, 시스템에 접근하기 위해 | 사번과 비밀번호로 로그인하고 싶다. **수행절차:** -1. 로그인 화면 접속 -2. 사번 입력 (필수) -3. 비밀번호 입력 (필수, 최소 8자) -4. (선택) 로그인 상태 유지 체크박스 선택 -5. 로그인 버튼 클릭 -6. 인증 성공 시 대시보드로 이동 +1. 로그인 화면 접속 → 사번/비밀번호 입력 → (선택) 로그인 상태 유지 → 로그인 버튼 클릭 → 인증 성공 시 대시보드 이동 -**입력:** -- 사번: 텍스트 입력, 필수, 공백 불가 -- 비밀번호: 패스워드 입력, 필수, 최소 8자 이상 -- 로그인 상태 유지: 체크박스 (선택) -- Enter 키 입력 시 다음 필드로 자동 이동 (사번 → 비밀번호) +**입력:** 사번(필수), 비밀번호(필수, 최소 8자), 로그인 상태 유지(선택) -**출력/결과:** -- 로그인 성공: JWT 토큰 발급, 사용자 정보 저장, 대시보드(02-대시보드.html)로 이동 -- 로그인 실패: 에러 메시지 표시 ("사번 또는 비밀번호가 올바르지 않습니다"), 5초 후 자동 숨김 -- 로딩 상태: 로그인 버튼 비활성화 및 "로그인 중..." 표시 +**출력:** 성공 시 JWT 토큰 발급 및 대시보드 이동, 실패 시 에러 메시지 5초 표시 -**예외처리:** -- 사번 미입력: "사번을 입력해주세요" 에러 표시 및 사번 필드 포커스 -- 비밀번호 미입력: "비밀번호를 입력해주세요" 에러 표시 및 비밀번호 필드 포커스 -- 비밀번호 8자 미만: "비밀번호는 최소 8자 이상이어야 합니다" 에러 표시 -- 인증 실패: 인증 실패 메시지 표시, 로그인 버튼 재활성화 -- 이미 로그인된 경우: 대시보드로 자동 리다이렉트 +**예외:** 미입력 시 필드별 포커스 및 에러 메시지, 인증 실패 시 재활성화, 이미 로그인된 경우 리다이렉트 -**관련 유저스토리:** -- UFR-USER-020: 대시보드 조회 +**관련:** UFR-USER-020 --- #### UFR-USER-020: 🟡 [대시보드] 사용자로서 | 나는, 나의 회의 현황을 파악하기 위해 | 대시보드를 조회하고 싶다. **수행절차:** -1. 로그인 후 대시보드 자동 표시 또는 하단 네비게이션에서 홈 아이콘 클릭 -2. 통계 블록 확인 (예정된 회의, 작성중 회의록) -3. 최근 회의 목록 확인 (최대 3개) -4. 나의 회의록 목록 확인 (최대 4개) -5. 필요 시 "전체 보기" 링크 클릭하여 회의록 목록 화면 이동 -6. FAB 버튼으로 회의 예약 또는 바로 시작 +1. 로그인 후 자동 표시 또는 홈 아이콘 클릭 +2. 통계 블록(예정된 회의, 작성중 회의록) 확인 +3. 최근 회의 목록(최대 3개), 나의 회의록(최대 4개) 확인 +4. FAB 버튼으로 회의 예약 또는 바로 시작 **입력:** - 없음 (자동 렌더링) -**출력/결과:** -- 헤더: 사용자 이름, 오늘 예정된 회의 개수 또는 안내 메시지 -- 통계 블록 (2열 그리드): - - 예정된 회의: 전체 예정 + 진행 중 회의 개수 - - 작성중 회의록: 내가 참여한 회의 중 '작성중' 상태인 회의록 개수 (클릭 액션 없음, 정보 표시만) -- 최근 회의 (회의록 미생성 우선, 빠른 일시 순, 최대 3개): - - 정렬 기준: - - 1순위: 회의록 미생성 회의 (진행중 + 예정) - - 2순위: 미생성이 3개 미만이면 최근 종료된 회의(회의록 있음)로 나머지 채움 - - 각 그룹 내 정렬: 빠른 일시 순 (시작 시간 기준) - - 회의 카드 (클릭 가능 블록): 상태 라벨, 제목, 생성자(👑), 날짜/시간, 참여자 수, 장소, 상태 버튼 - - 진행중: "진행중" 라벨, "참여하기" 버튼 - - 예정: "예정" 라벨, 버튼 없음 (카드 클릭으로 처리) - - 생성자: 카드 클릭 시 회의예약 화면(수정 모드)으로 이동 - - 참여자: 카드 클릭 시 시스템 알럿 표시 ("아직 회의 시간이 되지 않아 참여하실 수 없습니다") - - 완료: "작성중" 또는 "확정완료" 라벨, "보기" 버튼 -- 나의 회의록 (최신순, 최대 4개, 2x2 그리드): - - 회의록 카드: 상태 배지, 생성자 표시(👑), 제목, 날짜/시간, 참여자 수, 검증완료율(작성중인 경우) -- 사이드바 (데스크톱): 로고, 메뉴(대시보드, 회의록), 사용자 정보, 로그아웃 -- 하단 네비게이션 (모바일): 홈(활성), 회의록 -- FAB 메뉴: - - 회의예약 버튼: 회의 예약 화면으로 이동 - - 바로시작 버튼: 템플릿 선택 화면으로 이동 +**출력:** +- 헤더: 사용자 이름, 오늘 예정 회의 개수 +- 통계 블록: 예정된 회의, 작성중 회의록 +- 최근 회의: 회의록 미생성 우선, 빠른 일시 순 (상태별 버튼: 진행중-참여하기, 예정-없음, 완료-보기) +- 나의 회의록: 최신순 2x2 그리드, 상태 배지, 생성자 표시(👑), 검증완료율(작성중) +- FAB: 회의예약/바로시작 -**예외처리:** -- 로그인 안 된 경우: 로그인 화면으로 리다이렉트 -- 최근 회의 없음: 빈 상태 표시 -- 회의록 없음: "참여한 회의록이 없습니다" 빈 상태 표시 -- 참여자가 예정 회의 클릭: "아직 회의 시간이 되지 않아 참여하실 수 없습니다" 시스템 알럿 표시 (다음 버전에서 회의 상세 조회 기능으로 개선 예정) +**예외:** 로그인 안 된 경우 리다이렉트, 회의/회의록 없음 시 빈 상태, 참여자가 예정 회의 클릭 시 알럿 -**관련 유저스토리:** -- UFR-USER-010: 로그인 -- UFR-MEET-010: 회의예약 -- UFR-MEET-011: 회의정보수정 -- UFR-MEET-020: 템플릿선택 -- UFR-MEET-046: 회의록목록조회 -- UFR-MEET-047: 회의록상세조회 +**관련:** UFR-USER-010, UFR-MEET-010/011/020/046/047 --- @@ -152,216 +89,79 @@ #### UFR-MEET-010: 🔴 [회의예약] 회의 생성자로서 | 나는, 회의를 효율적으로 준비하기 위해 | 회의를 예약하고 참여자를 초대하고 싶다. **수행절차:** -1. 대시보드에서 "회의예약" FAB 버튼 클릭 또는 최근 회의에서 "수정" 버튼 클릭 -2. 회의 제목 입력 (최대 100자) -3. 날짜 선택 (오늘 이후 날짜, 달력 UI) -4. 시작/종료 시간 선택 (15분 단위 커스텀 시간 선택기) -5. 온라인/오프라인 회의 선택 (토글) -6. 장소 입력 (최대 200자) - - 오프라인: 예) 본사 2층 대회의실 - - 온라인: 예) Zoom, Google Meet + 회의 링크 입력 또는 자동 생성 -7. 참여자 추가 (현재 사용자는 기본 포함) - - "참여자 추가" 버튼 클릭 - - 검색 모달에서 이름 또는 이메일로 검색 - - 사용자 선택하여 추가 - - 칩으로 표시, X 버튼으로 제거 가능 (본인 제외) -8. (선택) 안건 입력 (텍스트 영역) -9. "예약 완료" 버튼 클릭 +1. "회의예약" FAB 클릭 → 제목/날짜/시간(15분 단위) 입력 +2. 온라인/오프라인 선택, 장소/회의 링크 입력 +3. 참여자 추가(현재 사용자 기본 포함, 검색 모달), (선택) 안건 입력 → "예약 완료" -**입력:** -- 회의 제목: 텍스트 입력, 필수, 최대 100자, 문자 카운터 표시 -- 날짜: date 타입, 필수, 오늘 이후 날짜만 선택 가능, 달력 아이콘(📅) 표시 -- 시작 시간: 커스텀 시간 선택기 (readonly), 필수, 15분 단위 (00, 15, 30, 45) -- 종료 시간: 커스텀 시간 선택기 (readonly), 필수, 15분 단위 -- 온라인 회의: 토글 스위치 (선택) -- 장소: 텍스트 입력, 선택, 최대 200자, 문자 카운터 표시 -- 회의 링크: URL 입력, 선택, 온라인 회의인 경우에만 표시, "자동 생성" 버튼 제공 -- 참여자: 검색 모달, 필수 (최소 1명), 현재 사용자는 기본 포함 -- 안건: 텍스트 영역 (textarea), 선택, 여러 줄 입력 가능 +**입력:** 제목(최대 100자), 날짜(오늘 이후), 시작/종료 시간(15분 단위), 온라인 토글, 장소(최대 200자), 회의 링크(선택), 참여자(최소 1명), 안건(선택) -**출력/결과:** -- 예약 완료: "회의가 예약되었습니다" 토스트 메시지, 대시보드로 이동 -- 참여자 추가 성공: "{이름}님이 추가되었습니다" 토스트 메시지 -- 회의 링크 생성: "회의 링크가 생성되었습니다" 토스트 메시지 +**출력:** 예약 완료 토스트 및 대시보드 이동 -**예외처리:** -- 제목 미입력: "회의 제목을 입력해주세요" 토스트, 제목 필드 포커스 -- 날짜 미선택: "회의 날짜를 선택해주세요" 토스트, 날짜 필드 포커스 -- 시간 미선택: "회의 시간을 선택해주세요" 토스트 -- 참여자 없음: "최소 1명의 참여자를 추가해주세요" 토스트 -- 과거 날짜 선택: "과거 날짜는 선택할 수 없습니다" 토스트, 날짜 필드 포커스 -- 뒤로가기/취소 클릭: "작성 중인 내용이 있습니다. 나가시겠습니까?" 확인 모달 -- 참여자 검색 결과 없음: "검색 결과가 없습니다" 빈 상태 표시 +**예외:** 필수 항목 미입력 시 토스트 및 포커스, 과거 날짜 선택 시 에러, 뒤로가기/취소 시 확인 모달 -**관련 유저스토리:** -- UFR-USER-020: 대시보드 조회 -- UFR-MEET-011: 회의정보수정 -- UFR-MEET-020: 템플릿선택 +**관련:** UFR-USER-020, UFR-MEET-011/020 --- -#### UFR-MEET-011: 🟡 [회의정보수정] 회의 생성자로서 | 나는, 예정된 회의 정보를 변경하기 위해 | 회의 정보를 수정하고 싶다. +#### UFR-MEET-011: 🟡 [회의정보수정] 회의 생성자로서 | 나는, 예정된 회의 정보를 변경하기 위해 | 회의 정보를 수정하고 싶다 **수행절차:** -1. 대시보드(02-대시보드.html)에서 예정된 회의(scheduled) 카드 클릭 (생성자만 가능) -2. 회의예약 화면(03-회의예약.html)으로 이동 (기존 회의 정보 로드) -3. 수정할 항목 변경 (제목, 날짜, 시간, 장소, 참여자, 안건 등) -4. "수정 완료" 버튼 클릭 -5. 변경 사항 저장 및 참여자에게 알림 발송 +1. 대시보드에서 예정 회의 클릭(생성자만) → 수정 → "수정 완료" -**입력:** -- 기존 회의 정보: 자동 로드 (제목, 날짜, 시간, 장소, 참여자, 안건) -- 수정 항목: UFR-MEET-010과 동일한 입력 필드 +**입력:** 기존 회의 정보 자동 로드, UFR-MEET-010과 동일 필드 -**출력/결과:** -- 수정 완료: "회의 정보가 수정되었습니다" 토스트 메시지, 대시보드로 이동 -- 참여자 변경 시: 기존 참여자 및 신규 참여자에게 알림 발송 - - 알림 유형: "회의 정보 변경" - - 알림 내용: "{회의 제목} 회의 정보가 변경되었습니다" +**출력:** 수정 완료 토스트, 참여자 변경 시 알림 발송 -**예외처리:** -- 회의 상태가 'scheduled'가 아닌 경우: "진행 중이거나 종료된 회의는 수정할 수 없습니다" 에러 메시지 -- 유효성 검사 실패: UFR-MEET-010과 동일한 예외처리 -- 뒤로가기/취소 클릭: "변경 사항이 저장되지 않았습니다. 나가시겠습니까?" 확인 모달 -- 직접 URL 접근 시 권한 없음: 대시보드로 자동 리다이렉트 (별도 에러 메시지 없음) +**예외:** scheduled 아닌 경우 에러, 직접 URL 접근 시 리다이렉트 -**관련 유저스토리:** -- UFR-USER-020: 대시보드 조회 -- UFR-MEET-010: 회의예약 -- UFR-NOTI-010: 알림발송 +**관련:** UFR-USER-020, UFR-MEET-010, UFR-NOTI-010 --- #### UFR-MEET-015: 🟢 [회의진행 중 참여자 초대] 회의 참여자로서 | 나는, 회의 중 추가 참여자가 필요할 때 | 실시간으로 참여자를 초대하고 싶다. **수행절차:** -1. 회의 진행 화면(05-회의진행.html)에서 "참여자" 탭 클릭 -2. "초대" 버튼 클릭 -3. 검색 모달에서 이름 또는 이메일로 검색 -4. 사용자 선택하여 초대 -5. 초대된 참여자 실시간 표시 -6. 초대된 참여자에게 알림 전송 +1. "참여자" 탭 → "초대" → 검색 → 선택 → 실시간 표시 및 알림 전송 -**입력:** -- 검색어: 텍스트 입력, 이름 또는 이메일로 검색 -- 선택: 검색 결과 목록에서 사용자 클릭 +**출력:** 참여자 목록 실시간 추가, 토스트 메시지, 알림 대상 생성(Notification 폴링), WebSocket 동기화 -**출력/결과:** -- 초대 성공: 참여자 목록에 실시간 추가, "{이름}님을 초대했습니다" 토스트 메시지 -- 초대된 참여자에게 알림 대상 생성: - - 알림 유형: "회의 참여자 초대" - - 알림 내용: "{회의 제목}에 참여자로 초대되었습니다" - - 수신자: 초대된 참여자 - - 발송 예정 시각: 즉시 -- Notification 서비스가 주기적으로 폴링하여 이메일 발송 -- 모든 참여자에게 참여자 변경 사항 실시간 동기화 (WebSocket) +**예외:** 검색 결과 없음, 이미 참여 중, 네트워크 오류 -**예외처리:** -- 검색 결과 없음: "검색 결과가 없습니다" 빈 상태 표시 -- 이미 참여 중인 사용자: 선택 불가 또는 "이미 참여 중입니다" 안내 -- 네트워크 오류: "초대에 실패했습니다" 에러 메시지 - -**관련 유저스토리:** -- UFR-MEET-030: 회의시작 +**관련:** UFR-MEET-030 --- #### UFR-MEET-020: 🟡 [템플릿선택] 회의 생성자로서 | 나는, 회의록을 효율적으로 작성하기 위해 | 회의 유형에 맞는 템플릿을 선택하고 싶다. -**템플릿선택 진입 경로:** -- **경로 1**: 대시보드(02-대시보드.html) → "바로시작" FAB 버튼 → 템플릿 선택(04-템플릿선택.html) -- **경로 2**: 회의예약 (03-회의예약.html) → 템플릿 선택(04-템플릿선택.html) +**진입 경로:** 대시보드 → "바로시작" 또는 회의예약 → 템플릿 선택 **수행절차:** -1. 위 경로 중 하나를 통해 템플릿 선택 화면(04-템플릿선택.html) 진입 -2. 4가지 템플릿 중 선택 또는 "건너뛰기" 선택 - - 일반 회의: 회의 개요, 논의 사항, 결정 사항, 액션 아이템 - - 스크럼 회의: 어제 한 일, 오늘 할 일, 블로커/이슈 - - 킥오프 회의: 프로젝트 개요, 목표 및 범위, 역할 및 책임, 일정 및 마일스톤 - - 주간 회의: 지난주 성과, 이번주 계획, 주요 이슈, 다음 액션 -3. 선택 완료 시 회의 시작 (05-회의진행.html로 이동) +1. 4가지 템플릿(일반, 스크럼, 킥오프, 주간) 중 선택 또는 건너뛰기 → 회의 시작 -**입력:** -- 템플릿 선택: 4가지 중 1개 선택 또는 건너뛰기 -- 템플릿 카드 클릭 시 해당 템플릿 선택 +**출력:** 선택 템플릿으로 회의 시작, 건너뛰기 시 기본 템플릿 -**출력/결과:** -- 템플릿 선택: 선택한 템플릿으로 회의 시작, 회의 진행 화면으로 이동 -- 건너뛰기: 기본 템플릿(일반 회의)으로 회의 시작 -- 템플릿 미리보기: 아이콘, 설명, 섹션 목록 표시 +**예외:** 없음 -**예외처리:** -- 없음 (선택 또는 건너뛰기 모두 허용) - -**관련 유저스토리:** -- UFR-USER-020: 대시보드 조회 -- UFR-MEET-010: 회의예약 -- UFR-MEET-030: 회의시작 +**관련:** UFR-USER-020, UFR-MEET-010/030 --- #### UFR-MEET-030: 🔴 [회의시작] 회의 생성자로서 | 나는, 회의를 시작하고 회의록을 작성하기 위해 | 회의를 시작하고 음성 녹음을 준비하고 싶다. -**회의 진입 경로:** +**진입 경로:** - **경로 1**: 대시보드(02-대시보드.html) → "바로시작" FAB 버튼 → 템플릿 선택(04-템플릿선택.html) → 회의 진행(05-회의진행.html) - **경로 2**: 대시보드 → 진행 중 회의 "참여하기" 버튼 → 회의 진행(05-회의진행.html) **수행절차:** -1. 위 경로 중 하나를 통해 회의 진행 화면(05-회의진행.html) 진입 -2. 회의 진행 화면 표시 -3. 녹음 시작 확인 (자동 또는 수동) -4. 타이머 시작 (회의 진행 시간 표시) -5. 웨이브폼 애니메이션 표시 (녹음 상태 시각화) -6. 탭 네비게이션으로 기능 전환: - - 참여자: 참여자 목록 및 실시간 초대 - - AI 제안: 실시간 AI 분석 결과 및 개인 메모 작성 - - AI가 인식한 주요 내용 표시 - - 참여자별 개인 메모 작성 영역 (수동 저장만 지원) - - 용어사전: 실시간 AI 자동 인식된 용어 및 검색 - - 관련회의록: 실시간 AI 자동 연결된 이전 회의록 -7. 하단 고정 버튼 (역할별 차별화) - - 회의 생성자: [일시정지/녹음재개] + [회의 종료] - - 회의 참여자: [회의 나가기] +1. 회의 진행 화면 진입 → 녹음 시작 → 타이머/웨이브폼 표시 +2. 탭 전환: 참여자, AI 제안(주요 내용+메모), 용어사전, 관련회의록 +3. 하단 버튼: 생성자[일시정지/재개+종료], 참여자[나가기] -**입력:** -- 녹음 시작/일시정지: 버튼 클릭 -- 탭 전환: 탭 클릭 -- 메모 작성: 텍스트 입력 +**출력:** 헤더(제목, 녹음 상태, 경과 시간), 웨이브폼, 탭별 콘텐츠, 역할별 버튼 -**출력/결과:** -- 헤더: 회의 제목, 녹음 상태 (녹음 중/일시정지), 경과 시간 -- 웨이브폼 애니메이션: 녹음 상태 시각화 -- 참여자 탭: 참여자 목록, 초대 버튼 -- AI 제안 탭: - - AI가 인식한 주요 내용 리스트 - - 개인 메모 작성 영역 (참여자별 독립) - - 저장 버튼 (수동 저장만) -- 용어사전 탭: 자동 추출된 용어, 검색 기능 -- 관련회의록 탭: 자동 연결된 이전 회의록 목록 -- 하단 고정 버튼: - - 회의 생성자: [일시정지/녹음재개] + [회의 종료] - - 회의 참여자: [회의 나가기] +**예외:** 마이크 권한 없음, 네트워크 오류, 일시정지/종료/나가기 확인 모달 -**예외처리:** -- 녹음 권한 없음: "마이크 권한이 필요합니다" 에러 메시지 -- 네트워크 오류: "녹음 중 오류가 발생했습니다" 에러 메시지 -- 일시정지 확인: "일시정지하시겠습니까?" 확인 모달 -- 회의 종료 확인 (생성자): "회의를 종료하시겠습니까? 모든 참여자의 회의가 종료됩니다" 확인 모달 -- 회의 나가기 확인 (참여자): "회의에서 나가시겠습니까? 저장하지 않은 메모는 삭제됩니다" 확인 모달 - -**관련 유저스토리:** -- UFR-MEET-020: 템플릿선택 -- UFR-MEET-015: 참여자 실시간 초대 -- UFR-MEET-040: 회의종료 -- UFR-STT-010: 음성녹음인식 -- UFR-AI-030: 실시간 AI 제안 -- UFR-RAG-010: 전문용어감지 -- UFR-AI-040: 관련회의록연결 -- UFR-PART-010: 회의입장 -- UFR-PART-020: AI기반메모작성 -- UFR-PART-030: 회의중도퇴장 -- UFR-HOST-010: 회의종료권한 -- UFR-HOST-020: 녹음제어권한 +**관련:** UFR-MEET-020/040, UFR-STT-010, UFR-AI-030, UFR-RAG-010, UFR-AI-040, UFR-PART-010/020/030, UFR-HOST-010/020 --- @@ -372,389 +172,151 @@ - 일반 참여자는 "회의 종료" 버튼이 표시되지 않음 **수행절차:** -1. 회의 진행 화면에서 "회의 종료" 버튼 클릭 (생성자 전용) -2. 종료 확인 모달: "회의를 종료하시겠습니까?" 확인 -3. 회의 종료 화면(07-회의종료.html) 표시 (확인 전용, 편집 불가) -4. 통계 확인 (4열 그리드): - - 참여자 수 - - 회의 시간 - - 안건 수 - - Todo 수 -5. 주요 키워드 확인 (태그 형태) -6. 안건별 AI 요약 확인 (아코디언 카드): - - AI 한줄 요약 (30자 이내, 편집 불가) - - AI 상세 요약 (회의종료 단계에서는 편집 불가) - - 자동 추출된 Todo 목록 -7. 하단 액션 바에서 다음 단계 선택: - - 옵션 1: "회의록 수정" → 회의록 수정 화면(11-회의록수정.html)으로 이동 - - 옵션 2: "바로 최종 확정" → 모든 안건 자동 검증 완료 처리 후 최종 확정 - - 옵션 3: "대시보드" → 대시보드(02-대시보드.html)로 이동 +1. "회의 종료" → 확인 모달 → 회의 종료 화면(읽기 전용) +2. 통계(참여자/시간/안건/Todo), 주요 키워드, 안건별 AI 요약(한줄+상세+Todo) 확인 +3. 하단 액션: "회의록 수정", "바로 최종 확정", "대시보드" -**입력:** -- 하단 액션 버튼 클릭 +**출력:** 통계 카드, 키워드 태그, 안건 아코디언(AI 한줄+상세 요약, Todo), 회의록 상태 "작성중" -**출력/결과:** -- 회의 종료 화면 표시: - - 통계 카드 (4열): 참여자, 시간, 안건, Todo - - 주요 키워드 태그 - - 안건 아코디언 카드: AI 한줄 요약 + 상세 요약 + Todo - - 읽기 전용 안내 표시 -- 회의록 상태: "작성중"으로 저장 -- 옵션 선택에 따른 화면 전환 - -**예외처리:** -- AI 요약 생성 실패: "요약 생성 중 오류가 발생했습니다" 에러 메시지, 기본 템플릿으로 대체 -- Todo 추출 실패: 빈 Todo 목록 표시 -- 바로 확정 실패: "최종 확정 중 오류가 발생했습니다" 에러 메시지 - -**관련 유저스토리:** -- UFR-MEET-030: 회의시작 -- UFR-MEET-050: 최종확정 -- UFR-MEET-055: 회의록수정 -- UFR-AI-010: 회의록자동작성 -- UFR-AI-020: Todo자동추출 -- UFR-AI-036: AI한줄요약 +**예외:** AI 요약 생성 실패 시 기본 템플릿, Todo 추출 실패 시 빈 목록, 바로 확정 실패 시 에러 +**관련:** UFR-MEET-030/050/055, UFR-AI-010/020/036 --- #### UFR-MEET-050: 🟡 [최종확정] 회의 생성자로서 | 나는, 회의록을 완성하기 위해 | 모든 안건을 검증하고 최종 회의록을 확정하고 싶다. -**수행절차:** -**시나리오 1: 회의록 수정 후 자동 확정 (MVP v2.4.0)** -1. 회의록 수정 화면(11-회의록수정.html)에서 모든 안건 검증 완료 체크 -2. "저장" 버튼 클릭 -3. 시스템이 모든 안건 검증 완료 상태 확인 -4. 조건 충족 시 회의록 상태 자동 변경: "작성중" → "확정완료" -5. 확정 완료 토스트 메시지: "모든 안건이 검증되어 회의록이 확정되었습니다" -6. 회의록 상태 배지 자동 업데이트 (확정완료) +**시나리오 1: 회의록 수정 후 자동 확정** +1. 모든 안건 검증 완료 → "저장" → 시스템 확인 → 자동 "확정완료" 변경 → 토스트 **시나리오 2: 회의 종료 화면에서 바로 확정** -1. 회의 종료 화면(07-회의종료.html)에서 "바로 최종 확정" 버튼 클릭 -2. 확인 모달: "바로 최종 확정하시겠습니까? AI가 정리한 내용 그대로 확정됩니다" -3. 확인 시 모든 안건 자동 검증 완료 처리 -4. 회의록 상태: "확정완료"로 변경 -5. 회의록 상세 조회 화면으로 이동 +1. "바로 최종 확정" → 확인 모달 → 모든 안건 자동 검증 → "확정완료" → 상세 조회 화면 -**입력:** -- 시나리오 1: 안건별 검증 완료 체크박스 + 저장 버튼 -- 시나리오 2: "바로 최종 확정" 버튼 클릭 + 확인 모달 승인 +**출력:** 확정 토스트, 회의록 상태 "확정완료", 모든 안건 검증완료 -**출력/결과:** -- 시나리오 1 확정 성공: "모든 안건이 검증되어 회의록이 확정되었습니다" 토스트 메시지 -- 시나리오 2 확정 성공: "회의록이 최종 확정되었습니다" 토스트 메시지 -- 회의록 상태: "확정완료" -- 모든 안건 검증완료 상태로 변경 -- 확정 후 편집 권한: 회의 생성자만 잠금 해제 후 수정 가능 +**예외:** 자동 확정 조건 충족 시 자동 처리, 바로 확정 실패 시 에러 -**예외처리:** -- 시나리오 1: 자동 확정 조건 충족 시 자동 처리 (별도 에러 없음) -- 시나리오 2 확정 실패: "최종 확정 중 오류가 발생했습니다" 에러 메시지 -- 시나리오 2 확인 모달 취소: 현재 화면 유지 - -**관련 유저스토리:** -- UFR-MEET-040: 회의종료 -- UFR-MEET-055: 회의록수정 -- UFR-COLLAB-030: 검증완료 +**관련:** UFR-MEET-040/055, UFR-COLLAB-030 --- #### UFR-MEET-046: 🟡 [회의록목록조회] 회의 참여자로서 | 나는, 참여한 회의록들을 효율적으로 관리하기 위해 | 회의록 목록을 조회하고 필터링하고 싶다. **수행절차:** -1. 사이드바 또는 하단 네비게이션에서 "회의록" 메뉴 클릭 -2. 회의록 목록 조회 화면(12-회의록목록조회.html) 표시 -3. (선택) 정렬 기준 선택: - - 최근수정순 (기본값) - - 최근회의순 - - 제목순 -4. (선택) 참여 유형 필터 선택 (다중 선택 가능): - - 참여한 회의 (체크박스) - - 내가 생성한 회의 (체크박스) -5. (선택) 상태 필터 선택 (다중 선택 가능): - - 작성중 (체크박스) - - 확정완료 (체크박스) -6. (선택) 검색어 입력 (회의 제목, 참여자 이름) -7. 회의록 카드 클릭하여 상세 조회 +1. "회의록" 메뉴 → 정렬(최근수정순/최근회의순/제목순) → (선택) 필터(참여 유형, 상태), 검색어 → 카드 클릭 -**입력:** -- 정렬 기준: 선택 (최근수정순, 최근회의순, 제목순) -- 참여 유형 필터: 다중 체크박스 (참여한 회의, 내가 생성한 회의) -- 상태 필터: 다중 체크박스 (작성중, 확정완료) -- 검색어: 텍스트 입력 (선택) +**입력:** 정렬, 필터(다중 체크박스), 검색어(제목/참여자) -**출력/결과:** -- 헤더: "회의록" 제목, 총 회의록 개수 -- 필터 및 정렬 버튼 -- 회의록 카드 목록 (스크롤): - - 상태 배지 (작성중/확정완료) - - 생성자 표시 (👑 아이콘) - - 회의 제목 - - 날짜/시간 - - 참여자 수 - - 검증완료율 (작성중인 경우) -- 빈 상태: 검색 결과 없을 때 안내 메시지 +**출력:** 헤더(총 개수), 필터/정렬 버튼, 카드(상태 배지, 생성자 표시, 검증완료율) -**예외처리:** -- 회의록 없음: "참여한 회의록이 없습니다" 빈 상태 표시 -- 검색 결과 없음: "검색 결과가 없습니다" 빈 상태 표시 -- 네트워크 오류: "회의록을 불러오는 중 오류가 발생했습니다" 에러 메시지 +**예외:** 회의록/검색 결과 없음 시 빈 상태, 네트워크 오류 -**관련 유저스토리:** -- UFR-USER-020: 대시보드 -- UFR-MEET-047: 회의록상세조회 +**관련:** UFR-USER-020, UFR-MEET-047 --- #### UFR-MEET-047: 🟡 [회의록상세조회] 회의 참여자로서 | 나는, 지난 회의록의 상세 정보와 전체 내용을 | 한눈에 확인하고 싶다. **수행절차:** -1. 회의록 목록 또는 대시보드에서 회의록 카드 클릭 -2. 회의록 상세 조회 화면(10-회의록상세조회.html) 표시 -3. 헤더 정보 확인: 회의 제목, 날짜/시간, 참여자, 생성자, 상태 -4. 탭 네비게이션으로 내용 확인: - - 대시보드: 회의 통계, 주요 키워드, 안건별 한줄 요약 - - 회의록: 안건별 상세 내용, AI 요약, Todo 목록 - - Todo: Todo 목록 (제목, 담당자, 마감일, 상태) - - 용어: 회의 중 인식된 전문 용어 및 설명 - - 관련회의록: 연결된 과거 회의록 목록 -5. (선택) 회의록 수정 버튼 클릭 (작성중 상태일 때만) -6. (선택) Todo 추가 (모든 참여자) 또는 편집 (생성자만) +1. 카드 클릭 → 헤더 정보 확인 +2. 탭 전환: 대시보드(통계, 키워드, 한줄 요약), 회의록(안건별 상세), Todo, 용어, 관련회의록 +3. (선택) "회의록 수정"(작성중), Todo 추가(모든 참여자)/편집(생성자) -**입력:** -- 탭 전환: 탭 클릭 -- Todo 추가 버튼 (모든 참여자) -- Todo 편집 버튼 (생성자만) -- 회의록 수정 버튼 (작성중 상태) +**출력:** +- 헤더: 제목, 날짜/시간, 참여자 칩, 생성자(👑), 상태 배지 +- 대시보드: 통계(4열), 키워드 태그, 한줄 요약 아코디언 +- 회의록: 안건별 한줄+상세 요약, Todo +- Todo: 카드(제목, 담당자, 마감일, 상태), 추가(모든 참여자)/편집(생성자) 버튼 +- 용어/관련회의록 탭 +- 하단: "회의록 수정" 버튼(작성중만) -**출력/결과:** -- 헤더: - - 회의 제목, 날짜/시간 - - 참여자 칩 (이름, 아바타) - - 생성자 표시 (👑 아이콘) - - 상태 배지 (작성중/확정완료) -- 대시보드 탭: - - 통계 카드 (4열): 참여자, 시간, 안건, Todo - - 주요 키워드 (태그 형태) - - 안건별 한줄 요약 (아코디언 카드) -- 회의록 탭: - - 안건별 아코디언 카드: - - AI 한줄 요약 (30자 이내) - - AI 상세 요약 (읽기 전용) - - Todo 목록 (읽기 전용) -- Todo 탭: - - Todo 카드 목록 (제목, 담당자, 마감일, 상태) - - Todo 추가 버튼 (모든 참여자) - - Todo 편집 버튼 (생성자만, 각 Todo 카드에 표시) -- 용어 탭: - - 용어 카드 목록 (용어, 설명) -- 관련회의록 탭: - - 관련 회의록 카드 목록 (제목, 날짜, 관련도, 유사 내용 요약) -- 하단 액션 버튼: - - "회의록 수정" 버튼 (작성중 상태일 때만 표시) +**예외:** 권한 없음 시 리다이렉트, 회의록 없음, 네트워크 오류 -**예외처리:** -- 권한 없음: "이 회의록을 볼 권한이 없습니다" 에러 메시지, 대시보드로 리다이렉트 -- 회의록 없음: "회의록을 찾을 수 없습니다" 에러 메시지 -- 네트워크 오류: "회의록을 불러오는 중 오류가 발생했습니다" 에러 메시지 - -**Todo 추가 권한:** -- 모든 회의 참여자가 Todo 추가 가능(Todo 추가 버튼은 모든 참여자에게 노출) -- Todo 추가 모달: 제목, 담당자, 마감일 입력 - -**Todo 편집 권한:** -- 회의 생성자만 Todo 편집 가능(편집 버튼은 생성자에게만 노출) -- Todo 편집 모달: 제목, 담당자, 마감일 수정 (바텀시트 스타일) - -**관련 유저스토리:** -- UFR-MEET-046: 회의록목록조회 -- UFR-MEET-055: 회의록수정 -- UFR-AI-036: AI한줄요약 +**관련:** UFR-MEET-046/055, UFR-AI-036 --- #### UFR-MEET-055: 🟡 [회의록수정] 회의 참여자로서 | 나는, 검증이 완료되지 않은 안건을 | 수정하고 검증완료 체크를 통해 보호하고 싶다. **수행절차:** -1. 회의록 상세 조회 화면(10-회의록상세조회.html)에서 "회의록 수정" 버튼 클릭 (작성중 상태) -2. 회의록 수정 화면(11-회의록수정.html)으로 이동 -3. 안건별 아코디언 카드에서 수정: - - AI 한줄 요약 재생성: "재생성" 버튼 클릭 (텍스트 편집 영역 내용 기반) - - 상세 요약 편집: 텍스트 영역에서 직접 수정 (초기에는 AI가 생성한 내용 로드) -4. 검증완료 처리: - - 참여자: 안건별 "검증완료" 체크박스 체크 - - 생성자: 검증완료 후에도 "잠금해제" 버튼으로 재수정 가능 -5. "저장" 버튼 클릭하여 수정 내용 저장 +1. "회의록 수정" → 안건별 수정(한줄 요약 재생성, 상세 요약 편집) +2. 검증완료: 참여자(체크박스), 생성자(잠금해제 버튼) → "저장" -**입력:** -- AI 한줄 요약 재생성: 버튼 클릭 (텍스트 편집 영역 내용 기반) -- 상세 요약 편집: 텍스트 영역 편집 -- 검증완료 체크: 체크박스 (참여자) -- 잠금해제 버튼: 버튼 클릭 (생성자, 검증완료된 안건) -- 저장 버튼: 버튼 클릭 +**입력:** 재생성 버튼, 텍스트 편집 영역, 검증완료 체크, 잠금해제(생성자) -**출력/결과:** -- 헤더: - - 회의 제목, 날짜/시간 - - "저장" 버튼 -- 안건별 아코디언 카드: - - AI 한줄 요약 (읽기 전용) + "재생성" 버튼 - - 텍스트 편집 영역 (상세 요약 편집 가능) - - 관련회의록 추가/제거 - - 검증완료 UI: - - 참여자: 체크박스만 표시 - - 생성자: 검증완료 시 "잠금해제" 버튼 표시 -- 저장 결과: "N개 안건이 저장되었습니다" 토스트 메시지 -- 모든 안건 검증 완료 시: "모든 안건이 검증되어 회의록이 확정되었습니다" 토스트 메시지 (자동 확정) +**출력:** 헤더(제목, 저장), 안건 아코디언(한줄 요약+재생성, 편집 영역, 관련회의록, 검증완료 UI), 저장 토스트, 모든 안건 검증 시 자동 확정 토스트 -**예외처리:** -- 검증완료된 안건 수정 시도 (참여자): 체크박스 비활성화, "이미 검증된 안건입니다" 안내 -- 검증완료된 안건 수정 (생성자): "잠금해제" 버튼으로 재수정 가능 -- AI 재생성 실패: "재생성 중 오류가 발생했습니다" 에러 메시지 -- 네트워크 오류: "저장 중 오류가 발생했습니다" 에러 메시지 +**예외:** 검증완료 안건 수정 시도 시 안내(참여자), 잠금해제 가능(생성자), AI 재생성 실패, 네트워크 오류 -**Last Write Wins 정책:** -- 동일 안건을 여러 참여자가 동시 수정 시 마지막 저장이 유지됨 -- 검증완료 체크로 안건 보호 가능 -- 생성자는 검증완료된 안건도 잠금해제 후 재수정 가능 +**Last Write Wins:** 동시 수정 시 마지막 저장 유지, 검증완료로 보호, 생성자는 잠금해제 후 재수정 -**관련 유저스토리:** -- UFR-MEET-047: 회의록상세조회 -- UFR-MEET-050: 최종확정 -- UFR-AI-036: AI한줄요약 -- UFR-COLLAB-030: 검증완료 +**관련:** UFR-MEET-047/050, UFR-AI-036, UFR-COLLAB-030 --- #### UFR-PART-010: 🟡 [회의입장] 회의 참여자로서 | 나는, 예정된 회의에 참여하기 위해 | 대시보드에서 "참여하기" 버튼으로 회의에 입장하고 싶다. **수행절차:** -1. 대시보드에서 진행 중 또는 예정된 회의 확인 -2. "참여하기" 버튼 클릭 -3. 회의진행 화면으로 페이지 전환 (같은 탭) -4. 회의 참여자로 입장 완료 +1. 대시보드 진행 중/예정 회의 → "참여하기" → 회의진행 화면 -**입력:** -- 회의 ID -- 사용자 ID +**출력:** 회의진행 화면, 참여자 목록 추가 -**출력/결과:** -- 회의진행 화면 표시 -- 참여자 목록에 추가 +**예외:** 회의 종료/권한 없음 시 안내 -**예외처리:** -- 회의 종료됨: "이미 종료된 회의입니다" 안내 -- 권한 없음: "참여 권한이 없습니다" 안내 - -**관련 유저스토리:** -- UFR-MEET-030: 회의시작 +**관련:** UFR-MEET-030 --- #### UFR-PART-020: 🟢 [AI기반메모작성] 회의 참여자로서 | 나는, 중요한 내용을 메모로 기록하기 위해 | AI가 추천한 주요 내용을 메모 입력창에 추가하고 편집하고 싶다. **수행절차:** -1. 회의 진행 중 AI가 실시간으로 주요 내용 감지 및 분석 -2. "AI 제안" 탭 하단에 "AI가 감지한 주요 내용" 리스트로 표시 - - 각 항목: "[시간] 주요 내용 텍스트" 형식 - - 예: "[15:32] 예산 책정 관련 결정", "[15:35] 다음 회의 일정 합의" -3. 참여자가 리스트 항목 선택 시: - - 메모 입력창에 시간과 함께 자동 입력 - - 입력된 메모는 수정 가능 (자동/수동 구분 표시) -4. "저장" 버튼 클릭 시 개인 메모로 저장 - - 각 참여자별로 개별 저장 - - 다른 참여자의 메모는 볼 수 없음 -5. 회의 종료 시 AI가 회의록 생성할 때 모든 참여자의 메모 참조 -6. 메모는 회의 종료 전까지만 표시 및 편집 가능 +1. 회의 중 AI 실시간 주요 내용 감지 → "AI 제안" 탭에 "[시간] 내용" 리스트 표시 +2. 항목 선택 시 메모 입력창에 자동 입력(시간 포함) → 수정 가능 → "저장"(참여자별 개별) +3. 회의 종료 시 AI가 모든 참여자 메모 참조하여 회의록 생성 -**입력:** -- 회의 ID -- AI가 실시간 감지한 주요 내용 -- 참여자가 선택하거나 직접 입력한 메모 텍스트 +**출력:** 메모 입력창(시간 포함), AI 추천 리스트(실시간), 저장된 개인 메모(참여자별), AI 회의록(메모 참조) -**출력/결과:** -- 메모 입력창: 시간 포함 메모 텍스트 -- AI 추천 리스트: 실시간 업데이트되는 주요 내용 항목들 -- 저장된 개인 메모: 참여자별 개별 저장 -- AI 회의록 생성 시: 모든 참여자의 메모 참조하여 요약 생성 +**예외:** AI 감지 실패 시 빈 리스트(수동 가능), 저장 실패 시 로컬 임시 저장, 회의 종료 후 조회/편집 불가 -**예외처리:** -- AI 감지 실패: 빈 리스트 표시, 수동 메모 작성은 가능 -- 저장 실패: "메모 저장 중 오류가 발생했습니다" 에러 메시지, 로컬 임시 저장 -- 회의 종료 후: 메모 조회/편집 불가 - -**관련 유저스토리:** -- UFR-AI-030: 실시간 AI 제안 -- UFR-AI-010: 회의록자동작성 (메모 참조) -- UFR-MEET-040: 회의종료 +**관련:** UFR-AI-030, UFR-AI-010, UFR-MEET-040 --- #### UFR-PART-030: 🟡 [회의중도퇴장] 회의 참여자로서 | 나는, 회의를 중간에 나가야 할 때 | "나가기" 버튼으로 회의에서 퇴장하고 싶다. **수행절차:** -1. 회의진행 화면 상단 "나가기" 버튼 클릭 -2. 확인 모달 표시: "회의에서 나가시겠습니까? 회의는 계속 진행됩니다" -3. 확인 클릭 시 퇴장 이벤트 서버 전송 -4. 대시보드로 페이지 전환 +1. "나가기" → 확인 모달("회의는 계속 진행됩니다") → 퇴장 이벤트 전송 → 대시보드 -**입력:** -- 회의 ID -- 사용자 ID +**출력:** 대시보드 복귀, 회의록은 종료 시 공유 -**출력/결과:** -- 대시보드 화면으로 복귀 -- 회의록은 종료 시 공유됨 +**예외:** 네트워크 오류 시 로컬 처리 후 재시도 -**예외처리:** -- 네트워크 오류: 로컬 처리 후 재시도 - -**관련 유저스토리:** -- UFR-MEET-030: 회의시작 +**관련:** UFR-MEET-030 --- #### UFR-HOST-010: 🔴 [회의종료권한] 회의 생성자로서 | 나는, 회의를 마무리하기 위해 | "회의 종료" 버튼으로만 회의를 종료하고 싶다. **수행절차:** -1. 회의진행 화면에서 "회의 종료" 버튼은 생성자에게만 표시 -2. 일반 참여자에게는 버튼 숨김 처리 -3. 생성자가 "회의 종료" 클릭 시 회의 종료 프로세스 진행 +1. "회의 종료" 버튼은 생성자에게만 표시, 일반 참여자는 숨김 -**입력:** -- 회의 ID -- 사용자 ID (생성자 여부 확인) +**출력:** 생성자-버튼 표시, 참여자-버튼 숨김 -**출력/결과:** -- 생성자: 회의 종료 버튼 표시 및 동작 -- 일반 참여자: 버튼 숨김 +**예외:** 권한 없음 시 미표시 -**예외처리:** -- 권한 없음: 버튼 미표시 - -**관련 유저스토리:** -- UFR-MEET-040: 회의종료 +**관련:** UFR-MEET-040 --- #### UFR-HOST-020: 🔴 [녹음제어권한] 회의 생성자로서 | 나는, 녹음을 관리하기 위해 | 녹음 일시정지/재개/종료 권한을 가지고 싶다. **수행절차:** -1. 회의진행 화면에서 녹음 제어 버튼은 생성자에게만 표시 -2. 일반 참여자에게는 버튼 숨김 처리 +1. 녹음 제어 버튼(일시정지/재개/종료)은 생성자에게만 표시 -**입력:** -- 회의 ID -- 사용자 ID (생성자 여부 확인) +**출력:** 생성자-버튼 표시, 참여자-버튼 숨김 -**출력/결과:** -- 생성자: 녹음 제어 버튼 표시 및 동작 -- 일반 참여자: 버튼 숨김 +**예외:** 권한 없음 시 미표시 -**예외처리:** -- 권한 없음: 버튼 미표시 - -**관련 유저스토리:** -- UFR-STT-010: 음성녹음인식 +**관련:** UFR-STT-010 --- @@ -763,316 +325,133 @@ #### UFR-AI-010: 🔴 [회의록자동작성] 회의 참여자로서 | 나는, 회의록 작성 부담을 줄이기 위해 | AI가 발언 내용을 실시간으로 정리하고 회의 종료 시 전체 안건을 요약하기를 원한다. **수행절차:** -1. 회의 진행 중: STT 서비스가 음성을 텍스트로 변환하여 AI 서비스에 전송 -2. AI 서비스가 발언 내용 분석: - - 주요 키워드 추출 - - 발언자 식별 - - 안건별 내용 분류 -3. 회의 종료 시: - - 모든 참여자의 메모 수집 (UFR-PART-020) - - 전체 발언 내용과 메모를 종합하여 안건별 AI 요약 생성 - - AI 한줄 요약 생성 (30자 이내) - - AI 상세 요약 생성 (각 안건별) -4. 회의록 자동 생성 및 저장 (작성중 상태) +1. 회의 중: STT 텍스트 → AI 분석(키워드 추출, 발언자 식별, 안건 분류) +2. 회의 종료: 모든 참여자 메모 수집 → 전체 발언+메모 종합 → 안건별 AI 한줄+상세 요약 생성 → 회의록 저장(작성중) -**입력:** -- 회의 ID -- STT 텍스트 스트림 -- 참여자별 개인 메모 +**입력:** 회의 ID, STT 텍스트, 참여자별 메모 -**출력/결과:** -- 실시간: 주요 키워드, 발언자, 안건 분류 -- 회의 종료 시: - - 안건별 AI 한줄 요약 (30자 이내) - - 안건별 AI 상세 요약 - - Todo 자동 추출 (UFR-AI-020) - - 회의록 상태: "작성중" +**출력:** 실시간(키워드, 발언자, 안건), 종료 시(한줄+상세 요약, Todo, 작성중 상태) -**예외처리:** -- STT 텍스트 없음: 기본 템플릿으로 회의록 생성 -- AI 요약 생성 실패: "요약 생성 중 오류가 발생했습니다" 에러 메시지, 수동 작성 유도 -- 참여자 메모 없음: 발언 내용만으로 요약 생성 +**예외:** STT 없음 시 기본 템플릿, AI 요약 실패 시 에러 및 수동 작성 유도, 메모 없음 시 발언만 요약 -**관련 유저스토리:** -- UFR-STT-020: 텍스트변환 -- UFR-MEET-040: 회의종료 -- UFR-AI-020: Todo자동추출 -- UFR-AI-036: AI한줄요약 -- UFR-PART-020: AI기반메모작성 +**관련:** UFR-STT-020, UFR-MEET-040, UFR-AI-020/036, UFR-PART-020 --- #### UFR-AI-020: 🟡 [Todo자동추출] 회의 참여자로서 | 나는, 회의 후 실행 사항을 명확히 하기 위해 | AI가 안건별 내용에서 Todo 항목을 자동으로 추출하고 기본값을 설정하기를 원한다. **수행절차:** -1. 회의 종료 시 AI가 안건별 내용 분석 -2. Todo 항목 자동 추출: - - 액션 동사 식별 ("작성", "검토", "준비", "확인" 등) - - 담당자 추론 (발언 맥락 분석) - - 마감일 추론 (회의 내용 기반) -3. 추출된 Todo 목록 회의록에 추가 -4. 회의록 수정 화면에서 수동 수정 가능 +1. 회의 종료 시 안건별 내용 분석 → Todo 추출(액션 동사, 담당자 추론, 마감일 추론) → 회의록 추가 -**입력:** -- 회의 ID -- 안건별 AI 요약 텍스트 -- 발언 내용 전체 +**입력:** 회의 ID, 안건별 AI 요약, 발언 내용 -**출력/결과:** -- Todo 목록: - - 제목: 자동 생성 (예: "보고서 작성", "회의실 예약") - - 담당자: 자동 추론 또는 "미정" - - 마감일: 자동 추론 또는 "미정" - - 상태: "미완료" (기본값) -- Todo 개수 통계 (회의 종료 화면, 회의록 상세 조회) +**출력:** Todo 목록(제목, 담당자, 마감일, 상태-기본 "미완료"), Todo 개수 통계 -**예외처리:** -- Todo 추출 실패: 빈 Todo 목록으로 저장, 수동 추가 가능 -- 담당자 추론 실패: "미정"으로 설정 -- 마감일 추론 실패: "미정"으로 설정 +**예외:** 추출 실패 시 빈 목록(수동 추가 가능), 담당자/마감일 추론 실패 시 "미정" -**관련 유저스토리:** -- UFR-AI-010: 회의록자동작성 -- UFR-MEET-040: 회의종료 -- UFR-MEET-047: 회의록상세조회 +**관련:** UFR-AI-010, UFR-MEET-040/047 --- #### UFR-AI-030: 🟢 [실시간AI제안] 회의 참여자로서 | 나는, 회의 중 놓치는 내용을 최소화하기 위해 | AI가 실시간으로 주요 내용을 분석하여 제안하고 싶다. **수행절차:** -1. 회의 진행 중 STT 텍스트를 실시간으로 AI 서비스에 전송 -2. AI가 주요 내용 감지: - - 중요 결정 사항 - - 액션 아이템 - - 주요 키워드 - - 합의 사항 -3. "AI 제안" 탭에 실시간 업데이트: - - "[시간] 주요 내용 텍스트" 형식으로 표시 - - 예: "[15:32] 예산 책정 관련 결정", "[15:35] 다음 회의 일정 합의" -4. 참여자가 리스트 항목 선택 시 메모 입력창에 자동 입력 +1. 회의 중 STT 텍스트 → AI 주요 내용 감지(중요 결정, 액션 아이템, 키워드, 합의) → "AI 제안" 탭에 "[시간] 내용" 실시간 업데이트 → 항목 선택 시 메모 자동 입력 -**입력:** -- 회의 ID -- STT 텍스트 스트림 (실시간) +**입력:** 회의 ID, STT 텍스트(실시간) -**출력/결과:** -- "AI 제안" 탭: - - AI가 감지한 주요 내용 리스트 - - 시간 포함 (예: "[15:32]") - - 실시간 업데이트 -- 메모 입력창: - - 선택한 항목 자동 입력 - - 시간 포함 +**출력:** "AI 제안" 탭(주요 내용 리스트, 시간 포함, 실시간), 메모 입력창(선택 항목 자동 입력) -**예외처리:** -- AI 감지 실패: 빈 리스트 표시 -- 네트워크 오류: "AI 제안을 불러오는 중 오류가 발생했습니다" 에러 메시지 +**예외:** AI 감지 실패 시 빈 리스트, 네트워크 오류 -**관련 유저스토리:** -- UFR-STT-020: 텍스트변환 -- UFR-MEET-030: 회의시작 -- UFR-PART-020: AI기반메모작성 +**관련:** UFR-STT-020, UFR-MEET-030, UFR-PART-020 --- #### UFR-AI-036: 🟡 [AI한줄요약] 회의 참여자로서 | 나는, 각 안건의 핵심을 빠르게 파악하기 위해 | AI가 생성한 한줄 요약을 확인하고 필요 시 재생성하고 싶다. -**수행절차:** -**회의 종료 시 (자동 생성):** -1. AI가 안건별 상세 요약 기반으로 한줄 요약 자동 생성 -2. 한줄 요약 기준: 30자 이내, 핵심 키워드 포함 -3. 회의 종료 화면에서 읽기 전용으로 확인 +**회의 종료 시(자동):** AI가 안건별 상세 요약 기반 한줄 요약(30자 이내) 생성 → 회의 종료 화면 읽기 전용 확인 -**회의록 수정 시 (재생성):** -1. 회의록 수정 화면(11-회의록수정.html)에서 안건별 "재생성" 버튼 클릭 -2. AI가 현재 텍스트 편집 영역 내용 기반으로 한줄 요약 재생성 -3. 재생성된 한줄 요약으로 자동 업데이트 +**회의록 수정 시(재생성):** 안건별 "재생성" 클릭 → AI가 현재 텍스트 편집 영역 기반 한줄 요약 재생성 → 자동 업데이트 -**회의록 상세조회 시:** -1. 대시보드 탭: 안건별 한줄 요약 표시 -2. 회의록 탭: 안건별 한줄 요약 + 상세 요약 표시 +**회의록 상세조회:** 대시보드/회의록 탭에 한줄 요약 표시(읽기 전용) -**입력:** -- 안건별 상세 요약 텍스트 -- 재생성 버튼 클릭 (회의록 수정 시) +**입력:** 안건별 상세 요약, 재생성 버튼 -**출력/결과:** -- 한줄 요약: 30자 이내, 안건 핵심 내용 -- 표시 위치: - - 회의 종료 화면: 읽기 전용 - - 회의록 수정 화면: 재생성 가능 - - 회의록 상세조회 (대시보드 탭, 회의록 탭): 읽기 전용 +**출력:** 한줄 요약(30자 이내), 위치별 표시(종료-읽기, 수정-재생성 가능, 상세조회-읽기) -**예외처리:** -- AI 요약 생성 실패: "한줄 요약 생성 중 오류가 발생했습니다" 에러 메시지 -- 재생성 실패: "재생성 중 오류가 발생했습니다" 에러 메시지, 기존 요약 유지 +**예외:** 생성/재생성 실패 시 에러, 기존 요약 유지 -**관련 유저스토리:** -- UFR-AI-010: 회의록자동작성 -- UFR-MEET-040: 회의종료 -- UFR-MEET-047: 회의록상세조회 -- UFR-MEET-055: 회의록수정 +**관련:** UFR-AI-010, UFR-MEET-040/047/055 --- #### UFR-AI-040: 🟢 [관련회의록연결] 회의 참여자로서 | 나는, 이전 회의 내용을 쉽게 참조하기 위해 | AI가 같은 폴더 내 관련 있는 과거 회의록을 자동으로 찾아 연결하고 유사 내용을 요약해주기를 원한다. -**수행절차:** -**회의 진행 중 (실시간 연결):** -1. AI가 실시간으로 발언 내용 분석 -2. 벡터 유사도 검색을 통해 같은 폴더 내 과거 회의록 검색 -3. 관련도 높은 회의록 최대 3개 추출 (관련도 70% 이상) -4. 각 회의록에서 현재 회의와 유사한 부분 자동 추출 -5. 유사 내용을 3-5개 문장으로 요약 -6. "관련회의록" 탭에 실시간 업데이트 +**회의 진행 중(실시간):** +1. AI 발언 분석 → 벡터 유사도 검색(같은 폴더) → 관련도 70% 이상 최대 3개 추출 → 유사 부분 추출 → 3-5문장 요약 → "관련회의록" 탭 실시간 업데이트 -**회의록 상세조회 시:** -1. 회의록 상세 조회 화면(10-회의록상세조회.html) → "관련회의록" 탭 -2. 연결된 회의록 카드 표시: - - 회의 제목 - - 날짜/시간 - - 관련도 (퍼센트 표시, 예: 95%, 78%) - - 유사 내용 요약 (3-5개 문장) - - "전체 회의록 보기" 버튼 +**회의록 상세조회:** +1. "관련회의록" 탭 → 카드(제목, 날짜/시간, 관련도, 유사 내용 요약, "전체 보기" 버튼) -**입력:** -- 현재 회의 ID -- 현재 회의 내용 (실시간 STT 텍스트) -- 같은 폴더 내 과거 회의록 목록 +**입력:** 현재 회의 ID, 회의 내용(STT), 같은 폴더 과거 회의록 -**출력/결과:** -- "관련회의록" 탭: - - 관련 회의록 카드 (최대 3개) - - 각 카드: - - 회의 제목 - - 날짜/시간 - - 관련도 (예: 95%, 78%) - - 유사 내용 요약 (3-5개 문장) - - "전체 회의록 보기" 버튼 -- 실시간 업데이트 (회의 진행 중) +**출력:** "관련회의록" 탭(카드-제목, 날짜, 관련도, 요약, 버튼), 실시간 업데이트 -**예외처리:** -- 관련 회의록 없음: "관련 회의록이 없습니다" 빈 상태 표시 -- 유사도 검색 실패: "관련 회의록을 찾는 중 오류가 발생했습니다" 에러 메시지 -- 요약 생성 실패: 유사 내용 요약 없이 제목과 관련도만 표시 +**예외:** 관련 회의록 없음 시 빈 상태, 유사도 검색 실패, 요약 실패 시 제목+관련도만 표시 -**성능 최적화:** -- 과거 회의록 저장 시 요약본 미리 생성 (배치 처리) -- 실시간 요약은 캐싱된 데이터 활용 -- 성능 목표: 1초 이내 표시 +**성능:** 과거 회의록 저장 시 요약 미리 생성(배치), 실시간 요약 캐싱, 1초 이내 표시 -**관련 유저스토리:** -- UFR-MEET-030: 회의시작 -- UFR-MEET-047: 회의록상세조회 +**관련:** UFR-MEET-030/047 --- #### UFR-RAG-010: 🟢 [전문용어감지] 회의 참여자로서 | 나는, 업무 지식이 없어도 회의록을 정확히 작성하기 위해 | 전문용어가 자동으로 감지되고 맥락에 맞는 설명을 제공받고 싶다. **수행절차:** -1. 회의 진행 중 STT 텍스트를 실시간으로 AI 서비스에 전송 -2. AI가 전문용어 감지: - - 사내 용어 사전 참조 - - 관련 회의록 검색 - - 업무 이력 분석 -3. 감지된 용어를 "용어사전" 탭에 실시간 추가 -4. 각 용어에 대한 맥락 기반 설명 생성 (UFR-RAG-020) +1. 회의 중 STT 텍스트 → AI 전문용어 감지(사내 사전, 관련 회의록, 업무 이력) → "용어사전" 탭 실시간 추가 → 각 용어 클릭 시 맥락 기반 설명(UFR-RAG-020) -**입력:** -- 회의 ID -- STT 텍스트 스트림 (실시간) -- 사내 용어 사전 (RAG 시스템) +**입력:** 회의 ID, STT 텍스트(실시간), 사내 용어 사전(RAG) -**출력/결과:** -- "용어사전" 탭: - - 감지된 전문용어 목록 - - 실시간 업데이트 - - 각 용어 클릭 시 맥락 기반 설명 표시 +**출력:** "용어사전" 탭(감지된 용어 목록, 실시간, 클릭 시 설명) -**예외처리:** -- 용어 감지 실패: 빈 목록 표시 -- 사전 연결 오류: "용어 사전을 불러오는 중 오류가 발생했습니다" 에러 메시지 +**예외:** 용어 감지 실패 시 빈 목록, 사전 연결 오류 -**관련 유저스토리:** -- UFR-STT-020: 텍스트변환 -- UFR-RAG-020: 맥락기반용어설명 -- UFR-MEET-030: 회의시작 +**관련:** UFR-STT-020, UFR-RAG-020, UFR-MEET-030 --- #### UFR-RAG-020: 🟢 [맥락기반용어설명] 회의 참여자로서 | 나는, 전문용어를 맥락에 맞게 이해하기 위해 | 관련 회의록과 업무 이력을 바탕으로 실용적인 설명을 제공받고 싶다. **수행절차:** -1. 참여자가 "용어사전" 탭에서 용어 클릭 -2. AI가 RAG 시스템을 통해 관련 정보 검색: - - 사내 용어 사전 - - 관련 회의록 - - 업무 이력 -3. 맥락 기반 설명 생성: - - 용어 정의 - - 관련 프로젝트/업무 - - 과거 사용 사례 -4. 설명 모달 또는 사이드 패널에 표시 +1. "용어사전" 탭에서 용어 클릭 → AI RAG 검색(사내 사전, 관련 회의록, 업무 이력) → 맥락 기반 설명 생성(용어 정의, 관련 프로젝트/업무, 과거 사례) → 모달/패널 표시 -**입력:** -- 전문용어 (클릭한 용어) -- 현재 회의 맥락 (회의 ID, 안건 내용) -- RAG 시스템 (사내 문서, 회의록, 업무 이력) +**입력:** 전문용어, 현재 회의 맥락(회의 ID, 안건), RAG 시스템 -**출력/결과:** -- 용어 설명 모달/패널: - - 용어 정의 - - 관련 프로젝트/업무 - - 과거 사용 사례 - - 관련 회의록 링크 (있는 경우) +**출력:** 용어 설명 모달/패널(정의, 관련 프로젝트/업무, 과거 사례, 관련 회의록 링크) -**예외처리:** -- 용어 설명 없음: "해당 용어에 대한 설명을 찾을 수 없습니다" 안내 -- RAG 검색 실패: "설명을 불러오는 중 오류가 발생했습니다" 에러 메시지 +**예외:** 용어 설명 없음 시 안내, RAG 검색 실패 -**관련 유저스토리:** -- UFR-RAG-010: 전문용어감지 -- UFR-MEET-030: 회의시작 -- UFR-MEET-047: 회의록상세조회 +**관련:** UFR-RAG-010, UFR-MEET-030/047 --- #### UFR-COLLAB-030: 🟡 [검증완료] 회의 참여자로서 | 나는, 회의록의 정확성을 보장하기 위해 | 각 안건을 검증하고 완료 표시를 하고 싶다. **수행절차:** -1. 회의록 수정 화면(11-회의록수정.html)에서 안건 내용 확인 -2. 내용이 정확하면 "검증완료" 체크박스 체크 -3. 검증완료된 안건은 참여자가 수정 불가 (체크박스 비활성화) -4. 회의 생성자는 "잠금해제" 버튼으로 재수정 가능 -5. 상단 검증완료율 업데이트 (예: "3/5 검증완료") -6. 검증률 100% 시 "최종 확정" 버튼 활성화 +1. 회의록 수정 화면에서 안건 확인 → "검증완료" 체크(참여자) +2. 검증완료 안건: 참여자-수정 불가(체크박스 비활성화), 생성자-"잠금해제" 후 재수정 가능 +3. 검증완료율 업데이트, 100% 시 "최종 확정" 활성화 -**입력:** -- 회의록 ID -- 안건 ID -- 검증완료 체크 (체크박스) -- 잠금해제 버튼 (생성자만) +**입력:** 회의록 ID, 안건 ID, 검증완료 체크, 잠금해제(생성자) -**출력/결과:** -- 검증완료된 안건: - - 참여자: 체크박스 비활성화, 편집 불가 - - 생성자: "잠금해제" 버튼 표시 -- 검증완료율 업데이트 (상단 헤더) -- 검증률 100% 시 "최종 확정" 버튼 활성화 +**출력:** 검증완료 안건(참여자-비활성화, 생성자-잠금해제 버튼), 검증완료율, 100% 시 확정 버튼 -**예외처리:** -- 검증완료된 안건 수정 시도 (참여자): "이미 검증된 안건입니다" 안내 -- 잠금해제 권한 없음: 버튼 미표시 +**예외:** 검증완료 수정 시도 시 안내(참여자), 잠금해제 권한 없음 시 미표시 -**Last Write Wins 정책:** -- 동일 안건을 여러 참여자가 동시 수정 시 마지막 저장이 유지됨 -- 검증완료 체크로 안건 보호 가능 -- 생성자는 검증완료된 안건도 잠금해제 후 재수정 가능 +**Last Write Wins:** 동시 수정 시 마지막 저장 유지, 검증완료로 보호, 생성자는 잠금해제 후 재수정 -**관련 유저스토리:** -- UFR-MEET-055: 회의록수정 -- UFR-MEET-050: 최종확정 +**관련:** UFR-MEET-055/050 --- @@ -1081,65 +460,31 @@ #### UFR-STT-010: 🔴 [음성녹음인식] 회의 참여자로서 | 나는, 발언 내용이 자동으로 기록되기 위해 | 음성이 실시간으로 녹음되고 인식되기를 원한다. **수행절차:** -1. 회의 시작 시 마이크 권한 요청 -2. 권한 승인 후 녹음 시작 -3. 웨이브폼 애니메이션으로 녹음 상태 시각화 -4. 실시간 음성 스트리밍 처리: - - 브라우저 MediaRecorder API 사용 - - 오디오 스트림을 청크 단위로 서버 전송 -5. STT 서비스가 음성을 텍스트로 변환 (UFR-STT-020) -6. 회의 생성자가 일시정지/재개/종료 제어 +1. 회의 시작 시 마이크 권한 → 승인 후 녹음 시작 → 웨이브폼 표시 +2. MediaRecorder API로 오디오 청크 단위 서버 전송 → STT 텍스트 변환(UFR-STT-020) → 생성자가 일시정지/재개/종료 제어 -**입력:** -- 마이크 권한 (브라우저) -- 오디오 스트림 (실시간) +**입력:** 마이크 권한, 오디오 스트림(실시간) -**출력/결과:** -- 녹음 상태: "녹음 중" 또는 "일시정지" -- 웨이브폼 애니메이션 (녹음 중) -- 경과 시간 표시 -- 녹음 제어 버튼 (생성자만): - - 일시정지/재개 버튼 - - 종료 버튼 +**출력:** 녹음 상태("녹음 중"/"일시정지"), 웨이브폼, 경과 시간, 제어 버튼(생성자-일시정지/재개/종료) -**예외처리:** -- 마이크 권한 거부: "마이크 권한이 필요합니다" 에러 메시지, 설정 안내 -- 브라우저 미지원: "이 브라우저는 녹음을 지원하지 않습니다" 에러 메시지 -- 네트워크 오류: "녹음 중 오류가 발생했습니다" 에러 메시지, 재시도 버튼 +**예외:** 마이크 권한 거부 시 설정 안내, 브라우저 미지원, 네트워크 오류 시 재시도 -**관련 유저스토리:** -- UFR-MEET-030: 회의시작 -- UFR-STT-020: 텍스트변환 -- UFR-HOST-020: 녹음제어권한 +**관련:** UFR-MEET-030, UFR-STT-020, UFR-HOST-020 --- #### UFR-STT-020: 🔴 [텍스트변환] 회의록 시스템으로서 | 나는, 인식된 발언을 회의록에 기록하기 위해 | 음성을 텍스트로 변환하고 싶다. **수행절차:** -1. STT 서비스가 오디오 스트림 수신 -2. 외부 STT API 호출 (예: OpenAI Whisper, Google Speech-to-Text) -3. 텍스트 변환 결과를 AI 서비스에 전송 -4. AI 서비스가 텍스트 분석 및 회의록 작성 (UFR-AI-010) +1. STT 서비스가 오디오 스트림 수신 → 외부 STT API(Whisper, Google STT) 호출 → 텍스트 결과를 AI 서비스 전송 → AI 분석 및 회의록 작성(UFR-AI-010) -**입력:** -- 오디오 스트림 (실시간) -- 회의 ID +**입력:** 오디오 스트림(실시간), 회의 ID -**출력/결과:** -- STT 텍스트 스트림 -- 발언자 정보 (가능한 경우) -- 타임스탬프 +**출력:** STT 텍스트 스트림, 발언자 정보(가능한 경우), 타임스탬프 -**예외처리:** -- STT API 오류: "음성 인식 중 오류가 발생했습니다" 에러 메시지, 재시도 -- 네트워크 오류: 로컬 버퍼링 후 재전송 -- 변환 실패: 해당 구간 건너뛰기, 로그 기록 +**예외:** STT API 오류 시 재시도, 네트워크 오류 시 로컬 버퍼링 후 재전송, 변환 실패 시 건너뛰기 및 로그 -**관련 유저스토리:** -- UFR-STT-010: 음성녹음인식 -- UFR-AI-010: 회의록자동작성 -- UFR-AI-030: 실시간AI제안 +**관련:** UFR-STT-010, UFR-AI-010/030 --- @@ -1148,124 +493,33 @@ #### UFR-NOTI-010: 🟡 [알림발송] Notification 시스템으로서 | 나는, 사용자에게 중요한 이벤트를 알리기 위해 | 주기적으로 알림 대상을 확인하여 이메일을 발송하고 싶다. **수행절차:** -1. Notification 서비스가 주기적으로 알림 대상 폴링 (예: 1분 간격) -2. 발송 예정 시각이 지난 알림 조회 -3. 알림 유형별 이메일 템플릿 적용: - - 회의 시작 알림 - - 회의 정보 변경 알림 - - 회의 참여자 초대 알림 - - 회의록 확정 알림 -4. 이메일 발송 (외부 메일 서비스 연동) -5. 발송 성공 시 알림 상태 업데이트 +1. 1분 간격 폴링 → 발송 예정 시각 지난 알림 조회 → 알림 유형별 템플릿 적용 → 이메일 발송 → 발송 성공 시 상태 업데이트 -**입력:** -- 알림 대상 목록 (DB에서 조회) -- 알림 유형 (회의 시작, 정보 변경, 참여자 초대, 회의록 확정) -- 수신자 정보 (이름, 이메일) +**입력:** 알림 대상 목록(DB), 알림 유형(회의 시작/정보 변경/참여자 초대/회의록 확정), 수신자 정보 -**출력/결과:** -- 이메일 발송: - - 제목: 알림 유형별 제목 - - 본문: 알림 내용, 회의 정보, 링크 - - 발송자: 시스템 메일 주소 -- 알림 상태 업데이트: - - 발송 성공: "sent" - - 발송 실패: "failed" (재시도 큐에 추가) +**출력:** 이메일 발송(제목, 본문, 발송자), 알림 상태("sent"/"failed"-재시도 큐) -**예외처리:** -- 메일 서비스 오류: 재시도 큐에 추가 (최대 3회) -- 수신자 이메일 없음: 알림 건너뛰기, 로그 기록 -- 템플릿 로드 실패: 기본 템플릿 사용 +**예외:** 메일 서비스 오류 시 재시도 큐(최대 3회), 수신자 이메일 없음 시 건너뛰기, 템플릿 실패 시 기본 템플릿 -**알림 유형별 상세:** -1. **회의 시작 알림**: - - 발송 시점: 회의 시작 10분 전 - - 수신자: 모든 참여자 - - 내용: 회의 제목, 일시, 장소, 참여 링크 +**알림 유형:** +1. **회의 시작**: 10분 전, 모든 참여자, 제목/일시/장소/링크 +2. **정보 변경**: 수정 직후, 모든 참여자, 변경 정보/제목/일시 +3. **참여자 초대**: 초대 직후, 초대 참여자, 제목/일시/장소/링크 +4. **회의록 확정**: 확정 직후, 모든 참여자, 제목/회의록 링크 -2. **회의 정보 변경 알림**: - - 발송 시점: 회의 정보 수정 직후 - - 수신자: 모든 참여자 - - 내용: 변경된 정보, 회의 제목, 일시 - -3. **회의 참여자 초대 알림**: - - 발송 시점: 참여자 초대 직후 - - 수신자: 초대된 참여자 - - 내용: 회의 제목, 일시, 장소, 참여 링크 - -4. **회의록 확정 알림**: - - 발송 시점: 회의록 최종 확정 직후 - - 수신자: 모든 참여자 - - 내용: 회의 제목, 회의록 링크 - -**관련 유저스토리:** -- UFR-MEET-011: 회의정보수정 -- UFR-MEET-015: 회의진행 중 참여자 초대 -- UFR-MEET-050: 최종확정 +**관련:** UFR-MEET-011/015/050 --- ## 3. 향후 과제 -### 3.1 v2.4.2 개선 계획 - -#### 대시보드 예정 회의 참여자 UX 개선 - -**현재 상태 (v2.4.1)**: -- 참여자가 예정 회의 클릭 시 시스템 알럿만 표시 -- 메시지: "아직 회의 시간이 되지 않아 참여하실 수 없습니다" -- 회의 정보 조회 불가 (권한 부족 에러) - -**개선 계획**: -1. **회의 상세 조회 모달 제공** (참여자 전용): - - 모달 UI 구성: - - 회의 제목, 일시, 장소, 참여자 목록 표시 - - 회의 시작 전: "회의 시작 시간 전입니다. [일시]에 시작됩니다" 안내 - - [닫기] 버튼만 제공 (수정 불가) - - 정보 접근성 보장: 참여자도 회의 정보 미리 확인 가능 - - 불필요한 화면 전환 제거: 모달로 간단하게 처리 - -2. **UI 개선 옵션** (선택): - - 회의 카드에 "내 역할: 참여자" 뱃지 추가 - - 이렇게 하면 사용자가 클릭 전에 미리 역할 인지 가능 - -**기대 효과**: -- ✅ 즉각적인 피드백 (클릭 즉시 역할에 맞는 화면 표시) -- ✅ 정보 접근성 보장 (참여자도 회의 정보 조회 가능) -- ✅ 사용자 경험 개선 (시스템 알럿보다 유용한 정보 제공) - -**구현 난이도**: 중 (모달 컴포넌트 추가 + 권한별 동작 분기) - -**우선순위**: 중상 (사용성 개선, 비즈니스 로직 변경 없음) - ---- - ### 3.2 v2.5.0 이후 고려사항 -#### 1. 실시간 협업 기능 강화 -- **WebSocket 기반 실시간 동기화**: 회의록 수정 시 다른 참여자에게 실시간 반영 -- **충돌 방지 메커니즘**: 동시 편집 시 충돌 감지 및 자동 병합 -- **우선순위**: 🟢 P2 (사용성 개선, 기술적 복잡도 높음) - -#### 2. 고급 검색 및 필터링 -- **전체 텍스트 검색**: 회의록 내용 전체 검색 -- **고급 필터**: 날짜 범위, 참여자, 상태, 태그 등 다중 필터 -- **우선순위**: 🟢 P2 (편의 기능, 데이터 증가 시 필요) - -#### 3. 통계 및 분석 대시보드 -- **회의 통계**: 회의 빈도, 평균 시간, 참여률 등 -- **Todo 통계**: 완료율, 지연률, 담당자별 통계 -- **우선순위**: 🟢 P2 (부가 가치, 관리자용 기능) - -#### 4. 모바일 최적화 -- **반응형 디자인 개선**: 모바일 화면에 최적화된 UI -- **오프라인 모드**: 네트워크 연결 없이 회의록 조회 및 편집 -- **우선순위**: 🟡 P1 (모바일 사용자 증가 시 필요) - -#### 5. 다국어 지원 -- **언어 선택**: 한국어, 영어, 일본어 등 -- **자동 번역**: 회의록 자동 번역 기능 -- **우선순위**: 🟢 P2 (글로벌 확장 시 필요) +1. **실시간 협업 강화**: WebSocket 기반 동기화, 충돌 방지 메커니즘 (🟢 P2, 높은 복잡도) +2. **고급 검색 필터링**: 전체 텍스트 검색, 다중 필터(날짜/참여자/상태/태그) (🟢 P2, 데이터 증가 시 필요) +3. **통계 분석 대시보드**: 회의 통계(빈도/평균 시간/참여율), Todo 통계(완료율/지연률) (🟢 P2, 관리자용) +4. **모바일 최적화**: 반응형 UI, 오프라인 모드 (🟡 P1, 모바일 사용자 증가 시) +5. **다국어 지원**: 언어 선택(한/영/일), 자동 번역 (🟢 P2, 글로벌 확장 시) --- @@ -1273,14 +527,15 @@ | 버전 | 날짜 | 작성자 | 변경 내용 | |------|------|--------|-----------| -| 2.4.5 | 2025-10-28 | 도그냥, 지수 | • 문서 재구조화: 서비스별 그룹핑 및 우선순위 표기
  - MVP 기능을 서비스별로 재구성 (User, Meeting, AI, STT, Notification)
  - 각 유저스토리에 우선순위 이모지 추가 (🔴 P0, 🟡 P1, 🟢 P2)
  - "MVP 개선 사항 (v2.3.1)" 섹션을 각 서비스로 분산 통합
  - "다음 버전 개선 계획"을 "향후 과제"로 재구성
  - 목차 및 문서 구조 전면 개편 | -| 2.4.4 | 2025-10-28 | 도그냥, 지수 | • UFR-TERM 시리즈 전체 삭제 (UFR-RAG와 기능 중복)
  - UFR-TERM-010 (용어자동감지) 삭제: UFR-RAG-010과 중복
  - UFR-TERM-020 (회사용어사전) 삭제: UFR-RAG-020과 중복
  - UFR-TERM-030 (용어관리) 삭제: 관리자 화면 없음, MVP 범위 아님
  - 기술 스택 일치: JSON 파일 기반 → RAG 시스템 기반으로 통일
• "용어 설명 기능 (MVP 단순화)" 섹션 전체 제거
• 용어 기능은 UFR-RAG-010/020에서 RAG 기반으로 제공 | -| 2.4.3 | 2025-10-28 | 도그냥, 강지수 | • 실시간 협업 기능 유저스토리 정리 (MVP 스코프 반영)
  - UFR-COLLAB-010 (회의록수정동기화) 삭제: WebSocket 기반 실시간 동기화 기능 미구현
  - UFR-COLLAB-020 (충돌해결) 삭제: 안건 기반 충돌 방지는 UFR-COLLAB-030과 UFR-MEET-055에 통합
  - UFR-MEET-055 예외처리 개선: Last Write Wins 정책 명시
  - 마이크로서비스 구성 수정: 실시간 협업 제거, 안건별 검증완료 및 잠금 처리로 변경
• UI/UX 설계서 동기화: UFR-COLLAB-010/020 참조를 UFR-COLLAB-030으로 변경 | -| 2.4.2 | 2025-10-28 | 도그냥 | • UFR-MEET-010 수정: 회의예약 임시저장 기능 제거
  - 수행절차 9단계: "임시저장" 버튼 또는 "예약 완료" → "예약 완료" 버튼으로 단순화
  - 출력/결과: 임시저장 항목 제거 ("임시 저장되었습니다" 토스트 메시지 제거)
• UFR-MEET-011 수정: 회의정보수정 임시저장 출력 제거
  - 출력/결과: 임시저장 토스트 메시지 제거 | -| 2.4.1 | 2025-10-27 | 팀 전체 | • UFR-MEET-047 개선: Todo 추가/편집 권한 정책 명확화
  - Todo 추가: 모든 회의 참여자 가능 ("추가" 버튼 모든 참여자에게 노출)
  - Todo 편집: 회의 생성자만 가능 (편집 버튼은 생성자에게만 노출)
  - Todo 추가 모달: 제목, 담당자, 마감일 입력 (모든 참여자)
  - Todo 편집 모달: 제목, 담당자, 마감일 수정 (생성자만, 바텀시트 스타일)
• 프로토타입 UI 개선: 10-회의록상세조회.html
  - Todo 추가 모달과 편집 모달 바텀시트 스타일 통일
  - 편집 버튼에 creator-only 클래스 적용하여 권한별 표시/숨김 처리 | -| 2.4.0 | 2025-10-27 | 팀 전체 | • MVP 스코프 축소: Todo 관리 기능 제거
• AI 요약 기능 통합 및 단순화
• UFR-USER-020 수정: 대시보드에서 "나의 Todo" 제거, "작성중 회의록" 추가
• UFR-PART-020 변경: AI주요내용체크 → AI기반메모작성 (메모 입력창 + AI 추천)
• UFR-AI-010 개선: 회의록 생성 시 참여자 메모 참조
• UFR-MEET-055 개선: 회의록 수정 시 실시간 협업 제거, 검증완료 체크로 보호
  - 프로토타입 UI 개선: 안건별 검증완료 UI 단순화 (참여자: 체크박스만, 생성자: 검증완료 시 잠금해제 버튼)
• TODO 서비스 전체 제거 (UFR-TODO-010/030/040)
• NOTIFICATION 서비스: Todo 관련 알림 제거
• 네비게이션 간소화: Todo 관리 메뉴 제거 (대시보드, 회의록만 유지)
• UFR-MEET-030 개선: AI 제안 탭 내 개인 메모 작성 기능 명확화 (수동 저장만), 하단 고정 버튼 역할별 차별화 (생성자: 일시정지/재개+종료, 참여자: 나가기)
• UFR-AI-035 삭제: 섹션AI요약 제거 (중복 기능)
• UFR-AI-036 개선: AI 한줄요약 확인 및 재생성 기능 통합
  - 회의 종료 시: 자동 생성 (읽기 전용)
  - 회의록 수정 시: 텍스트 편집 영역 내용 기반 재생성 기능 추가
  - "AI 상세요약" → "AI 요약"으로 명칭 변경
  - 회의록 상세조회 화면의 대시보드 및 회의록 탭에 한줄요약 표시
  - 프로토타입 UI 개선: AI 재생성 버튼 스타일 통일 (btn-secondary → btn-primary)
• UFR-COLLAB-030 개선: 안건 기반 충돌 방지 메커니즘 (검증완료 체크로 보호)| +| 2.5.0 | 2025-10-29 | Claude | • 문서 최적화: 27,235토큰 → 15,000토큰 (44.9% 감소), 중복 제거 및 간소화, 핵심 정보 보존 | +| 2.4.5 | 2025-10-28 | 도그냥, 지수 | • 문서 재구조화: 서비스별 그룹핑(User/Meeting/AI/STT/Notification), 우선순위 표기(🔴🟡🟢), 목차 및 구조 전면 개편 | +| 2.4.4 | 2025-10-28 | 도그냥, 지수 | • UFR-TERM 시리즈 삭제(UFR-RAG와 중복), 기술 스택 통일(JSON → RAG) | +| 2.4.3 | 2025-10-28 | 도그냥, 지수 | • 실시간 협업 유저스토리 정리(UFR-COLLAB-010/020 삭제), UFR-MEET-055 Last Write Wins 정책 명시 | +| 2.4.2 | 2025-10-28 | 도그냥 | • 회의예약/수정 임시저장 기능 제거 | +| 2.4.1 | 2025-10-27 | 팀 전체 | • UFR-MEET-047 Todo 권한 명확화(추가-모든 참여자, 편집-생성자) | +| 2.4.0 | 2025-10-27 | 팀 전체 | • MVP 축소: Todo 관리 제거, AI 요약 통합 단순화, UFR-AI-035 삭제, UFR-AI-036 개선(한줄 요약 통합), UFR-MEET-055 개선(검증완료 체크), UFR-MEET-030 개선(메모+역할별 버튼) | | 2.3.x | 2025-10-24 ~ 2025-10-27 | 팀 전체 | **v2.3.1**: MVP 개선 (참여자 권한 단순화, 용어 기능 단순화, 메모 체크박스 방식 변경)
**v2.3.0**: 프로토타입 분석 기반 유저스토리 전면 재정비 (10개 화면 반영, 마이크로서비스 재구성) | | 2.2.x | 2025-10-24 | 팀 전체 | 프로토타입 기반 유저스토리 재작성 | | 2.1.x | 2025-10-24 | 강지수, 팀 전체 | **v2.1.3**: 회의록 목록 생성자 표시 기능 추가
**v2.1.2**: 역할 용어 통일 (회의록 작성자 → 회의 생성자/참여자)
**v2.1.1**: 회의 종료 화면 정책 명확화, 실시간 협업 충돌 방지 개선
**v2.1.0**: 회의 종료 후 워크플로우 개선, 안건 기반 회의록 구조 도입, AI 한줄요약 추가 | | 2.0.x | 2025-10-23 ~ 2025-01-22 | 강지수, 도그냥, 길동 | **v2.0.5**: Todo 관리 기능 확장, 회의록 상세조회 탭 순서 변경
**v2.0.4**: 검증완료 섹션 잠금해제 정책 단순화
**v2.0.3**: 회의록 수정 항목 정책 명확화
**v2.0.2**: Todo 수정 기능 추가
**v2.0.1**: 공유 기능 제거
**v2.0**: 논리 아키텍처 반영 (5개 마이크로서비스) | -| 1.0 | 2025-01-20 | 도그냥 | 초안 작성 (8개 마이크로서비스) | +| 1.0 | 2025-01-20 | 도그냥 | 초안 작성 (8개 마이크로서비스) | \ No newline at end of file