Skip to content

jueunk617/catfe

 
 

Repository files navigation

😺 Catfé

가상 스터디룸에서 캠/오디오/화면을 공유하며 함께 공부하고, 스터디 플래너와 커뮤니티를 통해 학습 동기를 부여하는 실시간 온라인 학습 서비스 (2025.09.12 ~ 2025.10.16)


📚 목차

  1. 🖼️ 프로젝트 소개
  2. 👥 팀 구성 및 역할
  3. 🎯 개발 배경
  4. ⚙️ 기술 스택
  5. 🧩 ERD
  6. 🧾 API
  7. 🌐 시스템 아키텍처
  8. 💾 주요 기능
  9. 🔄 개발 프로세스
  10. 🧠 트러블슈팅
  11. 💡 주요 결정 및 배운 점

🖼️ 프로젝트 소개

undefined.png

함께 공부하는 가상 스터디 카페, Catfé

Catfé는 온라인 환경에서도 오프라인 스터디 카페처럼 함께 공부하는 몰입감을 제공하는 실시간 학습 플랫폼입니다.

WebRTC 기반 실시간 통신, 스터디 플래너, 타이머, 커뮤니티 기능을 통해 사용자의 자기 주도적 학습을 지원하고 학습 동기를 높입니다.


👥 팀 구성 및 역할

🎨 FrontEnd

팀원 이름 GitHub 담당 기능
정은진
FE 팀장
@eafiseemn • 스터디 플래너 / 유지 정보
• 스터디룸 채팅
• 커뮤니티 페이지
• 404 페이지
김유하 @cheezstick • Guest / User Home
• 스터디룸 검색 페이지
• 외부 스터디룸 모달
• 로딩 페이지
박진강 @JinKeyP • 로그인 / 회원가입
• 계정 찾기
• WebRTC / 스터디룸 페이지
• 스터디룸 타이머

🛠 BackEnd

팀원 이름 GitHub 담당 기능
김주은
BE 팀장
@jueunk617 • 스터디룸 상호작용
• 채팅 / 알림
김선호 @KSH0326 • 스터디 플래너
남기은
PO
@namgigun • 인프라 / 배포 / 운영
• 파일 업로드
조예원 @joyewon0705 • 인증 / 인가
• 커뮤니티
진민호 @loseminho • 스터디룸 관리

🎯 개발 배경

❗ 문제 인식

온라인 학습 환경이 보편화되었음에도 불구하고, 많은 학습자들은 여전히 혼자 공부하는 과정에서 한계를 느끼고 있습니다.

  • 혼자 공부하며 집중력 저하동기 부족 발생
  • 오프라인 스터디 공간은 시간·장소·비용 제약이 큼
  • 학습을 함께 관리하고 지속할 수 있는 환경 부족

⚠ 기존 서비스의 한계

기존 온라인 학습 서비스와 화상 통화 도구는 다음과 같은 구조적 한계를 가지고 있었습니다.

  • 학습 도구가 분산되어 있어 흐름이 끊김
  • 단순 화상 연결 중심으로 상호작용 부족
  • 학습 계획·기록 관리가 수동적이고 파편화됨
  • 참여가 일회성에 그쳐 학습 지속성 확보가 어려움

💡 해결 방향

Catfé는 이러한 문제를 해결하기 위해
학습의 지속성 · 몰입 · 연결감을 동시에 제공하는 온라인 스터디 카페 플랫폼을 목표로 기획되었습니다.

  • 실시간 화상 기반 스터디룸으로 공간적 몰입감 제공
  • 타이머와 연동된 스터디 플래너로 자동화된 학습 관리
  • 커뮤니티 기반 상호작용을 통해 동기 부여 및 참여 유도

🎯 개발 목표

혼자 공부하는 공간을, 함께 성장하는 공간으로

Catfé는 학습자가 실제 스터디 카페에 있는 것처럼
함께 공부하고, 기록하고, 소통하며
지속 가능한 온라인 학습 경험을 제공하는 것을 목표로 합니다.


⚙️ 기술 스택

Backend

Realtime Communication

Database

Deployment & Infra

협업 & 문서화


🧩 ERD

catfe-ERD-(MVP).png

MVP VER.


🧾 API

Catfé는 REST API와 실시간 통신 API(WebSocket / WebRTC)를 함께 제공합니다.

📌 전체 API 명세는 아래 문서에서 확인할 수 있습니다.

  • 🔗 API 명세서 (Notion)

    REST API 전체 명세 및 Swagger에서 확인하기 어려운 WebSocket(STOMP) API를 별도로 정리했습니다.

  • 🔗 Swagger UI

    REST API 요청·응답을 테스트할 수 있는 문서입니다.



📌 API 구조 개요

인증 / 사용자

  • 회원가입 / 로그인 / 로그아웃
  • 프로필 조회 / 수정

스터디룸

  • 스터디룸 생성 / 조회 / 참여 / 삭제
  • 역할 관리 / 타이머 상태 관리

스터디 플래너

  • 플래너 등록 / 수정 / 삭제
  • 일정 조회

커뮤니티

  • 게시글 / 댓글 CRUD
  • 좋아요 / 북마크

파일 업로드

  • 이미지 업로드 / 삭제

⚡ 실시간 통신 API

WebSocket (STOMP 기반)

  • 채팅 메시지 송수신
  • 스터디룸 입장 / 퇴장 이벤트
  • 스터디룸 상태 변경 알림

WebRTC

  • 캠 / 오디오 스트림
  • 화면 공유
  • WebSocket 기반 시그널링 처리

상세한 요청/응답 구조 및 예시는 위 Notion 명세에서 확인해주세요.


🌐 시스템 아키텍처

akitegcheo.png


💾 주요 기능

🏠 홈 화면

Guest Home User Home
  • 비회원 / 회원 상태에 따라 분리된 홈 화면 제공
  • 스터디룸 탐색 및 주요 기능으로의 진입 동선 분리

🎥 실시간 스터디룸

스터디룸 생성 스터디룸 검색 스터디룸 입장
  • 공개 / 비공개 스터디룸 생성 및 검색
  • Redis 기반 초대 코드 발급 및 검증
  • 동시 입장 시 정원 초과 방지를 위한 동시성 제어

🎬 스터디룸 내부 & 실시간 상호작용

스터디룸 실시간 채팅 스터디룸 타이머
  • WebRTC(P2P) 기반 캠 / 오디오 / 화면 공유
  • STOMP 기반 WebSocket 실시간 채팅
  • 타이머 상태 및 입장 / 퇴장 / 역할 변경 이벤트 실시간 동기화

⏱ 스터디 플래너

스터디 플래너 계획 등록 / 수정
  • 타이머와 연동된 자동 학습 기록
  • 시간대 기반 계획 등록 및 수정
  • 반복 일정 및 예외 처리 지원

🧑‍🤝‍🧑 커뮤니티

스터디 그룹 탐색 게시글 댓글
  • 스터디 그룹 탐색 및 모집
  • 게시글 / 댓글 CRUD
  • 좋아요 및 북마크 기능 제공

👤 마이페이지

마이페이지 회원 정보 수정 회원 탈퇴
  • 프로필 정보 조회 및 수정
  • 계정 탈퇴(soft delete) 처리 및 개인정보 보호

🔄 개발 프로세스

👉 개발 및 배포 프로세스 & Git 컨벤션 가이드 바로가기


🧠 트러블슈팅

1️⃣ [WebRTC] SFU 없이 다수 인원 화상 통신 구현

  • 💥 문제: WebRTC 기반 화상 스터디 플랫폼에서 최대 20명까지 실시간 참여가 필요했으나,
    AWS 프리티어 환경 제약으로 SFU 서버(Media Server)를 사용할 수 없었음.

  • 🔍 원인: P2P(WebRTC Mesh) 구조는 참가자 수가 늘어날수록 브라우저 부하와 네트워크 트래픽이 급격히 증가함.
    단일 룸에서 무제한 화상 연결은 현실적으로 불가능한 구조였음.

  • 해결:

    • 사전 PoC를 통해 4명 이하에서는 P2P 화상 통신이 안정적임을 검증함.
    • 스터디룸을 목적에 따라 분리 설계함.
      • OnCam 룸: 최대 4명 (화상/음성 중심)
      • OffCam 룸: 최대 20명 (화면 공유 + 채팅 중심)
    • 룸 타입에 따라 WebRTC 기능 활성화 범위를 제한함.

    👉 결과: 서버 비용 0원 유지하면서도, 사용 목적에 맞는 안정적인 사용자 경험 확보.


2️⃣ [WebRTC] 시그널링 충돌로 인한 연결 실패 문제

  • 💥 문제: 다수 사용자가 동시에 스터디룸에 입장할 경우, WebRTC 연결이 connectionState = failed 상태로 종료되는 현상 발생.

  • 🔍 원인:

    • 동시 입장 시 양쪽 클라이언트가 동시에 Offer를 전송하면서 시그널링 충돌 발생.
    • 기존 1:1 메시지 방식에서 principal.getName()과 실제 userId 불일치로 메시지 전달 실패.
  • 해결:

    • 시그널링 채널을 방 전체 브로드캐스트(/topic/room/{roomId}/webrtc) 방식으로 변경하고, 클라이언트에서 필요한 메시지만 필터링하도록 구조 개선.
    • 양보 규칙(Polite Peer Strategy) 적용
      • ID가 작은 쪽 → 기존 Offer 유지
      • ID가 큰 쪽 → Offer 취소 후 상대 Offer 수락

    👉 결과: 동시 입장 상황에서도 P2P 연결 성공률 대폭 개선.


3️⃣ [Redis] 실시간 세션 불일치 문제 (유령 사용자)

  • 💥 문제: 비정상 종료된 사용자가 계속 ‘온라인’ 상태로 남아
    이미 나간 사용자에게 메시지를 보내는 현상 발생.

  • 🔍 원인:

    • WebSocket 연결 상태와 룸 참여자 정보가 분리 관리됨.
    • 기존 TTL(4시간)이 길어 세션 정리가 지연됨.
  • 해결:

    • Redis 기반 실시간 세션 관리 전략 수립
      • ws:user:{userId}: 사용자 WebSocket 세션
      • ws:session:{sessionId}: 세션 ↔ 유저 매핑
      • ws:room:{roomId}:users: 룸 참여자 Set
    • JWT 인증 기반으로 현재 연결된 세션만 유효 사용자로 판단
    • TTL을 4시간 → 5분으로 조정하여 비정상 종료 빠른 감지

    👉 결과: 세션 동기화 정확도 100% 달성.


4️⃣ [WebSocket] 입·퇴장 상태 반영 지연 문제 (Pull → Push)

  • 💥 문제: 스터디룸 입·퇴장 정보가 5~10초 지연되어 반영됨.

  • 🔍 원인: 클라이언트가 주기적으로 상태를 조회하는 Pull 방식 구조로 인해 실시간성이 떨어짐.

  • 해결:

    • 이벤트 기반 Push 구조로 전환
      • Backend: SessionManager → 이벤트 발행 → RoomService 처리
      • Frontend: /topic/room/{id}/events 구독
    • USER_JOINED, USER_LEFT 이벤트 수신 즉시 화면 갱신

    👉 결과: 입·퇴장 상태 즉시 반영, 실시간 동기화 달성.


5️⃣ [리팩토링] 270줄 God Class 개선 (Facade 패턴)

  • 💥 문제: WebSocketSessionManager가 Redis 접근, 세션 관리, 룸 로직을 모두 담당하며 SRP 위반.

  • 🔍 원인: 초기 구현 단계에서 빠른 기능 완성에 집중해 책임 분리가 이루어지지 않음.

  • 해결: Facade 패턴을 적용해 역할 분리

    • RedisSessionStore : Redis CRUD
    • UserSessionService : 세션 생명주기 관리
    • RoomParticipantService : 룸 참여자 로직

    👉 결과: 코드량 31.5% 감소, 유지보수성 및 확장성 향상.


6️⃣ [이벤트] 실시간 알림 시스템 비동기화

  • 💥 문제: 알림 로직이 각 도메인 서비스에 직접 연결되어 강결합 발생.

  • 🔍 원인: 알림 실패 시 비즈니스 로직까지 영향을 줄 수 있는 구조.

  • 해결:

    • Spring Events + @Async 기반 비동기 알림 처리
    • Publisher / Subscriber 패턴 도입

    👉 결과: 알림 실패와 무관하게 핵심 트랜잭션 안정성 확보.


7️⃣ [성능] N+1 쿼리 최적화

  • 💥 문제: UserProfile 조회 시 N+1 쿼리 발생.

  • 🔍 원인: 연관 엔티티 지연 로딩 구조로 인한 반복 조회.

  • 해결:

    • QueryDSL fetch join (To-One)
    • hibernate.default_batch_fetch_size=50 (To-Many)
    • datasource-proxy로 쿼리 수 자동 검증

    👉 결과: 조회 쿼리 11회 → 2회로 감소.


💡 주요 결정 및 배운 점

  • WebRTC 구조 설계의 현실성

    • 무작정 기술적으로 ‘가능한 구조’보다, 인프라 제약과 사용자 목적을 함께 고려한 설계가 중요함을 배웠습니다.
  • 실시간 시스템에서의 상태 동기화

    • Pull 방식보다 이벤트 기반 Push 구조가 실시간 서비스에 훨씬 적합함을 체감했습니다.
  • Redis는 단순 캐시가 아니다

    • Redis를 세션 스토어로 활용하면서, 실시간 상태 관리의 핵심 인프라로 사용할 수 있음을 배웠습니다.
  • 리팩토링은 선택이 아니라 필수

    • 기능 구현 후 책임 분리를 통해 코드 복잡도를 낮추는 것이 장기적으로 훨씬 효율적임을 경험했습니다.
  • 이벤트 기반 아키텍처의 힘

    • Spring Events를 통해 도메인 간 결합도를 낮추고, 확장 가능한 구조를 설계할 수 있었습니다.

About

가상 스터디룸에서 함께 공부하는 경험을 제공하는 실시간 온라인 스터디 카페

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Java 99.4%
  • Other 0.6%