๐ŸŽจ 3๋‹จ๊ณ„ : ์˜จ๋ณด๋”ฉ ๋„๋ฉ”์ธ ํ…Œํฌ์ŠคํŽ™ - 100-hours-a-week/7-team-ddb-wiki GitHub Wiki

๋ฌธ์„œ ๊ด€๋ฆฌ

์ž‘์„ฑ์ผ 2025-05-30
๋ฒ„์ „ 1.1
์ž‘์„ฑ์ž suzy.kang (๊ฐ•์ˆ˜์ง€)
๊ฒ€ํ† ์ž kevin
์ƒํƒœ ์™„๋ฃŒ

๋ณ€๊ฒฝ ์ด๋ ฅ

๋ฒ„์ „ ๋‚ ์งœ ์ž‘์„ฑ์ž ๊ฒ€ํ† ์ž ๋ณ€๊ฒฝ๋‚ด์šฉ
1.0 2025-04-26 suzy kevin ์ดˆ์•ˆ
1.1 2025-05-30 suzy kevin MVP ๊ฐœ๋ฐœ ์ดํ›„ ๋ฌธ์„œ ๋™๊ธฐํ™”

๋ฐฐ๊ฒฝ (Background)

ํ”„๋กœ์ ํŠธ ๋ชฉํ‘œ (Objective)

  • ์„œ๋น„์Šค์˜ ํ•ต์‹ฌ ๊ฐ€์น˜์™€ ๊ธฐ๋Šฅ์„ ํšจ๊ณผ์ ์œผ๋กœ ์†Œ๊ฐœ
  • ์ง๊ด€์ ์ด๊ณ  ๋งค๋ ฅ์ ์ธ ์˜จ๋ณด๋”ฉ UI/UX ์ œ๊ณต
  • ์นด์นด์˜ค ์†Œ์…œ ๋กœ๊ทธ์ธ์œผ๋กœ์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ์œ ๋„

๋ชฉํ‘œ๊ฐ€ ์•„๋‹Œ ๊ฒƒ (Non-goals)

  • ๋‹ค๊ตญ์–ด ์ง€์›
  • ์ƒ์„ธํ•œ ์„œ๋น„์Šค ์ด์šฉ ๋ฐฉ๋ฒ• ์„ค๋ช…
  • ๋ณต์žกํ•œ ์ธํ„ฐ๋ž™์…˜์ด๋‚˜ ์• ๋‹ˆ๋ฉ”์ด์…˜

์„ค๊ณ„ ๋ฐ ๊ธฐ์ˆ  ์ž๋ฃŒ (Architecture and Technical Documentation)

์•„ํ‚คํ…์ฒ˜ ๊ฐœ์š” (Architecture Overview)

ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • Next.js (v15.3.0) + React (v19.1.0)
    • App Router ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…
    • SSR/ISR ํ™œ์šฉ์œผ๋กœ SEO ์ตœ์ ํ™”
    • React 19์˜ use() ํ›… ํ™œ์šฉํ•œ ๋ฐ์ดํ„ฐ ํŽ˜์นญ

์• ๋‹ˆ๋ฉ”์ด์…˜

  • Framer Motion
    • ์Šค์™€์ดํ”„ ์ œ์Šค์ฒ˜ ์ง€์›
    • ๋ถ€๋“œ๋Ÿฌ์šด ํŽ˜์ด์ง€ ์ „ํ™˜

UI/์Šคํƒ€์ผ๋ง

  • Tailwind CSS (v4.1)
    • ์œ ํ‹ธ๋ฆฌํ‹ฐ ํผ์ŠคํŠธ ์ ‘๊ทผ์œผ๋กœ ๋น ๋ฅธ ๊ฐœ๋ฐœ
    • ์ปค์Šคํ…€ ํ…Œ๋งˆ๋กœ ๋ธŒ๋žœ๋“œ ๋””์ž์ธ ์‹œ์Šคํ…œ ๊ตฌ์ถ•
  • shadcn/ui
    • Tailwind ๊ธฐ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ
    • ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋งŒ ๊ฐ€์ ธ์™€ ๋ฒˆ๋“ค ํฌ๊ธฐ ์ตœ์ ํ™”

์ด๋ฏธ์ง€ ์ตœ์ ํ™”

  • Next.js Image Component
    • ์ž๋™ ์ด๋ฏธ์ง€ ์ตœ์ ํ™”
    • priority ์†์„ฑ์œผ๋กœ ์ค‘์š” ์ด๋ฏธ์ง€ ์šฐ์„  ๋กœ๋”ฉ

ํด๋” ๊ตฌ์กฐ

src/
โ”œโ”€โ”€ app/(auth)/onboarding/
โ”‚   โ””โ”€โ”€ page.tsx              # ์˜จ๋ณด๋”ฉ ํŽ˜์ด์ง€
โ””โ”€โ”€ features/onboarding/
    โ”œโ”€โ”€ components/           # UI ์ปดํฌ๋„ŒํŠธ
    โ”‚   โ”œโ”€โ”€ dolpin-logo/
    โ”‚   โ”œโ”€โ”€ kakao-login-button/
    โ”‚   โ””โ”€โ”€ onboarding-slider/
    โ”‚       โ”œโ”€โ”€ OnboardingSlider.tsx
    โ”‚       โ”œโ”€โ”€ OnboardingSlide.tsx
    โ”‚       โ””โ”€โ”€ SlideIndicator.tsx
    โ””โ”€โ”€ constants/           # ์ƒ์ˆ˜
        โ””โ”€โ”€ slides.ts        # ์Šฌ๋ผ์ด๋“œ ๋ฐ์ดํ„ฐ

์ฃผ์š” ํŽ˜์ด์ง€

/onboarding : ์˜จ๋ณด๋”ฉ ํŽ˜์ด์ง€

  • ๊ตฌํ˜„๋œ ๊ธฐ๋Šฅ:
    • 4๊ฐœ์˜ ์˜จ๋ณด๋”ฉ ์Šฌ๋ผ์ด๋“œ
    • ์Šค์™€์ดํ”„ ์ œ์Šค์ฒ˜ ์ง€์›
    • ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ
    • ์Šฌ๋ผ์ด๋“œ ์ธ๋””์ผ€์ดํ„ฐ
  • ์‚ฌ์šฉ ์ปดํฌ๋„ŒํŠธ:
    • DolpinLogo - ๋Œํ•€ ๋กœ๊ณ 
    • OnboardingSlider - ์Šฌ๋ผ์ด๋“œ ์ปจํ…Œ์ด๋„ˆ
    • KakaoLoginButton - ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ
  • ๋ ˆ์ด์•„์›ƒ:
    • ๋กœ๊ณ : ์™ผ์ชฝ ์ƒ๋‹จ ๊ณ ์ •
    • ์Šฌ๋ผ์ด๋”: ์ค‘์•™ ๋ฐฐ์น˜
    • ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ: ํ•˜๋‹จ ๊ณ ์ •

๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ

OnboardingSlider : ์˜จ๋ณด๋”ฉ ์Šฌ๋ผ์ด๋“œ ์ปจํ…Œ์ด๋„ˆ

  • ์—ญํ• : ์˜จ๋ณด๋”ฉ ์Šฌ๋ผ์ด๋“œ๋“ค์„ ๊ด€๋ฆฌํ•˜๊ณ  ์Šค์™€์ดํ”„ ๊ธฐ๋Šฅ์„ ์ œ๊ณต

  • Props & Interface:

    interface OnboardingSliderProps {
      slides: {
        imageUrl: string;
        title: string;
        description: string;
      }[];
    }
  • ๊ธฐ๋Šฅ:

    • ์Šค์™€์ดํ”„ ์ œ์Šค์ฒ˜ (๋“œ๋ž˜๊ทธ)
    • ์Šคํ”„๋ง ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ „ํ™˜
    • ๋ฐฉํ–ฅ ๊ฐ์ง€ (์™ผ์ชฝ/์˜ค๋ฅธ์ชฝ)
    • ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ (์ฒซ/๋งˆ์ง€๋ง‰ ์Šฌ๋ผ์ด๋“œ)
  • ์ƒํƒœ ๊ด€๋ฆฌ:

    • activeIndex: ํ˜„์žฌ ํ™œ์„ฑ ์Šฌ๋ผ์ด๋“œ
    • direction: ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐฉํ–ฅ
  • ์• ๋‹ˆ๋ฉ”์ด์…˜:

    • Framer Motion ์‚ฌ์šฉ
    • enter/center/exit ์ƒํƒœ
    • ์Šคํ”„๋ง ํšจ๊ณผ (stiffness: 300, damping: 30)

OnboardingSlide : ๊ฐœ๋ณ„ ์˜จ๋ณด๋”ฉ ์Šฌ๋ผ์ด๋“œ

  • ์—ญํ• : ๊ฐ ์˜จ๋ณด๋”ฉ ๋‹จ๊ณ„์˜ ์ด๋ฏธ์ง€์™€ ํ…์ŠคํŠธ๋ฅผ ํ‘œ์‹œ

  • Props & Interface:

    interface OnboardingSlideProps {
      imageUrl: string;
      title: string;
      description: string;
    }
  • ๊ธฐ๋Šฅ:

    • ์ด๋ฏธ์ง€ ํ‘œ์‹œ
    • ์ œ๋ชฉ ๋ฐ ์„ค๋ช… ํ…์ŠคํŠธ
    • ๋ฐ˜์‘ํ˜• ๋ ˆ์ด์•„์›ƒ
  • ์Šคํƒ€์ผ๋ง:

    • ํ…์ŠคํŠธ ์ค‘์•™ ์ •๋ ฌ
    • ๋ผ์ธ ๋ธŒ๋ ˆ์ดํฌ ์ง€์› (\n)
    • ์ด๋ฏธ์ง€: 256px ๋†’์ด, ์ „์ฒด ๋„ˆ๋น„
    • ๋‘ฅ๊ทผ ๋ชจ์„œ๋ฆฌ (rounded-md)
    • ์—ฌ๋ฐฑ: mb-6 (์ด๋ฏธ์ง€), mb-5 (์ œ๋ชฉ)

SlideIndicator : ์Šฌ๋ผ์ด๋“œ ์ธ๋””์ผ€์ดํ„ฐ

  • ์—ญํ• : ํ˜„์žฌ ์Šฌ๋ผ์ด๋“œ ์œ„์น˜๋ฅผ ๋„ํŠธ๋กœ ํ‘œ์‹œ

  • Props & Interface:

    interface SlideIndicatorProps {
      total: number;
      active: number;
    }
  • ๊ธฐ๋Šฅ:

    • ์ „์ฒด ์Šฌ๋ผ์ด๋“œ ์ˆ˜๋งŒํผ ๋„ํŠธ ํ‘œ์‹œ
    • ํ™œ์„ฑ ๋„ํŠธ ํ•˜์ด๋ผ์ดํŠธ
  • ์Šคํƒ€์ผ๋ง:

    • ๋„ํŠธ ํฌ๊ธฐ: 8x8px
    • ํ™œ์„ฑ ์ƒํƒœ: ์ง„ํ•œ ์ƒ‰์ƒ + ๋„ˆ๋น„ 16px
    • ๋น„ํ™œ์„ฑ ์ƒํƒœ: ์—ฐํ•œ ์ƒ‰์ƒ
    • ํŠธ๋žœ์ง€์…˜: 300ms

KakaoLoginButton : ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ

  • ์—ญํ• : ์นด์นด์˜ค ๋กœ๊ทธ์ธ API ํ˜ธ์ถœ ๋ฐ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์ฒ˜๋ฆฌ
  • ๊ธฐ๋Šฅ:
    • OAuth ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ URL ํš๋“
    • ์นด์นด์˜ค ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™
    • ๋กœ๋”ฉ ์ค‘ ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™”
  • ์ƒํƒœ ๊ด€๋ฆฌ:
    • redirectUrl: OAuth URL ์ƒํƒœ
    • useEffect๋กœ ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ URL ํš๋“
  • ์Šคํƒ€์ผ๋ง:
    • ์นด์นด์˜ค ์‹ฌ๋ณผ + ํ…์ŠคํŠธ
    • ํ™”์‚ดํ‘œ ์•„์ด์ฝ˜
    • ์ „์ฒด ๋„ˆ๋น„ ๋ฒ„ํŠผ

DolpinLogo : ๋Œํ•€ ๋กœ๊ณ 

  • ์—ญํ• : ์„œ๋น„์Šค ๋กœ๊ณ  ํ‘œ์‹œ
  • ๊ธฐ๋Šฅ:
    • SVG ๋กœ๊ณ  ํ‘œ์‹œ
    • priority ๋กœ๋”ฉ
  • ์Šคํƒ€์ผ๋ง:
    • ํฌ๊ธฐ: 120x120px
    • ์œ„์น˜: ์™ผ์ชฝ ์ƒ๋‹จ ๊ณ ์ •

์˜จ๋ณด๋”ฉ ์Šฌ๋ผ์ด๋“œ ๋ฐ์ดํ„ฐ

export const slides = [
  {
    imageUrl: '/img/onboarding-1.png',
    title: '์ผ์ƒ์„ ํƒํ—˜ํ•˜๋“ฏ ๊ธฐ๋กํ•˜์„ธ์š”',
    description:
      '๋งค์ผ ๊ฑท๋Š” ๊ฑฐ๋ฆฌ๋„ ๊ฒŒ์ž„์ฒ˜๋Ÿผ, \n ๋‹น์‹ ์˜ ๋ฐœ์ž์ทจ๋ฅผ ๋”ฐ๋ผ \n ๋‚˜๋งŒ์˜ ์ด์•ผ๊ธฐ ์ง€๋„๋ฅผ ๋งŒ๋“ค์–ด๋ณด์„ธ์š”.',
  },
  {
    imageUrl: '/img/onboarding-2.png',
    title: '๋‚ด ์œ„์น˜, ๋‚ด ๊ธฐ๋ก์œผ๋กœ ์™„์„ฑ๋˜๋Š” ์ถ”์ฒœ',
    description:
      '์ง€๊ธˆ ์ด๊ณณ๊ณผ ์ง€๋‚œ ๋‚˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ \n ๋”ฑ ๋งž๋Š” ์žฅ์†Œ๋ฅผ ์ถ”์ฒœํ•ด๋“œ๋ฆฝ๋‹ˆ๋‹ค.',
  },
  {
    imageUrl: '/img/onboarding-3.png',
    title: '๊ฒ€์ƒ‰ํ•˜๋Š” ๋‹จ์–ด์—๋„ ์˜๋ฏธ๋ฅผ ๋‹ด์•„',
    description: '๋‹น์‹ ์ด ์›ํ•˜๋Š” ์žฅ์†Œ,\n  ์ง€๊ธˆ ๊ฐ€์žฅ ์–ด์šธ๋ฆฌ๋Š”๊ณต๊ฐ„์„  ์ฐพ์•„๋“œ๋ ค์š”.',
  },
  {
    imageUrl: '/img/onboarding-4.png',
    title: 'ํ•€ ํ•˜๋‚˜๋กœ, ํ•˜๋ฃจ๋ฅผ ๊ธฐ๋กํ•˜์„ธ์š”',
    description:
      'ํ˜„์žฌ ์œ„์น˜์— ํ•€์„ ์ฐ๊ณ  \n ๊ทธ ์ˆœ๊ฐ„์˜ ๊ฐ์ •๊ณผ ๊ธฐ์–ต์„ \n ๊ธฐ๋ก์œผ๋กœ ๋‚จ๊ฒจ๋ณด์„ธ์š”.',
  },
];

์ƒํƒœ ๊ด€๋ฆฌ

Local State (React useState)

  • OnboardingSlider:
    • activeIndex: ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ ์Šฌ๋ผ์ด๋“œ ์ธ๋ฑ์Šค
    • direction: ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐฉํ–ฅ (-1, 0, 1)
  • KakaoLoginButton:
    • redirectUrl: OAuth ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ URL

API ์—ฐ๋™

๊ตฌํ˜„๋œ API

  • GET /api/v1/auth/oauth - OAuth ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ URL ํš๋“

API ํ˜ธ์ถœ ์˜ˆ์‹œ

// ์นด์นด์˜ค ๋กœ๊ทธ์ธ URL ํš๋“
const { redirect_url } = await getOAuthRedirectUrl();
window.location.href = redirect_url;

์‚ฌ์šฉ์ž ํ”Œ๋กœ์šฐ

  1. ์˜จ๋ณด๋”ฉ ์ง„์ž…

    • 4๊ฐœ์˜ ์Šฌ๋ผ์ด๋“œ ์ž๋™ ํ‘œ์‹œ
    • ์ฒซ ๋ฒˆ์งธ ์Šฌ๋ผ์ด๋“œ๋ถ€ํ„ฐ ์‹œ์ž‘
  2. ์Šฌ๋ผ์ด๋“œ ํƒ์ƒ‰

    • ์ขŒ์šฐ ์Šค์™€์ดํ”„๋กœ ์ด๋™
    • ์ธ๋””์ผ€์ดํ„ฐ๋กœ ํ˜„์žฌ ์œ„์น˜ ํ™•์ธ
  3. ๋กœ๊ทธ์ธ

    • ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญ
    • ์นด์นด์˜ค ์ธ์ฆ ํŽ˜์ด์ง€๋กœ ์ด๋™
    • ์ธ์ฆ ์™„๋ฃŒ ํ›„ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ

์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒ์„ธ

์Šฌ๋ผ์ด๋“œ ์ „ํ™˜

const variants = {
  enter: (direction) => ({
    x: direction > 0 ? 300 : -300,
    opacity: 0,
    position: 'absolute',
  }),
  center: {
    x: 0,
    opacity: 1,
    position: 'relative',
  },
  exit: (direction) => ({
    x: direction < 0 ? 300 : -300,
    opacity: 0,
    position: 'absolute',
  }),
};

๋“œ๋ž˜๊ทธ ์„ค์ •

  • dragConstraints: ์ขŒ์šฐ ์ œํ•œ
  • dragElastic: 0.2 (ํƒ„์„ฑ)
  • ์ž„๊ณ„๊ฐ’: 100px ๋˜๋Š” 500 velocity

์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ ์˜ˆ์‹œ

OnboardingSlider ์‚ฌ์šฉ

import { slides } from '@/features/onboarding';

<OnboardingSlider slides={slides} />;

๊ฐœ๋ณ„ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ

// ์Šฌ๋ผ์ด๋“œ
<OnboardingSlide
  imageUrl="/img/onboarding-1.png"
  title="์ผ์ƒ์„ ํƒํ—˜ํ•˜๋“ฏ ๊ธฐ๋กํ•˜์„ธ์š”"
  description="๋งค์ผ ๊ฑท๋Š” ๊ฑฐ๋ฆฌ๋„ ๊ฒŒ์ž„์ฒ˜๋Ÿผ..."
/>

// ์ธ๋””์ผ€์ดํ„ฐ
<SlideIndicator total={4} active={0} />

// ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ
<Suspense>
  <KakaoLoginButton />
</Suspense>

// ๋กœ๊ณ 
<DolpinLogo />

ํŽ˜์ด์ง€ ๋ ˆ์ด์•„์›ƒ

<div className="relative min-h-screen bg-white">
  <div className="absolute left-2 top-0 z-10">
    <DolpinLogo />
  </div>
  <div className="flex min-h-screen flex-col items-center justify-center pt-20">
    <OnboardingSlider slides={slides} />
    <div className="mt-8 w-full max-w-md px-4">
      <Suspense>
        <KakaoLoginButton />
      </Suspense>
    </div>
  </div>
</div>

์ปดํฌ๋„ŒํŠธ ๊ฐ„ ๊ด€๊ณ„

graph TD
    A[Onboarding Page] --> B[DolpinLogo]
    A --> C[OnboardingSlider]
    A --> D[KakaoLoginButton]
    C --> E[OnboardingSlide]
    C --> F[SlideIndicator]
    C --> G[Framer Motion]
    D --> H[getOAuthRedirectUrl API]
Loading

์ฃผ์š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์ƒ์„ธ

์Šค์™€์ดํ”„ ์ œ์Šค์ฒ˜

<motion.div
  drag="x"
  dragConstraints={{ left: 0, right: 0 }}
  dragElastic={0.2}
  onDragEnd={(e, info) => {
    const offsetX = info.offset.x;
    const velocityX = info.velocity.x;

    if (offsetX < -100 || velocityX < -500) {
      paginate(1); // ๋‹ค์Œ ์Šฌ๋ผ์ด๋“œ
    } else if (offsetX > 100 || velocityX > 500) {
      paginate(-1); // ์ด์ „ ์Šฌ๋ผ์ด๋“œ
    }
  }}
/>

OAuth ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์ฒ˜๋ฆฌ

useEffect(() => {
  const handleRedirect = async () => {
    const { redirect_url } = await getOAuthRedirectUrl();
    setRedirectUrl(redirect_url);
  };
  handleRedirect();
}, []);

์„ฑ๋Šฅ ์ตœ์ ํ™”

  • ์ด๋ฏธ์ง€ ์ตœ์ ํ™”
    • Next.js Image ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ
    • priority ์†์„ฑ์œผ๋กœ ๋กœ๊ณ  ์šฐ์„  ๋กœ๋”ฉ
  • ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ตœ์ ํ™”
    • GPU ๊ฐ€์† ์‚ฌ์šฉ (transform)
    • will-change ์†์„ฑ ํ™œ์šฉ
  • ๋ฒˆ๋“ค ํฌ๊ธฐ
    • Framer Motion ํŠธ๋ฆฌ ์‰์ดํ‚น

์ ‘๊ทผ์„ฑ

  • ์ด๋ฏธ์ง€ ๋Œ€์ฒด ํ…์ŠคํŠธ
    • ๋ชจ๋“  ์ด๋ฏธ์ง€์— alt ์†์„ฑ
  • ๋ฒ„ํŠผ
    • ์ ์ ˆํ•œ ํด๋ฆญ ์˜์—ญ
    • ์‹œ๊ฐ์  ํ”ผ๋“œ๋ฐฑ

์—๋Ÿฌ ์ฒ˜๋ฆฌ

OAuth URL ํš๋“ ์‹คํŒจ

  • ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™” ์œ ์ง€ (ํ–ฅํ›„)
  • ์ฝ˜์†” ์—๋Ÿฌ ๋กœ๊น…

์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ

  • Next.js ๊ธฐ๋ณธ ์—๋Ÿฌ ์ฒ˜๋ฆฌ
  • ๋Œ€์ฒด ์ด๋ฏธ์ง€ ๊ณ ๋ ค (ํ–ฅํ›„)

๋ชจ๋ฐ”์ผ ์ตœ์ ํ™”

๋ทฐํฌํŠธ ์„ค์ •

  • min-height: 100svh ์‚ฌ์šฉ
  • ์•ˆ์ „ ์˜์—ญ ๊ณ ๋ ค
  • ๋ฐ˜์‘ํ˜• ํฐํŠธ ํฌ๊ธฐ

์ด๋ฏธ์ง€ ์ตœ์ ํ™”

  • ๋ชจ๋ฐ”์ผ ํ•ด์ƒ๋„๋ณ„ ์ด๋ฏธ์ง€
  • WebP ํฌ๋งท ์ง€์›
  • ์ ์ ˆํ•œ sizes ์†์„ฑ

๊ธฐ์ˆ ์  ๊ฒฐ์ •์‚ฌํ•ญ

Framer Motion ์„ ํƒ ์ด์œ 

  • React Native ์Šคํƒ€์ผ ์ œ์Šค์ฒ˜
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”
  • ์„ ์–ธ์  API

SSG ์‚ฌ์šฉ

  • ์ •์  ์ฝ˜ํ…์ธ ๋กœ ๋น ๋ฅธ ๋กœ๋”ฉ
  • ์ด๋ฏธ์ง€ ์‚ฌ์ „ ์ตœ์ ํ™”
  • CDN ์บ์‹ฑ ํ™œ์šฉ

Suspense ์‚ฌ์šฉ

  • ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ์ง€์—ฐ ๋กœ๋”ฉ
  • ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ๊ฐœ์„ 
  • ์—๋Ÿฌ ๋ฐ”์šด๋”๋ฆฌ ํ™œ์šฉ

์š”์•ฝ

ํ•ต์‹ฌ ํŠน์ง•

  • ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ธ UI
  • ๋ถ€๋“œ๋Ÿฌ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜
  • ๋น ๋ฅธ ๋กœ๋”ฉ (SSG)
  • ๋ชจ๋ฐ”์ผ ์ตœ์ ํ™”

๊ฐœ์„  ๊ฐ€๋Šฅ ์˜์—ญ

  • ์ ‘๊ทผ์„ฑ ๊ฐ•ํ™”
  • ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง

์ฐธ๊ณ  ์ž๋ฃŒ

โš ๏ธ **GitHub.com Fallback** โš ๏ธ