Background
기존의 수기 명단 관리, 계좌 송금, 현장 혼잡 등 공연 운영 과정의 비효율을 개선하기 위해 시작한 프로젝트입니다. 기존에 공연 주최측은 입금을 받고 입장 처리하기 전 입금자명과 관객을 일일히 비교해야 하는 번거로움이 있었습니다. 현장이 혼잡하면 입장까지 더 오랜 시간이 소요되기도 합니다. Uket은 공연 주최자가 공연 정보를 등록하면 관람객이 온라인으로 티켓을 구매하고, 공연 당일에는 QR 코드로 입장할 수 있는 공연 사전 티켓팅 플랫폼입니다. 입금 확인은 및 승인은 공연 주최측에 제공되는 어드민 플랫폼을 사용하여 수동 검사를 줄입니다. 시간대별 티켓팅, QR 기반 입장, 카카오 송금 연동, 알림톡 발송 기능을 지원합니다. 서울 소재 대학 동아리 공연에 서비스를 운영하며 약 100명의 관람객이 티켓 구매부터 입장까지 전 과정을 문제없이 진행했고, 사용자와 주최자의 피드백도 매우 긍정적이었습니다.
Contributions
OpenGraph 메타데이터 적용을 통한 SNS 공유 미리보기 품질 개선
문제 배경
공연 서비스는 특성상 SNS를 통한 공연 정보 공유가 활발해, 링크 미리보기 품질이 유입과 전환에 직접적인 영향을 준다고 판단했습니다. 그러나 기존 Vite 기반 SPA 구조에서는 초기 HTML에 공연별 OpenGraph 메타데이터가 포함되지 않아 SNS 크롤러가 공연 제목, 설명, 이미지 정보를 읽지 못했습니다. 그 결과 공유 미리보기에 공연 정보가 정상적으로 노출되지 않았습니다.
접근 방식 1
먼저 react-helmet-async를 적용해 클라이언트에서 메타 태그를 동적으로 변경하는 방식을 시도했습니다. 하지만 브라우저 렌더링 이후에 메타데이터가 반영되기 때문에, 초기 HTML만 읽는 SNS 크롤러 환경에서는 공연별 메타데이터를 안정적으로 제공하기 어려웠습니다.
접근 방식 2
다음으로 Puppeteer와 prerender 방식을 도입해 공연 상세 페이지를 사전 렌더링하고 페이지별 HTML을 생성했습니다. 동적 메타데이터를 포함한 HTML 생성에는 성공했지만, 배포 환경에서 Chromium 실행 문제가 반복되어 운영 환경에 안정적으로 적용하기 어려웠습니다.
접근 방식 3
최종적으로 기존 Vite 기반 SPA 구조를 Next.js로 마이그레이션했습니다. 서버 사이드 렌더링 환경으로 전환한 뒤 Next.js의 Metadata API를 활용해 공연 상세 페이지별 메타데이터를 서버 응답 시점에 포함했습니다. 이를 통해 SNS 크롤러가 초기 HTML에서 공연 정보를 직접 읽을 수 있는 구조를 만들었습니다.
성과
배포 환경에서도 공연 상세 페이지의 SNS 공유 미리보기가 안정적으로 노출되도록 개선했습니다. 또한 Next.js 도입과 함께 렌더링 구조를 최적화해 초기 JS 번들을 675KB에서 140KB로 줄였고, FCP를 4.1초에서 1.1초로 개선했으며, Lighthouse Performance 점수도 약 20% 향상시켰습니다.
에러 처리 및 데이터 관리 구조 중앙화로 유지보수성 개선
React Query의 쿼리 키를 문자열로 직접 관리하면서 오타와 네이밍 불일치가 발생하기 쉬웠고, 갱신·무효화 로직의 일관성도 보장하기 어려웠습니다. 또한 토스트와 에러 바운더리로 나뉜 에러 처리 로직이 컴포넌트마다 분산되어 정책 변경 시 여러 파일을 수정해야 했습니다.
에러 처리와 데이터 관리 책임을 공통 계층으로 모았습니다. Axios 인터셉터와 커스텀 에러 객체로 네트워크 에러를 표준화하고, Query Key Factory를 도입해 도메인별 쿼리 키를 함수 형태로 관리했습니다.
그 결과 에러 정책 변경 시 수정 범위를 1~2개 파일 수준으로 줄였고, 쿼리 관련 파일 수를 약 40% 감소시켜 에러 처리와 캐시 관리의 일관성을 높였습니다.
RSC 기반 prefetch를 활용해 초기 렌더링 및 요청 워터폴 개선
기존 클라이언트 중심 useQuery 패턴은 페이지 진입 이후 브라우저에서 데이터를 요청해 초기 화면에 로딩 상태를 먼저 노출했습니다. 또한 컴포넌트별 loading/error 분기가 반복되고, 화면 구성에 필요한 요청이 클라이언트 마운트 이후 시작되어 요청 워터폴이 발생하기 쉬웠습니다.
RSC를 활용해 페이지 단에서 데이터를 선조회하고, HydrationBoundary로 쿼리 캐시를 클라이언트에 전달한 뒤 RCC에서는 useSuspenseQuery로 hydrate된 데이터를 바로 읽도록 전환했습니다.
초기 데이터 요청 시점을 서버 렌더링 단계로 앞당겨 첫 화면 로딩 깜빡임과 요청 워터폴을 줄였고, loading/error 분기와 중복 로직도 함께 줄였습니다.
공연 정보 등록을 위한 리치 텍스트 에디터 도입
공연 등록 화면에서는 운영자가 정보를 빠르게 입력하면서도 사용자가 내용을 쉽게 읽을 수 있어야 했습니다. 기존 textarea는 입력은 단순했지만, 실제 사용자 화면에서는 내용이 줄글처럼 노출되어 주의사항과 상세 안내의 구조가 잘 드러나지 않았습니다.
처음에는 textarea에 bullet 자동 삽입, Enter/Backspace 처리, 붙여넣기 변환, 들여쓰기 유지 로직을 직접 구현했습니다. 하지만 입력 패턴이 다양해질수록 예외 처리가 늘어나 결과가 일관되지 않았습니다. 그래서 목록과 서식을 안정적으로 다룰 수 있는 리치 텍스트 에디터로 전환했습니다.
운영자는 메뉴바와 slash command를 통해 굵게, 밑줄, 리스트 등 서식을 직관적으로 작성할 수 있게 되었고, 공연 상세 정보와 주의사항을 더 구조적으로 전달할 수 있게 되었습니다.
가설 기반의 사용성 개선
서비스 출시 전 실제 사용자 피드백이 없었기 때문에, 사용자 관점에서 서비스를 반복적으로 사용하며 불편이 발생할 수 있는 지점을 찾고 가설로 정의했습니다.
어드민 대시보드 개선
테이블 상태를 쿼리 스트링과 동기화해 페이지, 필터, 정렬 조건이 URL로 유지되도록 재설계했습니다. 등록·수정·삭제 액션에는 optimistic update를 적용하고, 실패 시 이전 캐시 기준으로 롤백했습니다. 그 결과 새로고침 이후에도 화면 상태를 유지하고 운영 이슈가 발생했을 때 동일한 화면을 빠르게 공유할 수 있게 되었습니다.
회원가입 플로우 개선
회원가입을 퍼널 기반으로 재설계해 입력 단계를 여러 화면으로 나누고, 이메일 인증 코드 재전송 기능과 명확한 피드백 메시지를 추가했습니다. 이를 통해 한 화면에서 처리해야 할 정보량을 줄이고 가입 과정의 혼란을 낮췄습니다.
공연 정보 탐색 경험 개선
공연 상세 정보를 공연 정보, 위치, 환불 규정으로 나눠 탭으로 분리하고, 핵심 정보는 우선 노출한 뒤 부가 정보는 모달로 확인할 수 있도록 재설계했습니다. 이를 통해 정보 탐색 속도를 높이고 불필요한 피로도를 줄였습니다.






