Skip to content

fullkeem/portfolio

Repository files navigation

πŸš€ FrontEnd Developer Portfolio

Next.js 15 기반의 λͺ¨λ˜ν•œ 포트폴리였 μ›Ήμ‚¬μ΄νŠΈ

GitHub 계정이 μ—†λŠ” μ‚¬μš©μžλ„ λŒ“κΈ€μ„ μž‘μ„±ν•  수 μžˆλŠ” ν•˜μ΄λΈŒλ¦¬λ“œ λŒ“κΈ€ μ‹œμŠ€ν…œκ³Ό Notion CMSλ₯Ό ν™œμš©ν•œ 동적 μ½˜ν…μΈ  관리 κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.

✨ μ£Όμš” κΈ°λŠ₯

🏠 ν™ˆνŽ˜μ΄μ§€

  • GSAP 기반 타이핑 μ• λ‹ˆλ©”μ΄μ…˜
  • 슀크둀 트리거 μ• λ‹ˆλ©”μ΄μ…˜
  • λ°˜μ‘ν˜• Hero Section
  • 기술 μŠ€νƒ μ‹œκ°ν™”
  • 포트폴리였/λΈ”λ‘œκ·Έ 미리보기

πŸ’Ό 포트폴리였

  • Notion Database 연동 (μ‹€μ‹œκ°„ 동기화)
  • κ³ κΈ‰ 필터링 μ‹œμŠ€ν…œ (기술 μŠ€νƒλ³„, 검색어)
  • μΈν„°λž™ν‹°λΈŒ μΉ΄λ“œ UI (3D ν˜Έλ²„ 효과)
  • 동적 상세 νŽ˜μ΄μ§€ (Notion 블둝 λ Œλ”λ§)
  • GitHub/Live 링크 연동

πŸ“ λΈ”λ‘œκ·Έ

  • Notion CMS 기반 μ½˜ν…μΈ  관리
  • μ‹€μ‹œκ°„ 검색 (λ””λ°”μš΄μŠ€ 적용)
  • μΉ΄ν…Œκ³ λ¦¬/νƒœκ·Έ 필터링
  • 슀마트 νŽ˜μ΄μ§€λ„€μ΄μ…˜
  • μΈν„°λž™ν‹°λΈŒ λͺ©μ°¨ (슀크둀 슀파이)
  • κ΄€λ ¨ 포슀트 μΆ”μ²œ (AI 기반)
  • μ½”λ“œ ν•˜μ΄λΌμ΄νŒ… (Shiki)

πŸ’¬ ν•˜μ΄λΈŒλ¦¬λ“œ λŒ“κΈ€ μ‹œμŠ€ν…œ

  • GitHub μ‚¬μš©μž: Giscus (GitHub Discussions)
  • 일반 μ‚¬μš©μž: Supabase + 이메일 인증
  • μ‹œμŠ€ν…œ 선택 UI (톡계 ν‘œμ‹œ)
  • μ‹€μ‹œκ°„ μ’‹μ•„μš”/λ‹΅κΈ€ κΈ°λŠ₯
  • 슀팸 μ‹ κ³  μ‹œμŠ€ν…œ
  • 닀크λͺ¨λ“œ μžλ™ 연동

🎨 UX/UI

  • 닀크/라이트 λͺ¨λ“œ (μ‹œμŠ€ν…œ ν…Œλ§ˆ 감지)
  • 슀무슀 슀크둀 (Lenis)
  • 마이크둜 μΈν„°λž™μ…˜ (Framer Motion)
  • λ°˜μ‘ν˜• λ””μžμΈ (λͺ¨λ°”일 μš°μ„ )
  • μ ‘κ·Όμ„± 지원 (WCAG 2.2 AA)

πŸ›  기술 μŠ€νƒ

Frontend

  • Framework: Next.js 15.1.x (App Router, RSC)
  • Language: TypeScript 5.x
  • Styling: Tailwind CSS 3.x
  • Animation: GSAP, Framer Motion, Lenis
  • State: Zustand
  • Forms: React Hook Form

Backend & Database

  • BaaS: Supabase (PostgreSQL)
  • CMS: Notion API
  • Auth: Row Level Security (RLS)
  • Real-time: WebSocket subscriptions

Deployment & Tools

  • Platform: Vercel
  • Package Manager: pnpm
  • Linting: ESLint, Prettier
  • Version Control: Git

πŸš€ λΉ λ₯Έ μ‹œμž‘

1. μ €μž₯μ†Œ 클둠

git clone https://github.com/your-username/portfolio.git
cd portfolio

2. μ˜μ‘΄μ„± μ„€μΉ˜

pnpm install

3. ν™˜κ²½ λ³€μˆ˜ μ„€μ •

cp .env.example .env.local

ν•„μˆ˜ ν™˜κ²½ λ³€μˆ˜:

# Notion API
NOTION_API_KEY=your_notion_integration_token
NOTION_PORTFOLIO_DATABASE_ID=your_portfolio_database_id
NOTION_BLOG_DATABASE_ID=your_blog_database_id

# Supabase (λŒ“κΈ€ μ‹œμŠ€ν…œ)
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key

# Giscus (GitHub λŒ“κΈ€)
NEXT_PUBLIC_GISCUS_REPO=your-username/your-repo
NEXT_PUBLIC_GISCUS_REPO_ID=your_repo_id
NEXT_PUBLIC_GISCUS_CATEGORY=Announcements
NEXT_PUBLIC_GISCUS_CATEGORY_ID=your_category_id

4. λ°μ΄ν„°λ² μ΄μŠ€ μ„€μ •

# Supabase λŒ“κΈ€ μ‹œμŠ€ν…œ μŠ€ν‚€λ§ˆ 적용
# Supabase Dashboard > SQL Editorμ—μ„œ lib/supabase/schema.sql μ‹€ν–‰

5. 개발 μ„œλ²„ μ‹€ν–‰

pnpm dev

πŸŽ‰ http://localhost:3000μ—μ„œ ν™•μΈν•˜μ„Έμš”!


πŸ“ ν”„λ‘œμ νŠΈ ꡬ쑰

fullkeem_portfolio/
β”œβ”€β”€ app/                      # Next.js App Router
β”‚   β”œβ”€β”€ (routes)/            # 라우트 κ·Έλ£Ή
β”‚   β”‚   β”œβ”€β”€ portfolio/       # 포트폴리였 νŽ˜μ΄μ§€
β”‚   β”‚   β”œβ”€β”€ blog/           # λΈ”λ‘œκ·Έ νŽ˜μ΄μ§€
β”‚   β”‚   └── contact/        # μ—°λ½μ²˜ νŽ˜μ΄μ§€
β”‚   β”œβ”€β”€ api/                # API Routes
β”‚   β”‚   └── comments/       # λŒ“κΈ€ API
β”‚   β”œβ”€β”€ globals.css         # μ „μ—­ μŠ€νƒ€μΌ
β”‚   β”œβ”€β”€ layout.tsx          # 루트 λ ˆμ΄μ•„μ›ƒ
β”‚   └── page.tsx            # ν™ˆνŽ˜μ΄μ§€
β”œβ”€β”€ components/              # μž¬μ‚¬μš© μ»΄ν¬λ„ŒνŠΈ
β”‚   β”œβ”€β”€ home/               # ν™ˆνŽ˜μ΄μ§€ μ„Ήμ…˜λ“€
β”‚   β”œβ”€β”€ portfolio/          # 포트폴리였 μ»΄ν¬λ„ŒνŠΈ
β”‚   β”œβ”€β”€ blog/               # λΈ”λ‘œκ·Έ μ»΄ν¬λ„ŒνŠΈ
β”‚   β”œβ”€β”€ common/             # 곡톡 μ»΄ν¬λ„ŒνŠΈ
β”‚   └── ui/                 # UI κΈ°λ³Έ μ»΄ν¬λ„ŒνŠΈ
β”œβ”€β”€ lib/                    # μœ ν‹Έλ¦¬ν‹° & μ„€μ •
β”‚   β”œβ”€β”€ notion/             # Notion API ν΄λΌμ΄μ–ΈνŠΈ
β”‚   β”œβ”€β”€ supabase/           # Supabase μ„€μ • & μŠ€ν‚€λ§ˆ
β”‚   └── utils.ts            # 곡톡 μœ ν‹Έλ¦¬ν‹°
β”œβ”€β”€ store/                  # Zustand μƒνƒœ 관리
β”œβ”€β”€ types/                  # TypeScript νƒ€μž… μ •μ˜
β”œβ”€β”€ hooks/                  # μ»€μŠ€ν…€ ν›…
└── docs/                   # ν”„λ‘œμ νŠΈ λ¬Έμ„œ

🎯 핡심 κΈ°λŠ₯ 상세

πŸ“Š Notion CMS 연동

// 포트폴리였 μžλ™ 동기화
const portfolios = await notionClient.getPortfolios({
  filter: { tech: 'React' },
  sort: 'created_time',
});

// λΈ”λ‘œκ·Έ 포슀트 μ‹€μ‹œκ°„ μ—…λ°μ΄νŠΈ
const posts = await notionClient.getBlogPosts({
  category: 'Development',
  published: true,
});

πŸ’¬ ν•˜μ΄λΈŒλ¦¬λ“œ λŒ“κΈ€ μ‹œμŠ€ν…œ

// μ‹œμŠ€ν…œ 선택 기반 λŒ“κΈ€ λ Œλ”λ§
<Comments slug="blog-post-1" title="포슀트 제λͺ©">
  {/* GitHub μ‚¬μš©μž: Giscus */}
  {/* 일반 μ‚¬μš©μž: Supabase + 이메일 */}
</Comments>

// μ‹€μ‹œκ°„ λŒ“κΈ€ ꡬ독
const unsubscribe = commentService.subscribeToComments(
  postSlug,
  (payload) => setComments(payload.new)
);

🎨 μ• λ‹ˆλ©”μ΄μ…˜ μ‹œμŠ€ν…œ

// GSAP 타이핑 μ• λ‹ˆλ©”μ΄μ…˜
gsap.to('.typing-text', {
  text: 'Full-Stack Developer',
  duration: 2,
  ease: 'none',
});

// 슀크둀 트리거 μ• λ‹ˆλ©”μ΄μ…˜
ScrollTrigger.create({
  trigger: '.portfolio-section',
  start: 'top 80%',
  animation: gsap.from('.portfolio-card', {
    y: 100,
    opacity: 0,
    stagger: 0.2,
  }),
});

πŸ”§ 개발 κ°€μ΄λ“œ

μƒˆλ‘œμš΄ 포트폴리였 μΆ”κ°€

  1. Notion Database에 μƒˆ νŽ˜μ΄μ§€ 생성
  2. ν•„μˆ˜ 속성 μž…λ ₯ (제λͺ©, κΈ°μˆ μŠ€νƒ, 링크 λ“±)
  3. μžλ™μœΌλ‘œ μ‚¬μ΄νŠΈμ— 반영 ✨

λΈ”λ‘œκ·Έ 포슀트 μž‘μ„±

  1. Notionμ—μ„œ μƒˆ νŽ˜μ΄μ§€ 생성
  2. published: true μ²΄ν¬λ°•μŠ€ ν™œμ„±ν™”
  3. μ‹€μ‹œκ°„μœΌλ‘œ λΈ”λ‘œκ·Έμ— κ²Œμ‹œ πŸ“

λŒ“κΈ€ μ‹œμŠ€ν…œ 관리

-- λŒ“κΈ€ 승인 (κ΄€λ¦¬μž)
SELECT approve_comment('comment-uuid');

-- 슀팸 λŒ“κΈ€ μ‚­μ œ
SELECT delete_comment('comment-uuid');

-- 톡계 쑰회
SELECT * FROM comment_stats WHERE post_slug = 'blog-post';

πŸ“ˆ μ„±λŠ₯ & SEO

μ„±λŠ₯ μ΅œμ ν™”

  • ⚑ 이미지 μ΅œμ ν™”: Next.js Image + WebP
  • πŸš€ μ½”λ“œ λΆ„ν• : Dynamic Imports
  • πŸ“¦ λ²ˆλ“€ μ΅œμ ν™”: Tree Shaking
  • 🎯 캐싱 μ „λž΅: ISR + SWR

SEO μ΅œμ ν™”

  • πŸ“Š κ΅¬μ‘°ν™”λœ 데이터: JSON-LD
  • 🏷️ 메타 νƒœκ·Έ: Open Graph, Twitter Card
  • πŸ—ΊοΈ μ‚¬μ΄νŠΈλ§΅: μžλ™ 생성
  • πŸ€– robots.txt: 크둀링 μ΅œμ ν™”

μ ‘κ·Όμ„±

  • β™Ώ WCAG 2.2 AA μ€€μˆ˜
  • ⌨️ ν‚€λ³΄λ“œ λ„€λΉ„κ²Œμ΄μ…˜ 지원
  • πŸ“± 슀크린 리더 μ΅œμ ν™”
  • 🎨 색상 λŒ€λΉ„ 4.5:1 이상

πŸ§ͺ ν…ŒμŠ€νŠΈ

λŒ“κΈ€ μ‹œμŠ€ν…œ ν…ŒμŠ€νŠΈ

# ν…ŒμŠ€νŠΈ νŽ˜μ΄μ§€ 접속
http://localhost:3000/test-comments

# API ν…ŒμŠ€νŠΈ
curl -X GET "http://localhost:3000/api/comments?slug=test-post"
curl -X POST "http://localhost:3000/api/comments" \
  -H "Content-Type: application/json" \
  -d '{"post_slug":"test","author_name":"ν…ŒμŠ€ν„°","author_email":"[email protected]","content":"ν…ŒμŠ€νŠΈ λŒ“κΈ€"}'

πŸš€ 배포

Vercel 배포

# Vercel CLI μ„€μΉ˜
npm i -g vercel

# ν”„λ‘œμ νŠΈ 배포
vercel --prod

# ν™˜κ²½ λ³€μˆ˜ μ„€μ •
vercel env add NOTION_API_KEY
vercel env add NEXT_PUBLIC_SUPABASE_URL

도메인 μ—°κ²°

  1. Vercel Dashboardμ—μ„œ 도메인 μΆ”κ°€
  2. DNS μ„€μ • (A λ ˆμ½”λ“œ/CNAME)
  3. SSL μΈμ¦μ„œ μžλ™ λ°œκΈ‰ πŸ”’

πŸ“š API λ¬Έμ„œ

λŒ“κΈ€ API

// λŒ“κΈ€ λͺ©λ‘ 쑰회
GET /api/comments?slug=post-slug

// λŒ“κΈ€ μž‘μ„±
POST /api/comments
{
  "post_slug": "string",
  "author_name": "string",
  "author_email": "string",
  "content": "string",
  "reply_to": "uuid" // 선택사항
}

// μ’‹μ•„μš” ν† κΈ€
POST /api/comments/[id]/like

// λŒ“κΈ€ 톡계
GET /api/comments/custom-stats?slug=post-slug

πŸ“ž μ—°λ½μ²˜


πŸ“„ λΌμ΄μ„ μŠ€

MIT License - μžμ„Έν•œ λ‚΄μš©μ€ LICENSE νŒŒμΌμ„ μ°Έμ‘°ν•˜μ„Έμš”.


Releases

No releases published

Packages

 
 
 

Contributors