지금 보고 계신 이 사이트, flexmstudio.com의 개발기입니다. 포트폴리오, 블로그, 자료실, 관리자 시스템까지 "나의 모든 것"을 하나의 사이트에 담고 싶었습니다. SPA의 SEO 한계를 정적 프리렌더링으로 해결하고, Cloudflare KV로 블로그와 포트폴리오를 서버 없이 관리하게 만든 과정을 공유합니다.
여러 프로젝트를 만들다 보니 한 가지 불편함이 생겼습니다. 결과물이 블로그, 깃허브, 각자의 도메인에 흩어져 있어서 "내가 만든 것"을 한눈에 보여줄 공간이 없었습니다. 그래서 포트폴리오 + 블로그 + 자료실 + 관리자 시스템을 모두 갖춘 개인 웹사이트를 만들기로 했습니다.
스택은 크게 고민하지 않았습니다. 익숙한 React 19 + TypeScript + Vite로 프론트엔드를 구성하고, 배포는 Cloudflare Pages를 사용했습니다. Pages가 지원하는 Workers 함수와 KV 저장소 덕분에 백엔드 서버 없이도 블로그·포트폴리오·댓글·문의 같은 동적 기능을 구현할 수 있었습니다.
| 역할 | 사용 기술 |
|---|---|
| 프론트엔드 | React 19, TypeScript, Vite, React Router 7 |
| 스타일 | Tailwind CSS 4 + CSS 변수 기반 디자인 시스템 |
| 배포 | Cloudflare Pages (전 세계 CDN) |
| 데이터 | Cloudflare KV (블로그·포트폴리오·댓글) |
| 이미지 | Cloudflare R2 (업로드 파일 저장) |
| 에디터 | TipTap 리치 텍스트 에디터 |
홈페이지 첫 화면은 타이핑 애니메이션 히어로로 시작합니다. "아이디어를 제품으로", "복잡함을 단순하게" 같은 문구가 순환하며 타이핑되는 방식입니다. 배경에는 파티클 캔버스가 흐르고, 마우스를 따라 은은한 글로우가 따라다닙니다. 스크롤하면 카드가 부드럽게 페이드인 되도록 useScrollFadeIn 훅으로 공통 처리했습니다.
아래로 내리면 최근 블로그 글, 최근 포트폴리오, 최근 자료가 실시간으로 렌더링됩니다. 홈이 곧 사이트의 요약 페이지인 셈입니다. 콘텐츠를 추가하면 홈도 자동으로 갱신되도록 Context 기반으로 데이터를 공유했습니다.
다크모드는 ThemeContext 하나로 처리합니다. 색상 팔레트를 CSS 변수(--c-text, --c-surface, --c-border 등)로 정의해 두고, 테마가 바뀌면 <html>에 클래스를 토글하는 방식입니다. 컴포넌트에서는 변수만 참조하므로 테마 전환을 위해 코드를 수정할 일이 없습니다.
// CSS 변수 기반 테마 — 컴포넌트는 var(--c-surface)만 참조
:root[data-theme='dark'] {
--c-surface: #0d1220;
--c-text: #e8ecf4;
/* ... */
}
블로그는 전부 Cloudflare KV에 JSON으로 저장됩니다. /api/blog Workers 함수가 글 목록 조회, 작성, 수정, 삭제, RSS 생성을 담당합니다. 글 작성은 TipTap 리치 텍스트 에디터를 사용하고, HTML 전문(全文)도 붙여넣기해 그대로 렌더링할 수 있습니다.
댓글은 별도의 KV 키에 저장되고, RSS(/feed.xml)와 /sitemap.xml도 자동 생성됩니다. 블로그 데이터를 브라우저 localStorage에 캐시해 첫 화면을 즉시 그린 뒤, 서버 데이터로 동기화하는 방식이라 체감 속도가 빠릅니다.
포트폴리오도 KV 기반입니다. 관리자 패널에서 로그인하면 프로젝트를 추가, 수정, 삭제, 드래그로 순서 변경까지 할 수 있습니다. 프로젝트마다 아이콘, 색상, 카테고리, 기간, 역할, 주요 기능 리스트를 입력하고, 썸네일 이미지도 업로드할 수 있습니다. 글 작성과 마찬가지로 즉시 반영됩니다.
이 프로젝트의 가장 큰 도전은 SPA의 SEO 문제였습니다. 자바스크립트로 렌더링되는 페이지는 검색엔진 크롤러에게 빈 껍데기로 보일 수 있습니다. 그래서 빌드 후 prerender-seo.mjs 스크립트가 10개 주요 라우트를 정적 HTML로 미리 렌더링해 dist에 생성합니다.
각 페이지는 useMetaTags 훅으로 제목, 설명, Open Graph, Twitter Card, canonical, JSON-LD(구조화 데이터)를 관리합니다. 그 덕분에 공유 시 카드 미리보기가 예쁘게 뜨고, 검색엔진이 페이지를 정상적으로 색인할 수 있습니다. sitemap과 RSS 피드도 자동 생성되어 색인 요청이 편리합니다.
사이트 뒤에는 완전한 관리자 시스템이 있습니다. 세션 토큰 기반 로그인, 비밀번호 변경, 그리고 AI 자동 글 생성 설정까지 포함합니다. 초기에는 AI가 뉴스를 요약해 자동으로 글을 발행하는 기능도 있었지만, 콘텐츠 품질 기준을 높이기 위해 자동 발행을 기본 비활성화로 바꾸고, 지금처럼 직접 쓴 원본 글 중심으로 운영 방향을 바꿨습니다.
이 사이트는 계속해서 제 작업의 중심이 되고 있습니다. 새 프로젝트가 나올 때마다 이곳에 기록이 쌓입니다.