[PonsLink] 더 큰 방을 꿈꾸자 PonsCast가 먼저 떠올랐다
영상 회의만 붙잡고 있으면 PonsLink는 작은 방에서 멈춘다. 더 큰 방을 상상하면 모든 사람이 카메라를 켜는 구조보다 말, 듣기, 방송, 다시 재생하는 흐름이 먼저 필요해진다. 이 판단은 ponslink-room-frontend/src/components/media/PonsCastReceiverViewer.tsx와 ponslink-room-frontend/src/hooks/usePonsCastReceiver.test.tsx를 함께 볼 때 더 분명해진다. 화면에서 보이는 기능은 결과이고, 실제 제품성은 그 기능이 열리는 조건과 실패했을 때 돌아갈 길에 있다.

PonsCast가 필요해진 지점
작은 방에서는 mesh가 이해하기 쉽다. 서로가 서로에게 연결되고, 문제도 비교적 눈에 보인다. 하지만 큰 방에서는 누가 active publisher인지가 비용과 품질을 좌우한다. 말하지 않는 사람에게까지 같은 미디어 권한을 주면 네트워크는 금방 무거워진다. 오디오 피벗은 영상 기능을 포기했다는 뜻이 아니었다. 방의 크기가 커질수록 영상이 항상 중심일 필요는 없다는 판단이었다.
발표자와 청취자, 다시 듣는 사람의 역할을 나누면 같은 WebRTC 기반이라도 훨씬 안정적인 제품 흐름을 만들 수 있다. 소규모 상담에서는 영상이 자연스럽다. 하지만 커뮤니티, 세미나, 오디오 스테이지, 녹화 기반 공유로 가면 모든 참가자가 동일한 media peer가 되는 구조는 부담스럽다. 카메라 수, 업로드 대역폭, 모바일 배터리, 발언 순서가 동시에 문제가 된다.
그래서 기능 소개가 아니라 그때 내가 어떤 기준을 세우지 못했고, 어떤 실패를 보고 나서 경계를 다시 잡았는지를 따라간다. PonsLink는 회의 앱을 흉내 낸 프로젝트가 아니라 요청에서 방, 방에서 기록으로 이어지는 흐름을 제품으로 만들려는 시도였다. PonsCast는 이 부담을 줄이는 방향을 보여 줬다. 실시간 발화는 방에서 처리하되, 흐름을 받아 다시 보거나 들을 수 있는 레이어를 만들면 모든 사람이 같은 시간에 같은 품질로 붙어 있을 필요가 줄어든다.
이것은 기능 추가라기보다 방의 시간 구조를 바꾸는 일이다.

그전에 흐름을 어떻게 봤나
더 큰 방을 꿈꾸자 PonsCast가 먼저 떠올랐다에서 먼저 확인한 파일은 ponslink-room-frontend/src/components/media/PonsCastReceiverViewer.tsx이다. 이 근거는 글의 출발점이 추상적인 제품 감상이 아니라 실제 화면과 상태를 가진 코드였음을 보여 준다. 화면 컴포넌트가 어떤 이름으로 나뉘어 있는지 따라가면 사용자가 보는 흐름과 운영자가 책임지는 흐름이 어디서 갈라지는지 보인다. 그 갈라짐을 문장으로 남기지 않으면 글은 다시 기능 소개로 돌아간다.
mediaPolicy.ts의 active publisher 제한은 이 피벗을 숫자로 표현한다. 참가자 수가 늘어도 발화자 수를 제한하면 mesh의 부담을 줄일 수 있다. 반대로 모두에게 카메라와 마이크 권한을 열면 TURN relay 비율이 조금만 올라가도 비용과 품질 문제가 함께 온다. 그래서 큰 방을 꿈꾼다는 말은 더 많은 사람을 허용한다는 뜻이 아니라 역할을 더 분명히 나눈다는 뜻이었다. 처음에는 WebRTC room을 조금 키우면 된다고 생각했다.
mediaPolicy.ts에도 small meeting, webinar, audio stage 같은 profile을 둘 수 있다. 하지만 profile 이름만 늘린다고 사용자 경험이 달라지지는 않았다. 이 선택은 빠르게 확인하기 좋았다. 사용자는 들어오고, 장치는 켜지고, 메시지는 오간다. 하지만 빠른 확인이 곧 운영 가능한 구조라는 뜻은 아니었다. 권한이 화면 안에 섞이면 나중에 기능을 줄이기도 어렵고, 문제가 생겼을 때 어디를 막아야 하는지도 흐려진다.
usePonsCastReceiver 테스트는 수신자가 안정적으로 흐름을 따라가야 한다는 요구를 보여 준다. 말하는 사람의 연결이 흔들릴 수 있고, 듣는 사람은 모바일 네트워크일 수 있으며, 어떤 사람은 나중에 다시 들어올 수 있다. 큰 방에서는 실시간 연결 그 자체보다 끊겼을 때 얼마나 자연스럽게 회복되는지가 더 중요했다. 이 기준은 작은 영상방을 만들 때보다 훨씬 엄격했다.
한계는 피어 수보다 역할 구분이었다. 발표자, 청취자, 질문자, 다시 듣는 사람은 같은 미디어 권한을 가져서는 안 된다. P2P mesh는 작은 방에서 단순하지만, 큰 방에서는 active publisher 수와 TURN relay 비용이 곧 운영 비용으로 돌아온다. 이 부분은 실제로 실패와 trade-off가 함께 있는 지점이었다. 기능을 열어 두면 데모는 풍성해지지만, 사용자에게 필요한 설명은 줄어들지 않는다.
반대로 권한을 좁게 잡으면 초반 경험은 답답해질 수 있지만 운영자는 사고 범위를 예측할 수 있다.

오디오 피벗이 선명해진 순간
active publisher 제한과 TURN 비용을 운영 정책으로 보는 다이어그램. 이후 PonsLink를 다시 본다면 영상 회의 제품으로만 설명하지 않을 것이다. 작은 방에서는 얼굴이 중요하지만, 큰 방에서는 말의 순서, 듣는 사람의 안정성, 다시 이어 듣는 흐름이 더 중요해진다. PonsCast는 그래서 부가 기능이 아니라 제품이 커질 때 필요한 두 번째 축이었다. *로컬 frontend의 PonsCast 기능 이미지를 본문 자료로 재가공했다.
운영자는 audio-stage profile에서 누가 발화할 수 있는지, 몇 명까지 활성 오디오 publisher를 허용할지, relay-only 검증이 필요한 네트워크인지 결정해야 한다. TURN credential은 짧게 발급되고, 브라우저는 받은 ICE server 이상을 알 필요가 없다. 사용자는 이 복잡도를 몰라도 된다. 대신 제품은 사용자가 보지 않는 곳에서 무엇을 허용하고 무엇을 미룰지 결정해야 한다. 그 결정을 숨기면 당장은 매끄러워 보여도 장애나 결제 지연, 네트워크 실패가 왔을 때 설명할 말이 없어진다.
PonsCastReceiverViewer.tsx를 보면서 깨달은 것은 방송형 흐름이 회의형 흐름과 다르다는 점이었다. 회의에서는 모두가 같은 방에 앉아 말할 수 있기를 기대한다. 방송이나 오디오 스테이지에서는 듣는 사람과 말하는 사람의 권한이 다르다. 이 차이를 무시하고 모두를 같은 peer로 만들면 UI는 공평해 보여도 네트워크와 운영 비용은 공평하지 않다. 마지막으로 ponslink-api-infra/src/turn/turnCredentials.ts를 함께 읽으면 다음 작업의 기준이 보인다.
PonsLink의 각 글은 독립된 기능 홍보가 아니라 앞뒤 글과 이어지는 판단 기록이어야 한다. 그래서 내부 링크를 두 개씩 남겼고, 이미지도 cover가 아니라 본문 근거로 다시 만들었다. 글 하나를 읽고 끝나는 것이 아니라 독자가 다음 방, 다음 권한, 다음 운영 문제로 넘어갈 수 있게 하는 것이 이번 확장의 목적이다.
경계 다시 그리기
그래서 피벗의 중심은 큰 영상방이 아니라 오디오와 PonsCast였다. 실시간 방은 발화와 반응을 담당하고, PonsCast는 흐름을 받아 다시 재생하거나 공유할 수 있는 레이어가 된다. README의 media policy처럼 topology와 active publisher 제한을 먼저 세워야 한다. 이때부터 PonsLink의 중심은 단순한 room component가 아니라 상태와 권한의 연결이 되었다. ponslink-api-infra/src/providers/mediaPolicy.ts와 ponslink-api-infra/src/turn/turnCredentials.ts를 보면 이 판단이 프론트엔드 취향이 아니라 API/BFF 경계와 맞물린 결정이라는 점이 보인다.
turnCredentials.ts는 사용자가 보지 않는 안전장치다. 제한된 시간의 credential을 주고, 필요한 경우 relay-only 검증으로 문제를 좁힌다. 사용자는 ICE 후보나 relay 정책을 몰라도 되지만, 운영자는 어떤 네트워크에서 연결이 실패하는지 알아야 한다. 오디오 피벗은 기능 방향이면서 동시에 관측 방향이었다. 큰 방은 더 많은 로그와 더 조심스러운 credential 정책을 요구했다. TURN credential과 relay 정책은 이 선택의 운영 버전이다.
네트워크가 나쁜 사용자를 위해 relay를 준비해야 하지만, 모든 트래픽을 relay로 보내면 비용이 커진다. 그래서 profile, publisher cap, relay-only 검증 같은 운영 스위치가 필요했다. 이어 읽으면 좋은 글은 [과 [이다. 앞 글은 왜 이 문제가 생겼는지 보여 주고, 다음 글은 같은 기준이 다른 기능이나 운영 경계로 어떻게 넘어갔는지 보여 준다.
구현과 운영에 남긴 조건
*영상 중심 방에서 audio stage와 PonsCast 흐름으로 나뉘는 구조. 지금 보면 PonsCast는 새 기능 이름이라기보다 제품이 더 큰 방을 견디기 위해 찾은 방향이었다. 모두를 같은 화면에 세우기보다 역할과 흐름을 나누는 편이 낫다. 이 선택은 화려한 데모보다 오래 켜지는 방을 위한 판단이었다. 다음에 같은 문제를 다시 푼다면 먼저 기능 목록을 쓰지 않고, 방의 목적과 닫혀야 하는 실패 경로를 표로 만들 것이다.
기능은 그 뒤에 붙여도 늦지 않다. 이 글의 결론은 더 큰 방을 만들려면 먼저 더 작은 권한을 설계해야 한다는 것이다. 모두에게 같은 권한을 주는 방은 공정해 보이지만 오래 버티기 어렵다. 역할을 나누고 흐름을 나눌 때 PonsLink는 영상 회의 앱을 넘어 방송형 협업 제품으로 갈 수 있었다. 운영 관점에서는 ponslink-api-infra/src/providers/mediaPolicy.ts가 글의 방어선이다. 사용자는 방을 하나의 경험으로 보지만 시스템은 요청, 세션, 미디어, 파일, 결제, 기록처럼 여러 책임으로 나뉜다.
이 책임을 나눠 적으면 글은 조금 덜 매끈해지지만, 실패했을 때 어디서 멈춰야 하는지 설명할 수 있다. 이번 배치에서 모든 글에 실패나 한계를 넣은 것도 이 때문이다. 작은 방에서는 mesh가 이해하기 쉽다. 서로가 서로에게 연결되고, 문제도 비교적 눈에 보인다. 하지만 큰 방에서는 누가 active publisher인지가 비용과 품질을 좌우한다. 말하지 않는 사람에게까지 같은 미디어 권한을 주면 네트워크는 금방 무거워진다.
'[PonsLink 더 큰 방을 꿈꾸자 PonsCast가 먼저 떠올랐다'을 관통하는 질문은 이 섹션에서도 같았고, 답만 더 구체적이 됐다.
무엇으로 검증했나
오디오 피벗은 영상 기능을 포기했다는 뜻이 아니었다. 방의 크기가 커질수록 영상이 항상 중심일 필요는 없다는 판단이었다. 발표자와 청취자, 다시 듣는 사람의 역할을 나누면 같은 WebRTC 기반이라도 훨씬 안정적인 제품 흐름을 만들 수 있다. 소규모 상담에서는 영상이 자연스럽다. 하지만 커뮤니티, 세미나, 오디오 스테이지, 녹화 기반 공유로 가면 모든 참가자가 동일한 media peer가 되는 구조는 부담스럽다.
카메라 수, 업로드 대역폭, 모바일 배터리, 발언 순서가 동시에 문제가 된다. 그래서 기능 소개가 아니라 그때 내가 어떤 기준을 세우지 못했고, 어떤 실패를 보고 나서 경계를 다시 잡았는지를 따라간다. PonsLink는 회의 앱을 흉내 낸 프로젝트가 아니라 요청에서 방, 방에서 기록으로 이어지는 흐름을 제품으로 만들려는 시도였다. PonsCast는 이 부담을 줄이는 방향을 보여 줬다.
실시간 발화는 방에서 처리하되, 흐름을 받아 다시 보거나 들을 수 있는 레이어를 만들면 모든 사람이 같은 시간에 같은 품질로 붙어 있을 필요가 줄어든다. 이것은 기능 추가라기보다 방의 시간 구조를 바꾸는 일이다. 더 큰 방을 꿈꾸자 PonsCast가 먼저 떠올랐다에서 먼저 확인한 파일은 ponslink-room-frontend/src/components/media/PonsCastReceiverViewer.tsx이다. 이 근거는 글의 출발점이 추상적인 제품 감상이 아니라 실제 화면과 상태를 가진 코드였음을 보여 준다.
화면 컴포넌트가 어떤 이름으로 나뉘어 있는지 따라가면 사용자가 보는 흐름과 운영자가 책임지는 흐름이 어디서 갈라지는지 보인다. 그 갈라짐을 문장으로 남기지 않으면 글은 다시 기능 소개로 돌아간다. mediaPolicy.ts의 active publisher 제한은 이 피벗을 숫자로 표현한다. 참가자 수가 늘어도 발화자 수를 제한하면 mesh의 부담을 줄일 수 있다. 반대로 모두에게 카메라와 마이크 권한을 열면 TURN relay 비율이 조금만 올라가도 비용과 품질 문제가 함께 온다.
그래서 큰 방을 꿈꾼다는 말은 더 많은 사람을 허용한다는 뜻이 아니라 역할을 더 분명히 나눈다는 뜻이었다. 처음에는 WebRTC room을 조금 키우면 된다고 생각했다. mediaPolicy.ts에도 small meeting, webinar, audio stage 같은 profile을 둘 수 있다. 하지만 profile 이름만 늘린다고 사용자 경험이 달라지지는 않았다. 이 선택은 빠르게 확인하기 좋았다. 사용자는 들어오고, 장치는 켜지고, 메시지는 오간다. 하지만 빠른 확인이 곧 운영 가능한 구조라는 뜻은 아니었다.
권한이 화면 안에 섞이면 나중에 기능을 줄이기도 어렵고, 문제가 생겼을 때 어디를 막아야 하는지도 흐려진다.
마치며
usePonsCastReceiver 테스트는 수신자가 안정적으로 흐름을 따라가야 한다는 요구를 보여 준다. 말하는 사람의 연결이 흔들릴 수 있고, 듣는 사람은 모바일 네트워크일 수 있으며, 어떤 사람은 나중에 다시 들어올 수 있다. 큰 방에서는 실시간 연결 그 자체보다 끊겼을 때 얼마나 자연스럽게 회복되는지가 더 중요했다. 이 기준은 작은 영상방을 만들 때보다 훨씬 엄격했다.
한계는 피어 수보다 역할 구분이었다. 발표자, 청취자, 질문자, 다시 듣는 사람은 같은 미디어 권한을 가져서는 안 된다. P2P mesh는 작은 방에서 단순하지만, 큰 방에서는 active publisher 수와 TURN relay 비용이 곧 운영 비용으로 돌아온다. 이 부분은 실제로 실패와 trade-off가 함께 있는 지점이었다. 기능을 열어 두면 데모는 풍성해지지만, 사용자에게 필요한 설명은 줄어들지 않는다.
반대로 권한을 좁게 잡으면 초반 경험은 답답해질 수 있지만 운영자는 사고 범위를 예측할 수 있다. *active publisher 제한과 TURN 비용을 운영 정책으로 보는 다이어그램. 이후 PonsLink를 다시 본다면 영상 회의 제품으로만 설명하지 않을 것이다. 작은 방에서는 얼굴이 중요하지만, 큰 방에서는 말의 순서, 듣는 사람의 안정성, 다시 이어 듣는 흐름이 더 중요해진다.
PonsCast는 그래서 부가 기능이 아니라 제품이 커질 때 필요한 두 번째 축이었다.