GROOVE 6단대 연합축제 웹앱
축제
요약
경북대 6개 단과대(IT·간호·예술·사회·사범·자연) 연합축제 GROOVE의 모바일 웹. 신청곡 PLAYLIST, 주막 지도와 테이블 QR 주문, 가요제 사연 접수·투표, 역할별 관리자 대시보드 제공.
요구사항 문서(PRD)·API 명세 작성, 서버 개발, 배포와 축제 당일 운영 담당. 대동제 80주년 웹앱의 서버 구조와 배포 방식을 이어받아 확장.
설계 결정
- 곡 검색 소스를 커버리지 기준으로 교체: Deezer(원곡 커버리지 약 65%)에서 iTunes, 한글 표기 확보를 위해 Last.fm으로 전환하고 앨범 커버는 iTunes로 보강
- 곡 신청은 로그인 없이 학번으로 받고, 덮어쓰기 위험은 append-only 감사 로그로 복구 가능하게 설계
- 캠퍼스 와이파이 NAT 환경을 고려해 신청 속도 제한 기준을 IP에서 학번으로 변경
- 단일 인스턴스 전제로 키 단위 인-프로세스 락과 Idempotency-Key로 중복 요청 처리, Redis 없이 운영
해결한 문제
- nullable 컬럼 변경 배포 후 ddl-auto가 기존 NOT NULL 제약을 풀지 못해 서버 재시작이 반복된 장애 복구. 이후 엔티티와 운영 스키마 불일치를 배포 전에 잡는 점검 스크립트, 축제 당일 준비 상태 점검 스크립트 도입. 초기 데이터 적재 실패가 서비스 전체 장애로 번지지 않게 분리
- 개발 서버 배포가 대기 중인 운영 배포를 밀어내던 CD 결함을 브랜치별 동시 실행 그룹으로 분리. 재배포 때 업로드 이미지가 사라지던 볼륨 누락 보완
- 축제 첫날 주문 버튼 연타로 생긴 중복 주문(487건 중 37건) 원인 파악. 서버·DB는 그대로 두고 클라이언트의 Idempotency-Key 재사용과 장바구니 초기화를 고쳐 운영 중 배포
- 주막 관리자 화면을 입금 확인·주방·주문 내역·설정으로 분리하고 정산 엑셀 내려받기 추가. 사범대 날짜별 학과 분리, 새벽 5시 날짜 경계 처리
운영
- 축제 이틀간 API 요청 약 35만 건, 최대 분당 1,738건 처리. API 5xx 0건(프록시 로그 기준)
- 학부 서버에 GHCR 이미지와 self-hosted runner 기반 자동 배포 구성, Nginx 프록시 뒤에서 운영
기술 스택
- 서버: Java 21, Spring Boot 3.5, JPA, MySQL
- 클라이언트: React 19, Vite, TanStack Query, Tailwind, Sentry
- 배포: Docker, GHCR, GitHub Actions(self-hosted runner), Nginx
링크
GROOVE 웹사이트 ↗GitHub · client (React)