[한컴AI 아카데미 | 2026.05.17 | Day 48][Code Room] WebSocket 기반 실시간 코드 공유 서비스 개발기 (2) - 개선 및 배포

2026. 5. 19. 02:48·부트캠프

1. 새로고침 시 코드 초기화 문제 해결

🚨 문제 상황

초기 버전에서는 강사가 코드를 열심히 작성하다가도 실수로 새로고침을 하면 에디터의 코드가 모두 유실되는 문제가 있었다. 이는 뒤늦게 입장한 학생 역시 기존에 진행되던 수업 내용을 볼 수 없고 만일의 경우 네트워크 문제가 생겼을 때 화면이 새로고침 되면 빈 화면만 렌더링되었다. 실시간 동기화는 잘 동작했지만, 실제 수업 환경에서 쓰기에는 사용성이 부족했다.

[사용자 새로고침] ──> [소켓 연결 끊김] ──> [에디터 초기화 (기존 코드 유실)]

💡 개선 방향 및 구현

새로 접속하거나 페이지를 새로고침한 사용자도 가장 최근의 코드 상태를 그대로 이어서 볼 수 있도록 상태 유지(Persistence) 구조를 도입했다.

[강사 코드 입력] ──> [DB에 실시간 최신화 저장] ──> [재접속 시] ──> [최근 코드 복원]

강사가 코드를 변경할 때마다 데이터베이스에 최신 코드를 상시 저장하도록 처리했다.

이후 사용자가 방에 진입(페이지 렌더링)할 때, FastAPI 백엔드에서 데이터베이스에 있던 최신 코드를 initial_code라는 변수에 담아 템플릿과 함께 반환한다.

return templates.TemplateResponse(
    "teacher.html",
    {
        "request": request,
        "initial_code": code
    }
)

프론트엔드(HTML)에서는 백엔드가 넘겨준 초기 코드를 hidden script 태그 안에 안전하게 심어둔다.

<script id="initial-code" type="application/json">
    {{ initial_code }}
</script>

최종적으로 클라이언트 JavaScript가 실행될 때 이 script 태그의 텍스트를 읽어와 Monaco Editor에 주입한다.

const initialCode = document.getElementById("initial-code").textContent;
editor.setValue(initialCode);

이 템플릿 바인딩 방식을 통해 새로고침이나 재접속 이후에도 끊김 없이 수업을 이어갈 수 있는 안정적인 구조를 만들었다.


2. 채팅 기록 유지

🚨 문제 상황 및 개선

채팅 기능 역시 코드 에디터와 동일한 문제를 겪고 있었다. 실시간 대화는 가능했지만 새로고침을 하면 이전 질문이나 공지사항 등의 대화 기록이 모두 사라졌다.

이를 해결하기 위해 채팅 메시지가 발생할 때마다 DB에 로그를 저장하고, 방에 입장하는 시점에 과거 대화 이력을 상단에 리스트로 먼저 불러온 뒤 소켓을 연결하는 방식으로 변경했다.

덕분에 단순 대화 도구를 넘어 '수업의 타임라인 기록' 역할까지 수행할 수 있게 되었다.


3. 아키텍처 리팩토링: 역할 단위 분리

🚨 문제 상황

초기 프로토타입 단계에서는 빠른 구현을 위해 대부분의 API와 WebSocket 비즈니스 로직을 main.py 파일 하나에 전부 몰아넣었다. 이에 대해 MVP 기능이 어느 정도 완성되었다 생각해서 리팩토링을 진행했다.

💡 개선 방향

프로젝트 구조를 계층별 역할에 맞게 명확히 분리(Layered Architecture)했습니다.

app/
├── routers/       # 페이지 이동, 일반 API 및 WebSocket 엔드포인트 라우팅
├── services/      # 비즈니스 로직 핵심 처리 및 데이터 가공
├── models/        # DB 테이블 ORM 모델 정의
├── database.py    # DB 커넥션 및 세션(Session) 관리
├── templates/     # 프론트엔드 HTML (Jinja2)
└── static/        # CSS, 클라이언트 JS 등 정적 자원

역할을 엄격히 격리하고 나니, 향후 새로운 기능을 추가하거나 버그를 수정할 때 찾아가야 할 파일이 명확해져 생산성이 크게 향상되었다.


5. Docker 기반 배포 환경 구축

🐳 왜 Docker인가?

Linux 서버 환경 실습을 경험하면서 서비스 구성 요소들을 컨테이너 단위로 독립시켜 관리하는 Docker의 필요성을 느꼈다. 추후 Redis(웹소켓 Pub/Sub용) 도입이나 백엔드 스케일아웃(Scale-out) 등 서비스 확장성을 고려했을 때 인프라를 가상화하는 것이 유리하다고 판단했다.

인프라 구성 구조

[사용자 요청] ──> [Cloudflare Tunnel] ──> [Nginx 컨테이너] ──> [FastAPI (Uvicorn) 컨테이너] ──> [PostgreSQL 컨테이너]

Docker Compose를 활용하여 Nginx(Reverse Proxy), FastAPI(Application), PostgreSQL(Database)을 각각의 컨테이너로 묶고 하나의 독립된 가상 네트워크 안에서 안전하게 통신할 수 있도록 오케스트레이션 환경을 구축했다.


6. Cloudflare Tunnel을 활용한 배포

일반적인 배포 방식인 포트 포워딩(Port Forwarding)을 사용하면 공유기 설정 변경, 공인 IP 노출에 따른 보안 취약점 등 번거로운 제약사항이 많았다.

이를 해결하기 위해 Cloudflare Tunnel을 도입했습니다. 홈 서버나 내부 로컬 포트를 외부로 직접 개방하지 않고도 Cloudflare 데몬을 통해 안전한 아웃바운드 터널을 형성할 수 있었다.

이를 통해 복잡한 방화벽 설정 없이도 도메인(gyagoodev.store) 연결 및 HTTPS SSL 인증서 자동 적용까지 한 번에 해결했다.


7. 현재의 한계점 및 향후 개선 방향

설계한 기능을 모두 배포하는 데는 성공했지만, 실제 프로덕션 수준으로 운영하기 위해 보완해야 할 한계점들이 존재한다. 다음 스텝으로 아래 5가지 개선 사항을 차근차근 반영해 나갈 예정이다.

① 배포 환경에서의 IP 기반 접근 제한 버그 수정

  • 원인: 로컬에서는 정상 작동했으나, Cloudflare Tunnel을 거쳐 배포하니 서버에 사용자 실제 IP가 아닌 Cloudflare 프록시 서버의 IP가 전달되어 대역 비교가 실패하는 문제가 발생했다.
  • 해결 방향: Nginx 설정 및 FastAPI 미들웨어에서 X-Forwarded-For 또는 CF-Connecting-IP 헤더를 정확히 파싱하여 실제 클라이언트 IP를 추출하도록 수정할 계획이다.

② 다중 파일(Multi-File) 공유 기능 지원

  • 원인: 현재는 단일 에디터 구조라 main.py 같은 단 하나의 파일만 공유할 수 있다. 실제 수업에서는 여러 스크립트와 마크업 파일을 동시에 다룬다.
  • 해결 방향: VS Code의 탭(Tab) 구조나 사이드바 파일 트리를 벤치마킹하여, 파일 트리 생성 및 탭 전환 시 해당 파일의 데이터가 실시간 동기화되는 다중 파일 구조를 고려하고 있다.

③ 에디터 언어(Language) 선택 기능 추가

  • 원인: 현재 Monaco 에디터의 Syntax Highlighting이 특정 언어로 고정되어 있다. 수업에 따라 Python, JavaScript, HTML 등 다채로운 언어가 사용된다.
  • 해결 방향: 상단에 언어 선택 드롭다운(Dropdown)을 배치하고, 값이 변경되면 Monaco Editor의 setModelLanguage API를 트리거해 문법 강조 및 자동완성(IntelliSense) UX를 극대화할 예정이다.

④ 명시적 코드 저장 및 버전 관리 기능

  • 원인: 지금은 타이핑할 때마다 자동으로 덮어쓰는 자동 저장 방식에 가깝다. 지난 강의 자료를 박제하거나 특정 시점의 코드로 롤백하기 어렵다.
  • 해결 방향: 강사 화면에 [코드 저장] 버튼을 신설하여 스냅샷 형태로 DB에 기록하고, 학생들이 지난 수업 회차의 코드를 다시 조회할 수 있는 '히스토리 관리' 기능으로 확장하고자 한다.

⑤ 학생용 '전체 코드 복사' 편의 기능

  • 원인: 강사의 코드를 본인 로컬 에디터로 가져가고 싶을 때, 마우스로 처음부터 끝까지 드래그하여 Ctrl + C를 해야 하는 번거로움이 있다.
  • 해결 방향: 학생 화면 우측 상단에 [전체 복사] 버튼을 배치하고, Navigator.clipboard API를 연동해 클릭 한 번으로 전체 코드가 복사되도록 하고 복사 완료 시 깔끔한 토스트(Toast) 메시지를 띄워 UX를 다듬을 예정이다.

메무아

이번 프로젝트를 진행하며 가장 크게 확인한 점은 로컬 환경에서 기능이 동작하는 것과 실제 운영 환경에 서비스를 배포하는 것은 완전히 다른 영역이라는 점이었다.

로컬에서는 정상적으로 동작하던 기능들도 실제 배포 환경에서는 예상하지 못한 문제를 마주했다. 특히 네트워크 구조, Reverse Proxy, 환경 변수, WebSocket 프로토콜, Docker 내부 통신 방식과 같은 요소들은 단순 기능 구현 단계에서는 잘 드러나지 않았지만 실제 서비스 구조에서는 핵심 요소로 작동했다.

솔직히 지금까지 완성된 Code Room은 MVP 기능만 구현된 상태이다. 하지만 짧은 기간 안에 최소 기능을 빠르게 구현하고 실제 배포까지 진행하면서, 평소 적용해보고 싶었던 WebSocket 기반 실시간 양방향 통신 구조를 직접 구현하고 흐름을 이해할 수 있었다는 점에서 큰 의미가 있었다.

특히 이번 프로젝트에서 인상 깊었던 부분은 Nginx에 대한 이해가 확장된 경험이었다.

이전에는 단순히 Reverse Proxy 혹은 정적 파일을 제공하는 도구 정도로만 이해하고 있었지만, 실제 배포 환경에서 Nginx가 수행하는 역할은 생각보다 훨씬 넓었다.

예를 들어서,

HTTPS(SSL) 처리
WebSocket 요청 전달
경로 라우팅
Reverse Proxy
향후 Load Balancing 구조 확장 가능성

와 같이 서비스 구조의 중심에서 동작하고 있었다.

 

특히 WebSocket 연결을 nginx가 중간에서 올바르게 전달하지 않으면 실시간 기능 자체가 정상 동작하지 않는다는 점을 직접 경험하면서, 애플리케이션 서버만큼이나 인프라 계층에 대한 이해가 중요하다는 것을 확인할 수 있었다.

배포 과정에서는 단순히 문서를 읽는 것만으로는 이해하기 어려운 문제들도 직접 경험했다.

대표적으로,

localhost ≠ db
ws ≠ wss
depends_on ≠ 서비스 준비 완료 보장

와 같은 부분이다.

Docker Compose 내부에서 localhost는 컨테이너 자기 자신을 의미한다는 점, HTTPS 환경에서는 ws://가 아닌 wss:// 프로토콜을 사용해야 한다는 점, 그리고 depends_on이 단순 실행 순서만 보장할 뿐 내부 애플리케이션의 완전한 준비 상태까지 보장하지 않는다는 점은 실제로 문제를 겪으며 이해할 수 있었다.

 

이번 프로젝트는 한 주 동안 연습했던

Linux
Docker
Nginx
Database
네트워크 구조
배포 환경

를 하나의 서비스 안에서 다시 적용하며 복습하는 과정에 가까웠다.

단순 CRUD 구현 수준을 넘어, 서비스가 실제로 동작하기 위해 필요한 구조를 직접 설계하고 문제를 해결하는 경험을 할 수 있었다는 점에서 의미가 있었다.

현재 Code Room은 아직 개선해야 할 부분이 많다. IP 기반 접근 제한 기능, 다중 파일 관리, 언어 선택, 코드 저장 기능 등 보완해야 할 요소들이 남아 있다. 앞으로는 이러한 한계점을 하나씩 개선하면서, 단순 실습 프로젝트를 넘어 실제 사용 환경에서도 활용 가능한 서비스 형태로 확장해보고자 한다🤗

 

 

 

 

더보기

————————————————————————————————————————————————————— 

 

본 후기는 [한글과컴퓨터x한국생산성본부x스나이퍼팩토리]

한컴 AI 아카데미 (B-log) 리뷰로 작성 되었습니다.

'부트캠프' 카테고리의 다른 글

[한컴AI 아카데미 | 2026.05.20 | Day 51] Nginx를 활용한 WAS 이중화 및 로드밸런싱 환경 구축  (0) 2026.05.21
[한컴AI 아카데미 | 2026.05.18-19 | Day 49-50][AWS] Lightsail 기반 WEB-WAS-DB 3-Tier 인프라 배포 및 설정 반영 가이드  (1) 2026.05.19
[한컴AI 아카데미 | 2026.05.16 | Day 47][Code Room] WebSocket 기반 실시간 코드 공유 서비스 개발기 (1) - 핵심 기능 구현  (0) 2026.05.19
[한컴AI 아카데미 | 2026.05.15 | Day 46][Code Room] 실시간 서비스 배포를 위한 핵심 개념 정리  (0) 2026.05.19
[한컴AI 아카데미 | 2026.05.14 | Day 45] Cloudflare Tunnel과 Nginx로 서비스 연결하기  (0) 2026.05.15
'부트캠프' 카테고리의 다른 글
  • [한컴AI 아카데미 | 2026.05.20 | Day 51] Nginx를 활용한 WAS 이중화 및 로드밸런싱 환경 구축
  • [한컴AI 아카데미 | 2026.05.18-19 | Day 49-50][AWS] Lightsail 기반 WEB-WAS-DB 3-Tier 인프라 배포 및 설정 반영 가이드
  • [한컴AI 아카데미 | 2026.05.16 | Day 47][Code Room] WebSocket 기반 실시간 코드 공유 서비스 개발기 (1) - 핵심 기능 구현
  • [한컴AI 아카데미 | 2026.05.15 | Day 46][Code Room] 실시간 서비스 배포를 위한 핵심 개념 정리
NGC463l
NGC463l
무한한 우주에서 헤엄치는 고래 한 마리
  • NGC463l
    고래별
    NGC463l
  • 전체
    오늘
    어제
    • 🚀 (66)
      • 부트캠프 (56)
      • CS (3)
      • 코딩 테스트 (2)
        • 백준 (1)
      • 프로젝트 (4)
        • 크보패스 (4)
      • 일상 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    컴퓨터네트워크
    이코테
    위치기반서비스
    스나이퍼팩토리
    개발자취업
    UDP
    AI개발자
    개발자교육
    ai전문가양성
    백엔드
    selenium
    fastapi
    kakaoapi
    프로젝트
    부트캠프
    AI아카데미
    한국생산성본부
    이것이코딩테스트다
    API연동
    알고리즘
    한컴ai아카데미
    LLM
    데이터전처리
    한글과컴퓨터
    ai개발자교육
    TCP
    PYTHON
    BFS
    코딩테스트
    크롤링
  • hELLO· Designed By정상우.v4.10.6
NGC463l
[한컴AI 아카데미 | 2026.05.17 | Day 48][Code Room] WebSocket 기반 실시간 코드 공유 서비스 개발기 (2) - 개선 및 배포
상단으로

티스토리툴바