Duckport | 포트폴리오
현재 배포된 포트폴리오 사이트 입니다
기간: 2026-01 ~ 진행중인원: 1 명
Stack: Next.js, Cloudflare, TypeScript, JavaScript
#Portfolio#Blog
DuckPort
Next.js 15 (App Router) 기반 포트폴리오 CMS. Cloudflare D1(SQLite) + R2(Object Storage) 위에서 동작하며, 관리자 대시보드를 통해 프로젝트/포스트/프로필/사이트 설정을 관리합니다.
Tech Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router), React 19, TypeScript (strict) |
| Styling | Tailwind CSS 4 |
| Visualization | D3.js 7 (버블 차트) |
| Math Rendering | KaTeX (LaTeX 수식) |
| Hosting | Cloudflare Pages |
| Database | Cloudflare D1 (SQLite) |
| Storage | Cloudflare R2 (이미지 + 마크다운 콘텐츠) |
| Build | OpenNext.js (@opennextjs/cloudflare) |
Features
Public Pages
- Home — 3페이지 플립북 인트로 (프로필 소개, About, 스킬 버블 차트)
- Projects — 리스트 / 그리드 / 간략 보기 전환, 카테고리 필터, 키워드 검색, 정렬
- Project Detail — Markdown + KaTeX 수식, 기간/팀/스택/링크, 사이드바 네비게이션
- Posts — 리스트 / 그리드 / 간략 보기 전환, 카테고리 필터, 키워드 검색, 정렬
- Post Detail — Markdown + KaTeX 수식, 태그, 사이드바 네비게이션
- Dark / Light Theme — 토글 + 시스템 설정 감지
Admin Dashboard
- Projects 관리 — CRUD, 썸네일 업로드, Markdown 편집기 + 실시간 미리보기, 발행/임시저장
- Posts 관리 — CRUD, 썸네일 업로드, Markdown 편집기 + 실시간 미리보기, 발행/임시저장
- Profile 편집 — 이름, 태그라인, 소개글, 아바타, 소셜 링크 (11종 아이콘 + 커스텀 아이콘)
- Site Settings — 사이트명, SEO, 폰트 (16종 + 5단계 크기), 버블 차트 설정
- Categories 관리 — 프로젝트/포스트별 카테고리 추가/삭제
Typography
16종 Google Fonts 선택 가능. 설정 페이지에서 실시간 미리보기 후 저장하면 전체 사이트에 적용됩니다. 폰트 크기(xs~xl)는 root font-size를 변경하여 모든 rem 기반 사이즈가 비례 스케일링됩니다.
| 분류 | 폰트 |
|---|---|
| Sans-serif | Inter, Roboto, Open Sans, Lato, Poppins, Nunito, Montserrat, DM Sans, Work Sans |
| Serif | Playfair Display, Lora, Noto Serif KR, Nanum Myeongjo |
| Korean | Noto Sans KR, Noto Serif KR, Nanum Gothic, Nanum Myeongjo |
| Monospace | Source Code Pro |
Architecture
src/
├── app/
│ ├── (public)/ # 공개 페이지 (홈, 프로젝트, 포스트)
│ ├── ad/ # 관리자 대시보드
│ └── api/ # REST API
├── components/ # React 컴포넌트
│ ├── layout/ # Header, Footer
│ ├── ui/ # 재사용 UI 컴포넌트
│ ├── PageFlipBook.tsx # 홈 플립북
│ ├── StackBubbles.tsx # D3 버블 차트
│ ├── DetailSidebar.tsx # 상세 페이지 사이드바
│ ├── PostListView.tsx # 포스트 목록 (검색, 필터, 뷰 전환)
│ ├── ProjectListView.tsx # 프로젝트 목록 (검색, 필터, 뷰 전환)
│ └── *Form.tsx # 관리자 폼 컴포넌트
├── lib/
│ ├── db/ # D1 데이터베이스 헬퍼
│ ├── r2/ # R2 스토리지 헬퍼
│ ├── auth/ # 인증 모듈
│ └── markdown.ts # Markdown → HTML 변환 (KaTeX 포함)
└── middleware.ts # 라우트 보호
Key Patterns
| Pattern | Description |
|---|---|
| 인증 | 서명 기반 세션 토큰, HttpOnly 쿠키 |
| 콘텐츠 저장 | D1에 메타데이터 + R2에 Markdown 파일 분리 저장 |
| 이미지 업로드 | R2 직접 저장 후 asset 메타 기록 |
| 폰트 시스템 | Google Fonts 동적 로드, root font-size 비례 스케일링 |
| 라우트 보호 | 미들웨어 기반 세션 검증 |
Data Model
D1 Tables
projects— 프로젝트 (제목, 슬러그, 카테고리, 스택, 태그, 기간, 팀, 링크)posts— 포스트 (제목, 슬러그, 카테고리, 태그)profile— 프로필 단일 행 (이름, 소개, 아바타)site_settings— 사이트 설정 단일 행 (브랜딩, 폰트, 카테고리, 소셜 링크)assets— 업로드 파일 메타데이터tags— 태그 관계 테이블
R2 Storage
- 업로드된 이미지 파일
- 프로젝트/포스트 본문 마크다운 파일
Getting Started
Prerequisites
- Node.js 18+
- Wrangler CLI (
npm install -g wrangler) - Cloudflare 계정 (D1 + R2 설정)
Setup
bash# 의존성 설치
npm install
# D1 로컬 마이그레이션 적용
npm run db:migrate
# 관리자 계정 생성
npm run db:seed-admin
# 개발 서버 실행
npm run dev
Commands
bashnpm run dev # 개발 서버 (localhost:3000)
npm run build # Next.js 빌드
npm run preview # Cloudflare 로컬 프리뷰
npm run deploy # Cloudflare Pages 배포
npm run db:migrate # D1 로컬 마이그레이션
npm run db:migrate:prod # D1 프로덕션 마이그레이션
npm run db:seed-admin # 관리자 계정 생성
npm run lint # ESLint
Environment Variables
| Variable | Description | Required |
|---|---|---|
SESSION_SECRET | JWT 서명 키 | Production |
SITE_URL | 사이트 기본 URL (메타데이터용) | Optional |