# 화상회의 화면 명세 (단계 1: 인프라 토대) > 이 문서는 **현재 구현된 화상회의 화면의 기능·구조·데이터 계약**을 정리한 것이다. > 새 UI를 직접 설계/구현할 때, 아래 "데이터 계약"과 "상태 흐름"만 그대로 연결하면 > 시각 디자인은 자유롭게 바꿔도 동작이 보장된다. > (미디어 전송은 LiveKit SDK가 담당하고, 우리는 토큰 발급 + 화면 구성만 한다.) --- ## 1. 범위 - **포함(단계 1)**: 방 입장 → LiveKit 연결 → 카메라/마이크 발행 → 참여자 영상 그리드 표시 → 나가기. 마이크/카메라 on·off. - **제외(후속 단계, 이번 UI에서 구현 안 함)** - 단계 2: 관리자(진행자)/일반 사용자 **권한 분기** (토큰 grant 차등) - 단계 3: **진행자 고해상도 큰 화면 + 참여자 썸네일**, 특정 참여자 **화면 승격**, **그리드 페이지네이션**(동시 표시 ~50명) - 단계 4: 방 목록/예약/참여 제한 - 즉 지금은 "같은 방 이름으로 들어온 사람끼리 동등하게 연결되는 기본 회의실"이다. --- ## 2. 진입 / 라우트 | 항목 | 값 | |---|---| | 라우트 | `/meeting/:room?` (room 파라미터는 선택) | | 라우트 name | `meeting` | | 인증 | `requiresAuth: true` (로그인 필요) | | 페이지 컴포넌트 | `frontend/src/pages/relay/MeetingPage.vue` | | 사이드바 네비 | `AppShell.vue` 의 "화상회의" 항목 (`/meeting`) | - `/meeting` 으로 들어오면 방 이름 미입력 상태의 로비. - `/meeting/<방이름>` 으로 들어오면 그 방 이름이 입력란에 채워진 로비(공유 링크 용도). **입장 버튼을 눌러야** 실제 연결된다(카메라 권한 타이밍 확보). - 입장 성공 시 주소창을 `/meeting/<방이름>` 으로 `replace` 한다(공유 가능 링크). --- ## 3. 화면 상태 (4가지) | 상태 | 조건 | 화면 | |---|---|---| | **로비(미연결)** | `connected === false` | 방 이름 입력 폼 | | **연결 중** | `connecting === true` | 입장 버튼이 "입장 중…" + 비활성 | | **회의실(연결됨)** | `connected === true` | 컨트롤 바 + 영상 그리드 | | **에러** | `joinError` / `errorMsg` 존재 | 해당 영역에 빨간/주황 문구 | - `joinError`: 입장 시도 단계의 오류(방 이름 형식 오류, 토큰 발급 실패 등) — 로비에 표시. - `errorMsg`: 연결 이후 미디어 단계의 오류(카메라/마이크 권한 거부 등) — 회의실에 표시. 권한 거부여도 연결 자체는 유지된다. --- ## 4. 로비 화면 (현재 구성) - 페이지 제목 `화상회의` + 안내 문구(lede) - 카드 폼: - 라벨 `* 방 이름` (필수 표기) - 힌트: "영문·숫자·하이픈(-)·밑줄(_)만 사용할 수 있습니다." - 입력란: `maxlength=64`, placeholder `예: team-standup` - 오류 문구(`joinError`) - 푸터: `입장하기` 버튼(제출 시 `onJoin`) - **방 이름 규칙**: `^[A-Za-z0-9_-]+$`, 1~64자. (백엔드 DTO와 동일하게 검증 — 한글/공백 불가) --- ## 5. 회의실 화면 (현재 구성) - **상단 바(room-bar)** - 방 이름(`roomName`) - 참여자 수(`참여자 N명` = `participants.length`) - 컨트롤 버튼 3개: - 마이크 토글 → `toggleMic()` (상태 `micEnabled`) - 카메라 토글 → `toggleCam()` (상태 `camEnabled`) - 나가기 → `onLeave()` (연결 해제 후 `/meeting` 로 이동) - **영상 그리드(grid)**: `participants` 를 순회하며 `ParticipantTile` 렌더. 첫 번째(`index === 0`)가 **본인(localParticipant)**. > 현재 컨트롤은 이모지(🎙/📹) 버튼이고 상단 우측에 있다 → 새 UI에서 하단 중앙 컨트롤 바 + 아이콘 버튼 등으로 자유롭게 재배치 가능. **연결되는 함수/상태만 동일하게 쓰면 된다.** --- ## 6. 참여자 타일 (`ParticipantTile.vue`) - **Props** - `participant: Participant` (livekit-client) — 필수 - `isLocal?: boolean` — 본인 타일 여부 - **동작** - 카메라 트랙을 `