Next.js 15 App Router 기반 포트폴리오 + 자체 Admin CMS. 3-layer 디자인 토큰, GSAP 수평 스크롤, Supabase 인증/DB까지 직접 구축.
프론트엔드 개발자로서 기술 역량을 직접 증명하기 위해 만든 포트폴리오 사이트입니다. 외부 CMS(Contentful, Sanity) 없이 Supabase + 자체 Admin 대시보드를 구축하여 콘텐츠를 직접 관리합니다.
핵심 아키텍처:
• 3-layer 디자인 토큰 시스템 (Raw → Semantic → Context) — 테마 전환 시 CSS Custom Properties만 교체하면 전체 UI가 반응
• Server/Client Component 분리 — 데이터 fetch는 서버, 인터랙션은 클라이언트로 명확히 분리
• Admin CRUD — Posts/Works/Profile/Settings를 탭 기반 UI로 편집, Supabase RLS로 인증 보호
• GSAP ScrollTrigger + Lenis — 데스크톱에서는 수평 스크롤 갤러리, 모바일(≤1024px)에서는 수직 스택으로 자동 전환
CSS Specificity 충돌 — globals/_base.css의 html[data-theme-ready] * 전환 규칙이 specificity (0,1,1)로, 컴포넌트 단일 클래스 (0,1,0)의 transition을 완전히 덮어씌움. max-height, transform 등의 애니메이션이 작동하지 않는 원인을 추적하는 데 시간이 걸렸습니다.
GSAP 수평 스크롤 + Lenis 통합 — ScrollTrigger의 pin과 Lenis의 smooth scroll이 서로의 스크롤 위치 계산을 간섭. 리사이즈 시 레이아웃이 깨지는 문제도 있었습니다.
Markdown 에디터 스크롤 동기화 — 에디터 패널과 프리뷰 패널의 스크롤 위치를 비율 기반으로 동기화할 때, 이미지가 포함된 프리뷰의 높이가 동적으로 변해 정확한 매핑이 어려웠습니다.
복합 셀렉터로 specificity 상승 — .parent .child 패턴 (0,2,0)을 적용하여 글로벌 규칙을 override. 이후 모든 컴포넌트 transition에 동일 컨벤션을 적용하고 MEMORY에 기록.
Lenis의 setInfinite(false) + GSAP onRefresh 콜백 — 페이지 진입 시 infinite scroll을 비활성화하고, resize 이벤트에서 ScrollTrigger.refresh()와 Lenis.resize()를 순차 호출하여 동기화.
scrollHeight 비율 매핑 + ResizeObserver — 프리뷰 패널에 ResizeObserver를 걸어 높이 변화를 감지하고, scrollTop / scrollHeight 비율을 실시간 재계산. requestAnimationFrame으로 스크롤 이벤트를 throttle 처리.