[PonsLink] 나는 먼저 방을 만들었다, 제품 설명은 그다음이었다
PonsLink 초반의 가장 큰 실수이자 가장 빠른 학습은, 방을 먼저 만든 일이었다.
방을 만들면 제품 설명은 나중에 따라올 줄 알았다. 영상이 되고, 채팅이 되고, 파일을 주고받고, 화이트보드까지 붙으면 사람들이 자연스럽게 이해할 거라고 생각했다. 기능이 쌓이면 제품이 된다고 본 셈이다.
실제로는 반대였다. 누가 왜 들어오는지, 어떤 요청이 먼저 있었는지, 돈을 받는다면 무엇에 대해 받는지, 결제 후 입장 권한이 어떻게 바뀌는지가 더 중요했다. 방은 보였는데 제품 설명은 계속 비었다.

방을 먼저 만들면 설명이 따라온다는 착각
처음 화면은 그럴듯했다. 로비가 있고, 카메라 preview가 있고, 입장 버튼이 있고, 방 안에는 참가자 카드와 채팅개발자 입장에서는 성취감이 빨랐다. 일단 들어가서 말할 수 있는 곳이 생겼기 때문이다.
문제는 그다음 질문에서 터졌다.
- 이 방에 왜 들어와도 되는가
- 지금 들어와도 되는 시점인가
- 들어오기 전에 무엇을 합의했는가
- 나간 뒤에는 무엇이 남는가
방 UI는 이 질문에 답하지 않는다. 마이크와 레이아웃은 보여 주지만, 요청·승인·결제·기록의 언어는 방 밖에 있다. 방을 제품의 입구로 두면, 사용자는 기능 목록을 보고도 이 제품이 무엇을 하는지 반복해서 묻게 된다.

결제·승인·입장이 한 덩어리로 보이던 순간
운영 사건이 들어오면서 착각이 깨졌다. 결제 성공은 방에 들어가도 된다는 뜻일까. 승인된 요청은 세션이 시작됐다는 뜻일까. 예약 시간이 지났다면 링크는 여전히 유효할까. 운영자가 요청을 거절하면 이미 나눠 준 링크는 어떻게 될까.
겉으로는 비슷한 질문처럼 들린다. 실제로는 다른 사건이다.
| 사건 | 의미 | 방이 바로 열리면 생기는 일 |
|---|---|---|
| 결제 성공 | 돈의 이동 | 권한 없는 입장, 환불/재시도 혼란 |
| 요청 승인 | host의 수락 | 일정·용건 없는 만남 |
| 세션 권한 발급 | 지금 들어갈 수 있음 | 입장 가능 시점의 기준 |
| 방 입장 | 실시간 runtime 시작 | 앞 단계 실패를 연결 문제로 오해 |
결제, 권한, 세션 입장을 하나로 묶으면 구현은 빠르다. 대신 나중에 설명할 수 없는 상태가 남는다. 사용자는 돈은 냈는데 왜 못 들어가나와 들어갔는데 왜 상대가 없나를 같은 화면에서 만나게 된다. 그 순간 방은 제품이 아니라 사고 현장이 된다.

방 언어와 제품 언어가 갈라진 지점
방 안의 언어는 참가자, 마이크, 파일, 메시지다. 방 밖의 언어는 요청자, host, 가격, 승인, 예약, 기록이다. 이 둘을 연결하지 못하면 제품 장르가 중간에 바뀐다.
사용자는 요청을 보냈는데 갑자기 회의방 설정 화면을 본다. host는 상담 준비 중인데 게스트는 이미 빈 방에서 장치를 켠다. 기록 담당자는 통화가 끝났다는 사실만 알고, 어떤 요청으로 만났는지는 모른다. 같은 제품 안에서 말이 안 통한다.
작은 실시간 제품일수록 이 섞임이 더 위험하다. 화면에는 버튼 하나와 링크 하나만 있어도, 내부에는 권한·연결·기록·복구·비용이 동시에 움직인다. 기능 이름을 늘리기 전에 경계를 나눠야 하는 이유다. 무엇을 브라우저에 맡길지, 무엇을 BFF에 남길지, 무엇을 사용자가 문장으로 이해해야 하는지를 적지 않으면, 방은 계속 멋진 데모로만 남는다.
방을 제품의 중심에서 runtime으로 옮기다
다시 잡은 순서는 단순하다.
- 요청이 남는다
- host가 수락하거나 일정을 고른다
- 세션 권한이 생긴다
- 그제야 방이 열린다
- 종료 후 기록이 요청에 다시 붙는다
이 구조에서 방이 사라지는 것은 아니다. 방의 자리가 정확해질 뿐이다. 방은 제품의 얼굴일 수 있지만, 제품의 전부는 아니다. 검증된 요청이 실시간으로 실행되는 runtime이다.
기능 패널도 같은 원칙으로 본다. 파일 업로드는 저장 경로의 규칙을 따르고, speech/translation 같은 기능은 backend-safe endpoint 뒤에서만 켜진다. provider secret은 브라우저에 두지 않는다. 방에서 할 수 있는가보다, 이 행동이 어떤 권한과 기록에 붙는가를 먼저 묻는다.
구현에서 남긴 불변조건
이후 구현과 리뷰에서 지키려 한 조건은 이렇다.
- 요청 없는 빈 방을 기본 경로로 두지 않는다
- 결제 성공과 세션 입장을 같은 이벤트로 취급하지 않는다
- 방 안 상태 이름과 사용자 문장을 분리한다
- 기록이 없는 종료를 정상 완료처럼 포장하지 않는다
- 예외 입장 경로는 짧게 남기되, 기본 경로를 덮어쓰지 않는다
특히 기록이 중요했다. 방을 먼저 만들면 종료 후 기록은 부가 기능처럼 붙는다. 유료 상담이나 문서 검토에서는 기록이 신뢰의 일부다. 누가 언제 들어왔고, 어떤 요청으로 만났고, 다음에 무엇을 해야 하는지가 요청 객체에 다시 붙어야 한다. 방이 휘발성인 것은 괜찮다. 요청까지 휘발되면 안 된다.
마치며
지금 다시 보면 첫 질문은 이것이었다. 방이 먼저인가, 제품 설명이 먼저인가.
나는 방을 먼저 만들었고, 그 선택은 빠른 데모를 줬지만 느린 설명을 남겼다. 연결 기술은 문을 연다. 그 문 앞에 어떤 용건과 권한과 기록을 세울지는 방이 아니라 제품이 정해야 한다.
다음에 같은 문제를 본다면, 방 UI 스케치보다 요청-권한-입장-기록 표를 먼저 쓰겠다. 그 표가 비어 있으면 실시간 기능은 아무리 화려해도 공중에 뜬 문이다. 방을 잘 만드는 일과 제품을 설명 가능하게 만드는 일은 같은 작업이 아니다.