· case-study · 2 min read

웹소설 플랫폼을 처음부터 만들어보았다 — 작가·구독자·관리자, 세 사람을 위한 풀스택 개발기

작가가 글을 쓰고, 구독자가 읽고, 관리자가 통계를 보는 — 세 종류의 사용자가 각자의 화면을 갖는 웹소설 플랫폼을 풀스택으로 만든 이야기.

웹소설 플랫폼을 처음부터 만들어보았다 — 작가·구독자·관리자, 세 사람을 위한 풀스택 개발기

한 문장 요약

작가가 글을 쓰고, 구독자가 읽고, 관리자가 전체 통계를 보는 — 세 종류의 사용자가 각자의 화면을 갖는 웹소설 플랫폼을 풀스택으로 만들었습니다. 기획부터 디자인, 백엔드, 인프라까지 한 팀에서 진행한 프로젝트입니다.

3D도 AI도 들어가지 않은 “평범한 웹 플랫폼” 인데, 평범한 게 진짜 어렵다는 걸 다시 한번 배운 프로젝트였어요.

세 사람을 위한 세 개의 화면

플랫폼 구축에서 가장 먼저 결정해야 하는 건 누가 쓰는가 입니다. 이 프로젝트는 처음부터 셋이었어요.

  • 작가 — 소설을 쓰고, 회차를 발행하고, 자기 작품을 관리
  • 구독자 — 로그인 없이도 공개 작품을 읽을 수 있고, 가입하면 즐겨찾기
  • 관리자 — 전체 회원·소설을 관리하고, 통계 대시보드로 플랫폼 상태를 확인

이 셋이 서로 다른 페이지·권한·UX를 가지므로, 사실상 세 개의 앱을 하나의 코드베이스에서 만드는 작업이었습니다.

“소설 > 회차” 라는 데이터 구조

웹소설은 단순한 블로그가 아닙니다. 소설 한 편 안에 회차가 수십~수백 개, 회차마다 발행 상태가 다르고, 일부는 무료, 일부는 유료가 될 수 있어야 합니다. 우리는 이렇게 모델링했어요.

User ──────────────┐
                   │
Novel              │
 ├─ id             │
 ├─ authorId ──────┘
 ├─ title
 ├─ genre
 ├─ status (draft/public/private)
 └─ Episodes []
      ├─ id
      ├─ order
      ├─ title
      ├─ content (rich text)
      ├─ status (draft/published)
      └─ publishedAt

회차의 order 가 핵심입니다. 작가는 종종 회차 순서를 바꿉니다 — “중간에 5화를 끼워 넣고 싶어요”. 이런 요구를 처리하려면 order가 단순한 정수가 아니라 소수점이 가능한 숫자 여야 했습니다.

4화와 5화 사이에 새 회차를 넣을 때 모든 회차의 order를 다시 매기면 DB가 죽습니다. 새 회차의 order를 4.5로 잡고, 충분히 누적되면 그때 한꺼번에 정수로 정규화 — 이게 정석입니다.

“로그인 없이도 읽는다” 가 만든 캐싱 전략

이 플랫폼의 핵심 결정 중 하나는 공개 회차는 비로그인 상태에서도 읽힌다 였습니다. 이 한 줄이 백엔드 캐싱 전략을 완전히 바꿨어요.

  • 공개 회차는 CDN 레벨에서 캐싱 — 로그인 사용자도, 비로그인 사용자도 같은 캐시 히트
  • 회차 본문에 “좋아요 수” 같은 동적 데이터를 안 박는다 → 별도 API로 비동기 로드
  • 캐시 무효화는 회차 수정·발행 시점에만 — 작가가 수정하면 그 회차 URL만 invalidate

결과적으로 트래픽의 90% 이상이 CDN에서 처리됩니다. 서버는 작가의 편집과 구독자의 “좋아요 / 댓글” 같은 인터랙션만 처리하면 됩니다.

관리자 대시보드는 별도 앱으로

처음에는 관리자 화면도 같은 React 앱 안에 라우트로 두려고 했습니다. 그런데 곧 깨달았어요.

  • 관리자 페이지가 무거워질수록 일반 구독자가 받는 번들도 커진다
  • 권한 분리가 코드 분리보다 약하다 (실수가 한 번이면 사고)
  • 관리자 UX 가 통계·차트 중심이라 라이브러리도 다르다

그래서 관리자 페이지는 같은 백엔드를 공유하되 별도 React 앱 + 별도 도메인으로 분리했습니다. 이 결정 덕분에 일반 페이지의 번들이 30% 이상 가벼워졌어요.

“수정과 발행을 분리한다”

작가들이 가장 자주 요청한 기능은 의외였습니다.

“수정 중인 내용이 실수로 발행되면 안 돼요.”

처음에는 글 = 콘텐츠 한 덩어리로 모델링했는데, 이러면 작가가 글을 쓰는 중에도 구독자가 보고 있는 상태가 됩니다. 그래서 한 회차당 draftpublished 두 개의 콘텐츠 슬롯을 두기로 했어요.

Episode
 ├─ draftContent
 ├─ publishedContent
 ├─ status
 └─ publishAt (예약 발행 가능)

작가는 항상 draftContent를 편집하고, “발행” 버튼을 눌러야 publishedContent로 복사 됩니다. 단순한 변경이지만 작가들의 안심도가 크게 올라갔어요.

모바일이 90%인 환경의 반응형

웹소설은 사용자의 90% 이상이 모바일 입니다. 이 가정이 디자인을 다 바꿉니다.

  • 본문 폰트는 16~18px 기본 — 작아 보여도 모바일에선 충분합니다
  • 줄 간격 1.7~1.8배 — 한 시간 읽어도 눈이 안 아픈 수준
  • 다크 모드 우선 설계 — 야간 독서가 압도적으로 많음
  • 스와이프 제스처로 회차 이동 — 다음/이전 버튼은 보조

이런 작은 디테일이 누적되면 체류 시간이 30% 이상 차이가 납니다. 우리는 처음에 이걸 “부수적 디테일” 로 봤다가, 베타 테스트 후 “핵심 기능” 으로 재분류했어요.

우리가 배운 것

“평범한 웹 플랫폼”이 가장 어렵다

3D나 AI 같은 화려한 요소가 없으면, 모든 평가가 속도·안정성·작은 UX 디테일에 집중됩니다. 숨을 곳이 없어요. 이런 프로젝트가 사실 가장 엔지니어링 실력을 드러냅니다.

캐싱 전략은 데이터 모델만큼 중요하다

“공개 콘텐츠는 CDN, 동적 데이터는 별도 API” — 이 한 줄짜리 룰이 인프라 비용을 다섯 배 줄입니다. 처음부터 이걸 의식하고 모델링하면 나중에 후회가 적어요.

관리자 페이지는 분리해라

같은 React 앱에 두지 마세요. 권한 분리, 번들 크기, 라이브러리 차이 — 세 가지 모두 분리가 정답입니다.

자주 받는 질문

비슷한 콘텐츠 플랫폼을 만드는 데 얼마나 걸리나요? 역할별 화면이 셋이라면 보통 12~16주 정도가 일반적입니다. 결제·구독 모듈이 들어가면 +4주.

작가용 에디터는 어떻게 구현했나요? ProseMirror 기반의 리치 텍스트 에디터를 썼습니다. 자동 저장(2초 단위), 이미지 인라인 업로드, 다른 회차 링크 자동 생성 — 작가의 글쓰기 흐름을 끊지 않는 게 가장 중요했어요.

확장성은 어디까지 보장하나요? 구독자 100만, 회차 100만 단위까지는 PostgreSQL + 적절한 인덱스로 충분합니다. 그 이상은 회차 본문을 별도 storage로 분리하는 식으로 확장합니다.

관리자 통계는 어떻게 보여주나요? 일별 신규 회원, 활성 작가, 인기 장르, 회차별 유입 등 15개 정도의 카드형 KPI와 시계열 차트로 구성했습니다. 모든 통계는 야간 배치로 사전 계산해 즉시 응답.


콘텐츠 플랫폼 — 웹소설, 강의, 뉴스레터, 블로그 등 — 을 처음부터 만들 계획이 있으시면 프로젝트 문의 로 사용자 역할 종류와 예상 규모를 알려주세요. 보통 첫 통화에서 데이터 모델과 캐싱 전략의 큰 그림을 같이 그려드립니다.

Hammergrid Lab은 React·Node.js 풀스택 웹 플랫폼과 3D·AI 도구를 만드는 크리에이티브 개발 스튜디오입니다.

English version: Building a Web Novel Platform from Scratch — One Codebase, Three Audiences

← 인사이트로

프로젝트 문의