D-—정치 노잼인 거 아는데D-—그래도 1분만D-—내 동네 후보 누군지는 알고 찍자D-—정당 보고만 찍지 말기D-—팩트만 깔끔하게D-—이거 보고도 안 가면 어쩔 수 없고D-—정치 노잼인 거 아는데D-—그래도 1분만D-—내 동네 후보 누군지는 알고 찍자D-—정당 보고만 찍지 말기D-—팩트만 깔끔하게D-—이거 보고도 안 가면 어쩔 수 없고
노잼선거
← 메인
아키텍처

노잼선거 구성도

5일 만에 만든 시민 사이트의 4-레이어 구성. 시민 → 도메인 → Next.js → 데이터·API·Redis.

노잼선거 아키텍처 구성도노잼선거 사이트의 4-레이어 구성: 시민(상단) → nojam.kr 도메인/Vercel → Next.js 페이지들 → 데이터·API·Redis(하단). 외부 연동 서비스도 표시.시민 (누적 3,705명)디시·카톡·검색 유입nojam.kr · Vercel Edge가비아 도메인 · Hobby 플랜 · 월 ₩2,300Next.js 14 · TypeScript · TailwindApp Router · Server + Client Components메인/DDay · Top5 · 내동네지역 (16개)/[region]5종 선거직 탭통계 (7개)/stats/*Top5·재산·전과·동네별무투표 당선/stats/uncontested112명 명단게시판/board비회원 디시 스타일회고/recap선거도 재밌을 수 있나?관리자/admin데모/원본 토글소개·개인정보/about · /privacy시민 정보·중립성정적 데이터 (JSON)data/*.json · 빌드에 박힘• 시·도지사 54• 교육감 58• 구청장 570• 시·도의원 1,645• 구·시·군의원 4,387= 6,714명API RoutesEdge runtime/api/votes노잼/유잼 카운터/api/posts게시판 (CRUD)/api/admin/loginUpstash RedisVercel KV• 투표 카운터• 게시판 글• Rate limit무료 50MB외부 연동 · 분석 · 마케팅Kakao Share SDK카톡 공유Google Search ConsoleSEO · 인덱싱네이버 서치어드바이저SEO · 인덱싱Vercel Analytics방문자·페이지뷰선관위 (info.nec.go.kr) — 원본 엑셀 80개 · 선거 후 비공개
L1

시민

누적 3,705명, 페이지뷰 16,291회 (D-day 기준). 디시인사이드·카톡 단톡방·구글/네이버 검색으로 유입. Bounce Rate 25% — 진성 유저 중심.

L2

도메인 · 호스팅

nojam.kr (가비아 .kr 도메인, 연 ₩28,000). Vercel Hobby 플랜 (무료 — 100GB 대역폭/월 한도, 노잼선거는 ~3GB 사용). Edge에서 동적 렌더링.

L3

Next.js 14 앱

App Router 기반. TypeScript + Tailwind CSS. 서버 컴포넌트 위주, 인터랙티브한 부분만 클라이언트("use client"). 페이지 8개 카테고리:

  • 메인 — 카운트다운, Top 5, 내 동네 선택
  • 지역 (16개) — 5종 선거직 탭, 후보 카드, 동네 순위 카드
  • 통계 (7개) — Top 5, 재산, 정당별 전과, 구청장·시·도의원·구·시·군의원, 무투표 당선
  • 게시판 — 비회원 글쓰기 + 본인 글 삭제
  • 관리자 — 데모/원본 토글 (쿠키 기반 인증)
  • 회고 — 시민 사이트의 짧은 일생 정리
  • 소개·개인정보 — 사이트 정체성·중립성·정보 처리 방침
L4

데이터 · API · Redis

정적 데이터는 빌드 시점 JSON 파일 (선거 끝나면 더 안 바뀜). API Routes는 동적 데이터용 (투표·게시판·인증, Edge runtime). Upstash Redis (Vercel KV)는 카운터·게시글·rate limit 저장 — 무료 50MB 한도 안.

데이터 수집 파이프라인

nojam-crawler (별도 Python 프로젝트)

6,714명 후보 데이터는 노잼선거 본 사이트가 아니라 nojam-crawler라는 별도 Python 프로젝트에서 수집했다. 선관위(info.nec.go.kr)에서 5종 선거직별로 크롤링 → 엑셀 다운로드 → JSON 변환 → 노잼선거 data/*.json으로 복사.

nojam-crawler 데이터 수집 흐름선관위 → Playwright 브라우저 자동화 → Python 크롤러 (5종) → JSON 파일 → 노잼선거 data/ 폴더중앙선관위info.nec.go.kr선거 후 비공개Playwrightnojam-crawler · Python5종 선거직별 크롤러 분리• nec_candidate_crawler.py시·도지사, 교육감, 구청장• nec_crawler_sido_uiwon.py시·도의원• nec_crawler_gusigun_uiwon.py구·시·군의원JSON 변환노잼선거 data/5개 JSON 파일governorsmayors · councilorssupers · local
  • 왜 Playwright? 선관위가 일반 HTTP 요청을 차단해서 (가드 로직 있음). 실제 브라우저 자동화로 우회.
  • 왜 크롤러 4개로 분리? 선거직마다 페이지 구조·파라미터가 달라서. 시·도의원·구·시·군의원은 선거구 단위가 복잡해서 별도 처리.
  • 코드 라인 수: 약 917 LOC. nec_candidate_crawler.py 274 + nec_crawler_playwright.py 206 + 의원 크롤러 2개 × 188.
  • 실행 흐름: 시·도 코드 조회 → 선거구 코드 조회 → 후보자 표 HTML 파싱 → 엑셀 다운로드 → JSON 변환.
  • 유지보수 부담: 선관위 페이지 구조 바뀌면 깨짐. 다행히 4년 단위라 다음 지선에 한 번만 점검.

※ 크롤러 자체는 노잼선거 본 사이트에 포함되지 않고 별도 리포지토리로 관리. 본 사이트는 크롤러가 만든 JSON을 정적으로 import 할 뿐.

총 운영 비용
도메인
₩28,000/년
Vercel
무료
Upstash
무료
월 환산
₩2,300

이 구성도를 본인 프로젝트로 설명할 수 있게 공부하려면 → 공부하기 가이드

기술 도식 너머의 5일짜리 이야기가 궁금하면

→ 회고 읽기
한 줄 평가

이 사이트 어땠어요?