본문으로 건너뛰기
배기훈프론트엔드 개발자
← 개인 프로젝트

Resume

운영 중

코드 없이 고치는 내 포트폴리오 사이트

관리자 화면에서 소개, 프로젝트, 경력을 고치고 화면 배치까지 바꿀 수 있는 포트폴리오 사이트입니다. 초안으로 저장해 두었다가 원할 때 게시하고, 이전 버전으로 되돌릴 수도 있습니다. 오픈소스라서 누구나 자기 서버에 설치해 쓸 수 있습니다.

왜 만들었나

포트폴리오는 한 번 만들고 끝나지 않아요. 프로젝트가 늘고 경력이 바뀔 때마다 고쳐야 하는데, 직접 코딩한 사이트는 문구 하나를 바꾸려 해도 코드를 열고 다시 배포해야 했습니다. 반대로 노코드 빌더는 편하지만 내 데이터와 디자인을 서비스에 맡겨야 하고요.

그래서 내 서버에 설치하고, 관리자 화면에서 바로 고치는 포트폴리오를 직접 만들기로 했습니다.

할 수 있는 것

  • 화면을 보면서 편집: 공개 사이트와 똑같이 그려지는 미리보기를 보면서 소개, 프로젝트, 회사 경험, 히스토리를 고칩니다.
  • 모듈로 페이지 구성: 자기소개, 대표 프로젝트, 성과, 기술 스택 같은 모듈을 추가하고, 배치와 크기를 바꿉니다.
  • 데스크톱과 모바일 따로 배치: 내용은 함께 쓰고, 순서와 너비, 숨김은 화면마다 따로 정합니다.
  • 초안 → 게시 → 되돌리기: 초안으로 저장해 두었다가 게시하고, 언제든 이전 버전으로 복원합니다.
  • 노션처럼 쓰는 상세 본문: 프로젝트와 회사 상세 페이지를 블록 에디터로 작성하고, 이미지도 올립니다.

구조

공개 사이트(apps/web)와 어드민(apps/admin)을 따로 배포하는 두 개의 Next.js 앱으로 나누었습니다. 공개 사이트는 어드민의 공개 API에서 게시본만 받아 그리기 때문에, 편집 중인 초안은 밖으로 나가지 않습니다.

두 앱은 서로의 코드를 가져다 쓰지 않고, 공통 패키지로만 공유합니다. 특히 모듈 렌더러를 패키지 하나로 빼서 공개 사이트와 어드민 미리보기가 같은 코드로 화면을 그리도록 했습니다. 그래서 미리보기에서 본 화면이 게시 후에도 그대로 나옵니다.

고민한 점

콘텐츠와 배치를 분리하기

프로젝트 같은 원본 콘텐츠는 한곳에 두고, 페이지의 모듈은 그 콘텐츠를 ID로 가리키게 했습니다. 같은 프로젝트를 홈에서는 크게, 목록에서는 작게 보여줘도 내용은 한 번만 고치면 됩니다.

미리보기에서 반응형을 그대로 재현하기

그리드가 화면 폭이 아니라 컨테이너 폭(container query)에 반응하도록 만들었습니다. 그래서 어드민에서 미리보기 프레임 폭만 1440px이나 390px로 바꾸면, 실제 데스크톱과 모바일 배치가 그대로 보입니다.

잘못된 데이터가 저장되지 않게 하기

모든 데이터 구조를 Zod 스키마 하나로 정의하고 편집할 때, 저장할 때, API로 응답할 때 모두 검사합니다. 존재하지 않는 프로젝트를 참조하거나 모듈이 겹쳐 배치되면 저장 전에 해당 입력칸에 오류가 표시됩니다. 본문도 HTML이 아니라 블록 JSON으로 저장해서 실행 가능한 문자열이 들어가지 않습니다.

여러 탭에서 편집해도 덮어쓰지 않기

초안에 버전 번호(revision)를 두고, 다른 탭에서 먼저 저장했다면 나중 저장을 거부합니다(낙관적 잠금). 모르는 사이에 작업이 사라지는 일을 막습니다.

설치와 운영을 단순하게

DB는 별도 서버 없이 SQLite 파일 하나로 동작하고, Docker로 실행할 수 있습니다. 관리자 계정은 웹 가입 없이 서버에서 명령어로만 만들고, 로그인 시도 횟수 제한과 출처(Origin) 검사로 어드민을 보호합니다.

기술 스택

  • 프런트엔드: Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS 4, shadcn/ui
  • 편집기: BlockNote
  • 백엔드·데이터: SQLite (better-sqlite3), Drizzle ORM, Better Auth, Zod
  • 개발 환경: Turborepo + pnpm 모노레포, Storybook, Biome, Playwright
  • 배포: Docker

매번 코드를 열지 않아도, 지금의 나를 바로 보여줄 수 있는 포트폴리오.