Skip to content

Do1K/brAIn

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🧠 brAIn

💡 개요

항목 내용
🕒 기간 2024-07 ~ 2024-08
👥 인원 6명
🛠 사용 기술
🎯 담당 역할 1) WebSocket, STOMP, RabbitMQ를 활용한 실시간 메시징 시스템 구축 (백엔드)
📖 개요 AI와 함께하는 브레인스토밍 회의 서비스

✍🏻 기획 배경:

  • 기존 아이디어 도출 회의에서 생성형 AI를 활용하는 시도는 그 자체로 혁신적이었으나, AI에게 질문을 던지며 발생하는 흐름의 단절과 참여자의 집중력 저하 문제는 중요한 도전 과제로 남아 있었습니다. 이는 AI가 회의 도중 단순 도구로 사용될 때 발생하는 문제점이며, 참여자들이 AI의 역할을 제대로 활용하지 못할 경우 더욱 두드러졌습니다.

  • 또한, 회의에 처음 참여하는 사람들, 특히 낯선 환경이나 새로운 사람들과 함께할 때 긴장감으로 인해 자신의 의견을 자유롭게 표현하지 못하는 경우가 종종 발생했습니다. 이는 회의의 효율성을 저하시키고, 창의적인 아이디어 도출의 기회를 놓치는 결과로 이어질 수 있습니다.

  • 이러한 문제들을 해결하기 위해 AI를 회의에 직접 참여시키고, 실시간으로 아이디어를 제공하며 논의를 촉진하는 역할을 맡기는 방식을 도입하고자 합니다. AI가 팀의 일원으로서 실시간 협업을 강화함으로써, 회의의 집중도와 효율성을 높이고, 참여자들이 자유롭고 편안하게 아이디어를 공유할 수 있는 환경을 조성하고자 합니다.

📛 서비스명 : brAIn

🏅 목표:

  • 창의적인 아이디어 도출: 라운드 로빈 기법을 적용하여 모든 참여자가 골고루 의견을 공유할 수 있도록 장려하며, 이를 통해 더 창의적이고 다양한 아이디어를 도출합니다.

  • AI와 인간의 협업 강화: AI가 회의의 일원으로서 실시간으로 아이디어를 제공하고, 논의의 방향을 제시하며, 이를 통해 인간 참여자들과의 협업을 극대화합니다.

  • 효율적인 회의 운영: AI와 라운드 로빈 기법의 결합으로 회의가 중단 없이 효율적으로 진행될 수 있도록 합니다. 또한, 이러한 방식은 참여자의 집중력을 유지하며 보다 많은 창의적 아이디어를 이끌어내는 데 중점을 둡니다.


⭐ 멤버

프론트엔드 프론트엔드 백엔드 백엔드 백엔드 & 인프라 백엔드 & AI
김상수 차민혁 김호준 강도원 정경원 박병준

🦾 주요 기능

익명성을 보장하는 회의 진행

  • 참가자들은 가명을 사용하여 익명으로 소통하며, 아이디어의 질과 양을 높이는 데 중점을 둡니다. 이를 통해 민감한 주제나 개인적 우려로 인해 제시하기 어려운 의견도 자유롭게 제시할 수 있습니다.
  • 라운드 로빈 방법을 이용한 회의 진행 모든 참가자는 정해진 순서에 따라 발언 기회를 가지며, 자신의 순서가 되면 반드시 아이디어를 제시해야 합니다.
  • 시스템이 발언 순서를 자동으로 관리하여, 모든 참가자가 한 번 이상 발언할 수 있도록 보장합니다.

실시간 공동 아이디어 보드 사용 및 투표

  • 모든 참가자가 실시간으로 아이디어를 시각적으로 공유하고 함께 작업할 수 있는 공용 작업 보드를 제공합니다.
  • 참가자들은 다른 사람의 의견을 실시간으로 확인하고, 보드에 직접 추가하거나 수정할 수 있어 협업의 효율성을 극대화할 수 있습니다.

회의 종료 후 요약본 즉시 확인

  • 회의가 종료되면 즉시 회의 요약본을 확인할 수 있어, 회의 내용을 빠르게 파악하고 후속 작업에 활용할 수 있습니다.

webRTC를 통한 실시간 화상 회의

  • webRTC 기술을 이용해 실시간으로 원활한 화상 회의를 진행하며, 원격지에서도 효율적인 소통이 가능합니다.

과거 회의 기록 관리

  • 모든 회의 기록은 자동으로 저장되어, 필요시 언제든지 과거 회의 내용을 참조할 수 있습니다.

✨ 기대 효과

  • 효율적인 브레인스토밍: AI의 실시간 참여로 회의 흐름이 중단되지 않고 지속되며, 다양한 아이디어가 끊임없이 도출됩니다. AI는 필요한 순간에 적절한 아이디어를 제공함으로써 회의의 진행을 촉진합니다.

  • 창의력 증대: AI가 제공하는 다양한 관점과 인간의 창의력이 결합되어 팀 전체의 창의력이 향상됩니다. AI는 새로운 시각에서의 아이디어를 제공하며, 이는 인간 참여자의 사고를 자극하여 더 독창적인 결과를 도출하게 합니다.

  • 집중력 유지: AI가 회의를 진행하면서 주요 논점을 요약하거나, 논의가 필요한 주제를 제시함으로써 참여자들의 집중력을 유지합니다. 이를 통해 회의의 질을 높이고, 보다 많은 의견이 효율적으로 공유될 수 있는 환경을 제공합니다.

  • 자유롭고 편안한 참여 환경 조성: 익명성이 보장되는 환경에서 AI가 회의의 일원으로 참여함으로써, 참여자들이 심리적 부담 없이 자유롭게 의견을 표현할 수 있습니다. 이는 특히 새로운 참여자나 낯선 환경에서 중요한 역할을 합니다.


📺 서비스 화면

메인 화면

main.png

회원 가입 화면

join.png

로그인 후 메인 화면

start.png

마이페이지 화면

mypage.png

회의 기록 화면

history.png

아이디어 도출 화면

opinion.png

아이디어 투표 화면

vote.png

아이디어 코멘트 화면

comment.png

회의록 & 화상 회의 화면

finalscreen.png

🧬 프로젝트 구조

아키텍처 다이어그램

arcitecture.png


🔥 나의 기여

1️⃣WebSocket, STOMP, RabbitMQ를 활용한 실시간 메시징 시스템 구축

1. 개요

프로젝트의 핵심 기능인 실시간 양방향 통신을 구현하기 위해 WebSocket을 기반으로, STOMP 프로토콜과 RabbitMQ 메시지 브로커를 조합하여 안정적이고 확장 가능한 메시징 시스템을 구축했습니다.

  • WebSocket: 클라이언트와 서버 간의 실시간 양방향 연결 통로를 제공합니다.
  • STOMP: WebSocket 위에서 동작하는 간단한 텍스트 기반 메시징 프로토콜로, 메시지의 발행(Pub)-구독(Sub) 모델을 쉽게 구현할 수 있도록 돕습니다.
  • RabbitMQ: 외부 메시지 브로커(Message Broker)로서, 서버의 부하를 줄이고 메시지를 안정적으로 처리 및 전파하는 역할을 수행합니다.

2. 핵심 아키텍처

메시징 시스템은 4개의 주요 구성 요소가 유기적으로 상호작용하도록 설계되었습니다.

  1. Client (Web Browser): 사용자가 접속하는 UI. WebSocket/STOMP 클라이언트를 통해 서버와 통신합니다.
  2. Spring Boot Server: 비즈니스 로직을 처리하는 백엔드 서버. STOMP 메시지를 수신하여 처리하고, 그 결과를 RabbitMQ로 전달합니다.
  3. RabbitMQ: 메시지 큐. Spring Boot 서버로부터 메시지를 받아 해당 메시지를 구독하고 있는 모든 클라이언트에게 신속하고 안정적으로 전파(Broadcast)합니다.
  4. Redis: 실시간 상태 관리 저장소. 회의 참가자 순서, 현재 진행 상태 등 빠르게 변하는 데이터는 Redis에 저장하여 성능을 확보했습니다.

3. 메시지 흐름 상세 분석

사용자가 메시지(포스트잇 제출 등)를 보내고 다른 사용자들에게 공유되기까지의 과정은 다음과 같습니다.

1단계: 연결 수립 및 브로커 설정

가장 먼저 클라이언트가 WebSocket 연결을 맺을 수 있는 엔드포인트(_**/ws**_)를 열어줍니다. 이후 메시지 브로커 설정을 통해 클라이언트와 서버, 그리고 외부 브로커(RabbitMQ) 간의 통신 규칙을 정의합니다.

💡 핵심 설정 (WebSocketConfig.java)

  • setApplicationDestinationPrefixes("/app"): 클라이언트가 서버로 메시지를 보낼 때(Publish) 사용하는 경로의 접두사입니다. /app으로 시작하는 메시지는 서버의 @MessageMapping 메서드로 라우팅됩니다.
  • enableStompBrokerRelay: Spring의 내장 브로커 대신 외부 RabbitMQ를 STOMP 브로커로 사용하도록 설정합니다. 이를 통해 메시지 처리의 책임을 RabbitMQ에 위임하여 서버의 부담을 줄이고 확장성을 확보합니다.

Java

// WebSocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // ...
        config.setApplicationDestinationPrefixes("/app")
              .enableStompBrokerRelay("/topic", "/queue", "/exchange", "/amq/queue")
              .setRelayHost("rabbitmq")
              .setRelayPort(61613)
              // ...
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").setAllowedOrigins("*");
    }
}

2단계: 서버 수신 및 비즈니스 로직 처리

클라이언트가 /app 접두사를 붙여 메시지를 발행하면, @MessageMapping 어노테이션이 해당 경로를 감지하여 메시지를 처리합니다.

MessageController는 메시지를 받은 후, 실제 데이터 처리 및 상태 변경 로직이 담긴 MessageService를 호출하여 비즈니스 로직을 수행합니다. 예를 들어, 제출된 포스트잇 내용을 Redis에 저장하고 다음 발표 순서를 결정하는 등의 작업을 처리합니다.

// MessageController.java
@Controller
public class MessageController {

    private final RabbitTemplate rabbitTemplate;
    private final MessageService messageService;
    ///...

    // ... 생성자 ...

    @MessageMapping("step1.submit.{roomId}")
    public void submitPost(RequestGroupPost groupPost, @DestinationVariable String roomId, StompHeaderAccessor accessor) {
        // 1. JWT 토큰을 통해 사용자 인증
        String token=accessor.getFirstNativeHeader("Authorization");
        String nickname=jwtUtilForRoom.getNickname(token);

        //...

        // 2. MessageService를 호출하여 비즈니스 로직 수행 (Redis에 데이터 저장 등)
        messageService.sendPost(Integer.parseInt(roomId), groupPost, nickname);

        ///...

        // 3. 응답 메시지 생성
        ResponseGroupPost aiResponseGroupPost=makeResponseGroupPost(aiGroupPost,Integer.parseInt(roomId),nextUser);


        // 4. 처리 결과를 RabbitMQ로 전송하여 모든 구독자에게 전파
        rabbitTemplate.convertAndSend("amq.topic","room." + roomId, aiResponseGroupPost);
    }
}

3단계: RabbitMQ를 통한 결과 전파 (Broadcast)

비즈니스 로직 처리가 완료되면, RabbitTemplate을 사용하여 그 결과를 RabbitMQ로 전송합니다. 이때 메시지는 amq.topic 이라는 기본 Topic Exchange로 보내지며, room.{roomId} 형태의 라우팅 키를 가집니다.

RabbitMQ는 이 라우팅 키와 일치하는 패턴(예: /topic/room/123)을 구독(Subscribe)하고 있는 모든 클라이언트에게 메시지를 전파합니다. 이 과정은 RabbitMQ가 전담하므로 서버는 다음 요청을 처리하는 데 집중할 수 있습니다.

4. 주요 기술적 결정: 동적 BindingQueue 관리

일반적인 RabbitMQ 백엔드 시스템에서는 Exchange, Queue, Binding을 개발자가 직접 코드로 설정하는 경우가 많습니다. 하지만 본 프로젝트처럼 다수의 채팅방이 동적으로 생성되고 사용자가 수시로 입장/퇴장하는 환경에서는 이러한 정적 설정이 비효율적입니다.

저는 이 문제를 STOMP 프로토콜의 특성과 RabbitMQ의 STOMP 플러그인을 활용하여 해결했습니다.

  • 자동화된 큐/바인딩: 클라이언트가 특정 주제(예: /topic/room/123)를 구독하면, RabbitMQ의 STOMP 플러그인은 해당 클라이언트만을 위한 임시 큐(Temporary Queue)를 자동으로 생성하고, 주제에 맞게 Exchange에 자동으로 바인딩합니다.
  • 자동 정리: 클라이언트의 연결이 끊어지면, 생성되었던 임시 큐와 바인딩은 자동으로 삭제됩니다.

✨ 이 접근 방식을 통해, 수동으로 큐를 관리할 필요 없이 동적인 Pub/Sub 환경을 효율적으로 구축할 수 있었습니다. 이는 코드의 복잡도를 낮추고 시스템의 유지보수성을 크게 향상시키는 효과를 가져왔습니다.

5. 결론

WebSocket, STOMP, RabbitMQ를 통합하여 실시간 메시징 시스템을 성공적으로 구축함으로써, 안정적으로 동작하고 수평 확장이 용이한 아키텍처를 구현할 수 있었습니다. 특히 외부 메시지 브로커를 도입하여 서버의 역할을 명확히 분리하고, STOMP 프로토콜의 장점을 활용해 동적인 Pub/Sub 환경을 효율적으로 관리한 경험은 분산 시스템에 대한 깊은 이해를 얻는 계기가 되었습니다.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Java 46.0%
  • JavaScript 40.1%
  • CSS 11.9%
  • Python 1.6%
  • Other 0.4%