From 999a8730ddebbbafdb016131068a2043c0f3d2cb Mon Sep 17 00:00:00 2001 From: ttipo Date: Wed, 24 Jun 2026 17:56:53 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=99=94=EC=83=81=ED=9A=8C=EC=9D=98=20?= =?UTF-8?q?UI=20=EC=A0=84=EB=A9=B4=20=EA=B0=9C=ED=8E=B8=20=EB=B0=8F=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=C2=B7=EB=A1=9C=EC=A7=81=20=EA=B2=80=ED=86=A0?= =?UTF-8?q?=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디자인 시안(프로토타입)을 실제 Vue 컴포넌트로 이식하고, 코드·로직·보안 검토에서 도출한 항목을 반영한다. UI 개편 - 컴포넌트 분리: MeetingLobby/CreateForm/Prejoin/Room/SidePanel/PeopleList/ Chat/ControlBar/ParticipantTile/QualityBars/MeetingIcon - 로비: 검색 툴바 + "새 회의 만들기" 모달(BaseModal) + 방 목록(삭제=휴지통) - 프리조인: 실제 카메라/마이크 미리보기 + 초기 on/off, 실제 프로필 아바타 - 회의실: 축소 스테이지 + 썸네일 그리드(한 페이지 50명) + 페이지네이션, 말하는 사람 하이라이트/연결 품질 막대 - 채팅: 데이터 채널 실제 구현(Shift+Enter 줄바꿈, 실제 프로필 아바타) 디자인 시스템 정합 - rem 단위/토큰 정렬, 공용 .btn/.form-*/.search/BaseModal/UserAvatar 재사용 - 회의실 다크 캔버스 토큰(--d-*, --d-red/green/amber/accent-soft) 추가 화질/성능 - 스테이지=고화질, 나머지=저화질 구독(setVideoQuality) - 타일 backdrop-filter 제거 + 발화/품질 이벤트 전체 리렌더 제거(버벅임 완화) 코드·로직·보안 검토 반영 - 채팅 표시 이름은 서명 토큰의 name/identity 만 신뢰(클라이언트 name 사칭 차단) - promote 는 보낸 사람 metadata role=host 일 때만 적용(인가) - 원격 오디오를 룸 레벨에서 전원 재생(페이지 밖 참여자 무음 수정) - 타일 언마운트 시 트랙 detach(누수 방지) - 마이크/카메라 토글 실패 시 상태 롤백 - 입장 토큰 TTL 1h → 12h(장시간 회의 재연결 안정성) - 채팅 길이 상한(MAX_CHAT_LENGTH) - 토큰 metadata 에 avatarUrl 포함(참여자/채팅 아바타) 기타 - 임시 명세/디자인 참고 파일 제거 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/modules/meeting/meeting.service.ts | 6 +- frontend/src/assets/styles/relay.css | 15 + .../src/components/meeting/MeetingChat.vue | 257 ++++ .../components/meeting/MeetingControlBar.vue | 257 ++++ .../components/meeting/MeetingCreateForm.vue | 443 +++++++ .../src/components/meeting/MeetingIcon.vue | 177 +++ .../src/components/meeting/MeetingLobby.vue | 391 ++++++ .../components/meeting/MeetingPeopleList.vue | 291 +++++ .../src/components/meeting/MeetingPrejoin.vue | 405 +++++++ .../src/components/meeting/MeetingRoom.vue | 493 ++++++++ .../components/meeting/MeetingSidePanel.vue | 145 +++ .../components/meeting/ParticipantTile.vue | 286 +++-- .../src/components/meeting/QualityBars.vue | 79 ++ frontend/src/composables/useLiveKitRoom.ts | 221 +++- frontend/src/pages/relay/MeetingPage.vue | 1066 ++++------------- frontend/src/shared/utils/avatar.ts | 29 + frontend/src/types/meeting.ts | 14 + 화상회의_화면명세.md | 207 ---- 18 files changed, 3618 insertions(+), 1164 deletions(-) create mode 100644 frontend/src/components/meeting/MeetingChat.vue create mode 100644 frontend/src/components/meeting/MeetingControlBar.vue create mode 100644 frontend/src/components/meeting/MeetingCreateForm.vue create mode 100644 frontend/src/components/meeting/MeetingIcon.vue create mode 100644 frontend/src/components/meeting/MeetingLobby.vue create mode 100644 frontend/src/components/meeting/MeetingPeopleList.vue create mode 100644 frontend/src/components/meeting/MeetingPrejoin.vue create mode 100644 frontend/src/components/meeting/MeetingRoom.vue create mode 100644 frontend/src/components/meeting/MeetingSidePanel.vue create mode 100644 frontend/src/components/meeting/QualityBars.vue create mode 100644 frontend/src/shared/utils/avatar.ts delete mode 100644 화상회의_화면명세.md diff --git a/backend/src/modules/meeting/meeting.service.ts b/backend/src/modules/meeting/meeting.service.ts index c7d53f7..1e0e465 100644 --- a/backend/src/modules/meeting/meeting.service.ts +++ b/backend/src/modules/meeting/meeting.service.ts @@ -81,8 +81,10 @@ export class MeetingService { const at = new AccessToken(this.apiKey, this.apiSecret, { identity: user.id, name: user.name, - ttl: '1h', - metadata: JSON.stringify({ role }), + // 장시간 회의 중 네트워크 재연결 시 토큰 만료로 재입장이 실패하지 않도록 넉넉히(12h). + ttl: '12h', + // role 은 진행자 식별용, avatarUrl 은 참여자/채팅 아바타 표시용 + metadata: JSON.stringify({ role, avatarUrl: user.avatarUrl }), }); at.addGrant({ roomJoin: true, diff --git a/frontend/src/assets/styles/relay.css b/frontend/src/assets/styles/relay.css index 1b45153..9741477 100644 --- a/frontend/src/assets/styles/relay.css +++ b/frontend/src/assets/styles/relay.css @@ -52,6 +52,21 @@ --shadow-sm: 0 1px 2px rgba(20, 24, 33, 0.05); --shadow-md: 0 4px 16px rgba(20, 24, 33, 0.1), 0 1px 3px rgba(20, 24, 33, 0.06); --shadow-pop: 0 8px 28px rgba(20, 24, 33, 0.16), 0 2px 6px rgba(20, 24, 33, 0.08); + + /* 다크 캔버스(화상회의 회의실/프리조인 전용) */ + --d-bg: #0e1014; + --d-panel: #16191f; + --d-panel-2: #1b1f27; + --d-border: #2a2f39; + --d-text: #eceef2; + --d-text-2: #aab2bf; + --d-text-3: #717a88; + --tile: #1b1d23; + /* 다크 위 상태색(라이트 토큰을 다크에 쓰면 탁해져 밝은 변형을 별도 정의) */ + --d-red: #ff7a8a; + --d-green: #46d18a; + --d-amber: #f0c478; + --d-accent-soft: #c7c2ff; } /* ============================================================ diff --git a/frontend/src/components/meeting/MeetingChat.vue b/frontend/src/components/meeting/MeetingChat.vue new file mode 100644 index 0000000..e3b020b --- /dev/null +++ b/frontend/src/components/meeting/MeetingChat.vue @@ -0,0 +1,257 @@ + + +