Progmong (프로그몽)
Progmong은 '개발자 성장'이라는 주제를 RPG 게임 요소와 결합한 커뮤니티 플랫폼입니다. 단순한 정보 공유를 넘어, 활동량에 따라 캐릭터가 성장하고 티어가 오르는 재미 요소를 더했습니다. 특히 반응형 웹의 한계를 넘어 게임 UI의 몰입감을 유지하기 위해 독자적인 스케일링 엔진을 구현했습니다.
프로젝트 개요
개발자를 위한 RPG 게이미피케이션 커뮤니티
Progmong은 개발자들이 자신의 학습 활동(Github 커밋, 백준 풀이 등)을 통해 경험치를 얻고, 캐릭터를 성장시키는 RPG 형태의 커뮤니티입니다. 딱딱할 수 있는 개발 활동에 게임의 재미를 접목하여 지속적인 동기부여를 제공합니다.
GitHub 및 Solved.ac API 연동을 통한 자동 경험치/티어 산정 시스템
데스크탑(Game View)과 모바일(App View)에 최적화된 Dual-Architecture 반응형 UI
Markdown 에디터 및 코드 하이라이팅, 수식(LaTeX)을 지원하는 강력한 콘텐츠 뷰어
사용자 행동에 반응하는 인터랙티브 펫 및 애니메이션 시스템
도전과제 및 해결과정
몰입형 게임 경험과 모바일 편의성을 동시에 잡는 Dual-Layout 전략
일반적인 반응형 웹(Fluid Layout) 방식으로는s 아트워크 중심의 고정 비율 게임 UI(데스크탑)와 세로 스크롤 중심의 모바일 UI를 동시에 만족시키기 불가능했습니다. 데스크탑에서는 게임의 몰입감을 위해 레이아웃이 깨지지 않아야 했고, 모바일에서는 작은 화면에서도 조작이 편리해야 했습니다.
• 단순 미디어 쿼리(CSS)만으로는 구조가 완전히 다른 두 뷰를 제어하기 어려움
• 데스크탑의 16:10 비율 게임 화면을 모바일 세로 화면에 억지로 끼워 맞출 시 가독성 저하
• 복잡한 게임 메뉴(상점, 던전 등)의 터치 영역 문제 발생
Scaling Stage 엔진과 Mobile Swiper의 이원화 UI 구현
화면 크기에 따라 단순히 CSS만 바꾸는 것이 아니라, 렌더링 전략 자체를 분기했습니다. 데스크탑은 브라우저 크기에 맞춰 비율을 유지하며 줌인/줌아웃되는 'Scaling Stage'를, 모바일은 터치 인터페이스에 최적화된 'Swiper' 메뉴를 제공했습니다.
Desktop: 'transform: scale'을 동적으로 계산하여 어떤 해상도에서도 1536x1024 디자인 원본 비율을 완벽하게 유지하는 Scaling Engine 구현
Mobile: 터치 친화적인 UX를 위해 게임 맵 대신 슬라이드 방식의 Navigation(Swiper)으로 레이아웃 전체 전환
'breakpoints.js' 유틸리티를 통한 체계적인 미디어 쿼리 관리 및 유지보수성 확보
// src/pages/Home/Home.jsx (Dual Layout 분기)
return (
<BackgroundContainer>
{isMobile ? (
// Mobile Strategy: 터치 친화적인 Swiper UI
<MobileSliderWrapper>
<Swiper modules={[Navigation]} loop>
{allItems.map(item => (
<SwiperSlide key={item.name}>
<MobileMenuIcon src={item.src} onClick={() => navigate(item.route)} />
</SwiperSlide>
))}
</Swiper>
</MobileSliderWrapper>
) : (
// Desktop Strategy: 비율 유지 Scaling Engine
<ScalingStage scale={scale}>
<StageContent>
{allItems.map(item => (
<DesktopMenuIcon
style={{ top: item.top, left: item.left }} // 절대 좌표 배치
onClick={() => navigate(item.route)}
/>
))}
</StageContent>
</ScalingStage>
)}
</BackgroundContainer>
)
사용자 콘텐츠의 보안 취약점 차단 및 렌더링 파이프라인 구축
개발자 커뮤니티 특성상 코드 포맷팅과 이미지, 수식 등 Rich Content 지원이 필수였습니다. 하지만 사용자가 입력한 HTML을 그대로 렌더링할 경우 XSS(Cross-Site Scripting) 공격에 노출될 치명적인 위험이 있었습니다.
• 'dangerouslySetInnerHTML' 사용 시 악성 스크립트 주입 공격 가능성
• 일반 텍스트 렌더링으로는 코드 블록 하이라이팅이나 수식 표현 불가
DOMPurify와 React Parser를 활용한 3단계 렌더링 파이프라인
입력된 콘텐츠를 '정제(Sanitize) -> 파싱(Parse) -> 변환(Transform)'하는 안전한 파이프라인을 구축하여 보안과 기능을 동시에 확보했습니다.
1단계 Sanitize: 'DOMPurify'를 통해 악성 스크립트 태그를 화이트리스트 기반으로 사전 제거
2단계 Parse: 'html-react-parser'로 HTML 문자열을 React VDOM으로 변환
3단계 Transform: '<pre><code>' 태그를 감지하여 'SyntaxHighlighter' 컴포넌트로 동적 치환 (코드 하이라이팅 적용)
// src/components/ContentView.jsx
export default function ContentViewer({ html }) {
// 1. 보안을 위한 Sanitization (XSS 방지)
const clean = DOMPurify.sanitize(html, { USE_PROFILES: { html: true } });
// 2. HTML -> React Lazy Component 변환
const content = parse(clean, {
replace(domNode) {
// 3. 코드 블록 발견 시 SyntaxHighlighter로 교체
if (domNode.name === 'pre' && domNode.children?.[0]?.name === 'code') {
const codeString = domNode.children[0].children[0]?.data;
return (
<SyntaxHighlighter language="javascript" style={dracula}>
{codeString}
</SyntaxHighlighter>
);
}
},
});
return <>{content}</>;
}
회고
기술적 도전과 사용자 경험 사이의 균형을 배운 프로젝트
반응형 웹을 단순히 '화면 너비에 따른 배치 변경'으로 접근했을 때, 모바일에서 게임 UI가 작아져 조작이 불가능해지는 치명적인 UX 결함을 발견했습니다. 이를 해결하기 위해 데스크탑은 '시각적 몰입(Scaling)', 모바일은 '조작 편의성(Swiping)'으로 렌더링 전략을 이원화했습니다. 플랫폼별 최적의 경험을 우선하는 엔지니어링 원칙을 정립한 계기가 되었습니다.
커뮤니티 기능을 구현하며 프론트엔드가 단순히 데이터를 보여주는 뷰어 역할에 그쳐서는 안 된다는 것을 배웠습니다. 사용자 입력을 그대로 렌더링할 때 발생하는 보안 위협(XSS)을 인지하고, 렌더링 직전에 정제(Sanitize)하는 파이프라인을 강제했습니다.