초보자 FAQ - "이건 어디서 설정해?" 모든 질문 해결
Provides a comprehensive FAQ guide for configuring common Next.js project settings. Use when users ask where to find specific configuration files or how to change common settings like colors, fonts, API keys, or add new pages.
/plugin marketplace add johunsang/kreatsaas/plugin install kreatsaas@kreatsaas-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
"이건 어디서 설정해?" 모든 질문에 대한 답변
| 질문 | 파일 위치 |
|---|---|
| API 키 설정 | .env.local |
| 색상 변경 | tailwind.config.ts |
| 폰트 변경 | src/app/layout.tsx |
| 로고 변경 | public/logo.png |
| 페이지 제목 변경 | src/app/layout.tsx |
| 결제 설정 | .env.local + src/lib/stripe.ts |
| 데이터베이스 연결 | .env.local + prisma/schema.prisma |
| 로그인 설정 | src/lib/auth.ts |
| 메뉴 추가 | src/components/Navigation.tsx |
| 새 페이지 추가 | src/app/[페이지명]/page.tsx |
질문: "OpenAI API 키는 어디에 넣어?"
위치: .env.local (프로젝트 루트)
# .env.local
# AI 서비스
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxx
# 결제
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxx
STRIPE_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxx
# 데이터베이스
DATABASE_URL=postgresql://user:password@host:5432/db
# 인증
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key-here
# 소셜 로그인
GOOGLE_CLIENT_ID=xxxxxxxxxxxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxxxxxxxxxxxxxxx
# 스토리지
CLOUDFLARE_R2_ACCESS_KEY=xxxxxxxxxxxxx
CLOUDFLARE_R2_SECRET_KEY=xxxxxxxxxxxxx
CLOUDFLARE_R2_BUCKET=my-bucket
주의사항:
.env.local은 git에 올리면 안 됨 (.gitignore에 포함되어 있음)NEXT_PUBLIC_ 접두사가 붙은 것만 브라우저에서 접근 가능질문: "메인 색상을 파란색에서 초록색으로 바꾸고 싶어"
위치: tailwind.config.ts
// tailwind.config.ts
import type { Config } from 'tailwindcss';
const config: Config = {
theme: {
extend: {
colors: {
// 여기서 색상 변경!
primary: {
50: '#f0fdf4', // 가장 밝은
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e', // 메인 색상
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d', // 가장 어두운
},
},
},
},
};
export default config;
색상 팔레트 생성 도구:
질문: "글꼴을 바꾸고 싶어"
위치: src/app/layout.tsx
// src/app/layout.tsx
// 방법 1: Google Fonts 사용 (권장)
import { Noto_Sans_KR, Inter } from 'next/font/google';
const notoSansKR = Noto_Sans_KR({
subsets: ['latin'],
weight: ['400', '500', '700'],
variable: '--font-noto',
});
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
});
export default function RootLayout({ children }) {
return (
<html lang="ko" className={`${notoSansKR.variable} ${inter.variable}`}>
<body className="font-noto">
{children}
</body>
</html>
);
}
// tailwind.config.ts
module.exports = {
theme: {
extend: {
fontFamily: {
noto: ['var(--font-noto)', 'sans-serif'],
inter: ['var(--font-inter)', 'sans-serif'],
},
},
},
};
인기 한글 폰트:
Noto_Sans_KR - 가독성 좋음Pretendard - 모던함Spoqa_Han_Sans_Neo - 깔끔함질문: "로고를 바꾸고 싶어"
위치:
public/logo.png - 메인 로고public/logo-dark.png - 다크모드 로고public/favicon.ico - 브라우저 탭 아이콘// src/components/Logo.tsx
import Image from 'next/image';
export function Logo() {
return (
<Image
src="/logo.png" // ← 이 파일 교체
alt="MySaaS Logo"
width={120}
height={40}
priority
/>
);
}
파비콘 생성:
public/ 폴더에 복사질문: "브라우저 탭에 뜨는 제목을 바꾸고 싶어"
위치: src/app/layout.tsx (전체) 또는 각 페이지의 page.tsx
// src/app/layout.tsx - 전체 사이트 기본값
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: {
default: 'MySaaS - 서비스 설명', // 기본 제목
template: '%s | MySaaS', // 페이지별 제목 템플릿
},
description: '서비스 설명 150자 이내',
};
// src/app/pricing/page.tsx - 개별 페이지
export const metadata: Metadata = {
title: '요금제', // → "요금제 | MySaaS" 로 표시됨
description: '다양한 요금제를 확인하세요',
};
질문: "새 페이지를 만들고 싶어"
위치: src/app/[페이지명]/page.tsx
# 예: /about 페이지 만들기
mkdir src/app/about
touch src/app/about/page.tsx
// src/app/about/page.tsx
export const metadata = {
title: '소개',
description: '회사 소개 페이지',
};
export default function AboutPage() {
return (
<div className="container mx-auto py-8">
<h1 className="text-3xl font-bold">회사 소개</h1>
<p>내용...</p>
</div>
);
}
URL 구조:
src/app/page.tsx → /
src/app/about/page.tsx → /about
src/app/blog/page.tsx → /blog
src/app/blog/[slug]/page.tsx → /blog/hello-world (동적 라우트)
질문: "상단 네비게이션에 메뉴를 추가하고 싶어"
위치: src/components/Navigation.tsx 또는 src/components/Header.tsx
// src/components/Navigation.tsx
const menuItems = [
{ href: '/', label: '홈' },
{ href: '/features', label: '기능' },
{ href: '/pricing', label: '요금제' },
{ href: '/about', label: '소개' }, // ← 새 메뉴 추가
{ href: '/contact', label: '문의' }, // ← 새 메뉴 추가
];
export function Navigation() {
return (
<nav>
{menuItems.map((item) => (
<Link key={item.href} href={item.href}>
{item.label}
</Link>
))}
</nav>
);
}
질문: "구글 로그인을 추가하고 싶어"
위치:
.env.local - API 키src/lib/auth.ts - 설정Step 1: Google Cloud Console 설정
http://localhost:3000/api/auth/callback/googleStep 2: 환경변수 설정
# .env.local
GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxxxxxxxxxxxx
Step 3: auth.ts 설정
// src/lib/auth.ts
import GoogleProvider from 'next-auth/providers/google';
export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
// 다른 프로바이더 추가...
],
};
질문: "로그인 페이지 디자인을 바꾸고 싶어"
위치: src/app/(auth)/login/page.tsx
// src/app/(auth)/login/page.tsx
'use client';
import { signIn } from 'next-auth/react';
export default function LoginPage() {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="bg-white p-8 rounded-xl shadow-lg max-w-md w-full">
<h1 className="text-2xl font-bold text-center mb-6">로그인</h1>
<button
onClick={() => signIn('google', { callbackUrl: '/dashboard' })}
className="w-full bg-white border py-3 rounded-lg flex items-center justify-center gap-2"
>
<GoogleIcon />
Google로 로그인
</button>
<div className="my-4 text-center text-gray-500">또는</div>
<form>
<input
type="email"
placeholder="이메일"
className="w-full p-3 border rounded-lg mb-3"
/>
<input
type="password"
placeholder="비밀번호"
className="w-full p-3 border rounded-lg mb-4"
/>
<button className="w-full bg-primary-500 text-white py-3 rounded-lg">
이메일로 로그인
</button>
</form>
</div>
</div>
);
}
질문: "Stripe 결제를 연동하고 싶어"
위치:
.env.local - API 키src/lib/stripe.ts - Stripe 설정src/app/api/webhooks/stripe/route.ts - 웹훅Step 1: Stripe 대시보드 설정
Step 2: 환경변수
# .env.local
STRIPE_SECRET_KEY=sk_test_xxxxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxx
Step 3: 가격 설정
// src/config/pricing.ts
export const PLANS = {
free: {
name: '무료',
price: 0,
priceId: null,
features: ['기본 기능', '월 100회 사용'],
},
pro: {
name: '프로',
price: 9900,
priceId: 'price_xxxxxxxxxxxxx', // Stripe에서 생성한 Price ID
features: ['모든 기능', '무제한 사용', '우선 지원'],
},
};
질문: "구독 가격을 바꾸고 싶어"
위치:
src/config/pricing.ts// src/config/pricing.ts
export const PLANS = {
starter: {
name: '스타터',
price: 4900, // ← 가격 변경
monthlyPriceId: 'price_xxx',
yearlyPriceId: 'price_yyy',
yearlyPrice: 49000, // 연간 (2개월 할인)
},
pro: {
name: '프로',
price: 14900, // ← 가격 변경
monthlyPriceId: 'price_xxx',
yearlyPriceId: 'price_yyy',
yearlyPrice: 149000,
},
};
질문: "데이터베이스 연결은 어떻게 해?"
위치:
.env.local - 연결 URLprisma/schema.prisma - 스키마 정의Step 1: 데이터베이스 생성 (예: Supabase)
Step 2: 환경변수 설정
# .env.local
DATABASE_URL="postgresql://postgres:password@db.xxxxx.supabase.co:5432/postgres"
Step 3: Prisma 설정
# 마이그레이션 생성 및 적용
npx prisma migrate dev --name init
# DB에서 타입 생성
npx prisma generate
# DB 확인
npx prisma studio
질문: "새 테이블을 추가하고 싶어"
위치: prisma/schema.prisma
// prisma/schema.prisma
// 새 모델 추가
model Product {
id String @id @default(cuid())
name String
description String?
price Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userId String
user User @relation(fields: [userId], references: [id])
}
// User 모델에 관계 추가
model User {
// ... 기존 필드
products Product[]
}
# 마이그레이션 실행
npx prisma migrate dev --name add_products
# 타입 생성
npx prisma generate
질문: "이메일 발송은 어떻게 해?"
위치:
.env.local - API 키src/lib/email.ts - 이메일 설정Resend 사용 예시:
# .env.local
RESEND_API_KEY=re_xxxxxxxxxxxxx
// src/lib/email.ts
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendWelcomeEmail(email: string, name: string) {
await resend.emails.send({
from: 'MySaaS <noreply@mysaas.com>',
to: email,
subject: '환영합니다!',
html: `<p>안녕하세요 ${name}님, 가입을 환영합니다!</p>`,
});
}
이메일 템플릿 위치: src/emails/ 또는 src/lib/email-templates/
질문: "이미지 업로드는 어떻게 해?"
위치:
.env.local - 스토리지 키src/lib/storage.ts - 업로드 설정Cloudflare R2 예시:
# .env.local
CLOUDFLARE_R2_ACCESS_KEY=xxxxx
CLOUDFLARE_R2_SECRET_KEY=xxxxx
CLOUDFLARE_R2_BUCKET=my-bucket
CLOUDFLARE_R2_ENDPOINT=https://xxxxx.r2.cloudflarestorage.com
// src/lib/storage.ts
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
const s3 = new S3Client({
region: 'auto',
endpoint: process.env.CLOUDFLARE_R2_ENDPOINT,
credentials: {
accessKeyId: process.env.CLOUDFLARE_R2_ACCESS_KEY!,
secretAccessKey: process.env.CLOUDFLARE_R2_SECRET_KEY!,
},
});
export async function uploadFile(file: File): Promise<string> {
const key = `uploads/${Date.now()}-${file.name}`;
await s3.send(new PutObjectCommand({
Bucket: process.env.CLOUDFLARE_R2_BUCKET,
Key: key,
Body: Buffer.from(await file.arrayBuffer()),
ContentType: file.type,
}));
return `${process.env.CLOUDFLARE_R2_PUBLIC_URL}/${key}`;
}
원인:
.env.local 파일명이 틀림 (.env 아님!)NEXT_PUBLIC_ 없이 접근해결:
# 서버 재시작
npm run dev
원인:
page.tsx가 아님src/app/ 안이 아님확인:
✅ src/app/about/page.tsx → /about
❌ src/app/about/About.tsx → 404
❌ src/pages/about.tsx → 404 (App Router에서)
원인:
DATABASE_URL 형식 오류확인:
# 연결 테스트
npx prisma db push
원인:
로컬 테스트:
# Stripe CLI 설치 후
stripe listen --forward-to localhost:3000/api/webhooks/stripe
| 하고 싶은 것 | 파일 위치 |
|---|---|
| 메인 색상 변경 | tailwind.config.ts |
| 폰트 변경 | src/app/layout.tsx |
| 로고 변경 | public/logo.png |
| 파비콘 변경 | public/favicon.ico |
| 사이트 제목 변경 | src/app/layout.tsx |
| API 키 설정 | .env.local |
| 메뉴 추가 | src/components/Navigation.tsx |
| 새 페이지 추가 | src/app/[이름]/page.tsx |
| 푸터 수정 | src/components/Footer.tsx |
| 소셜 로그인 추가 | src/lib/auth.ts |
| 결제 연동 | src/lib/stripe.ts |
| 이메일 설정 | src/lib/email.ts |
| 데이터베이스 스키마 | prisma/schema.prisma |
| 환경변수 | .env.local |
| 빌드 설정 | next.config.js |
| 라우트 리다이렉트 | next.config.js → redirects() |
| 404 페이지 | src/app/not-found.tsx |
| 에러 페이지 | src/app/error.tsx |
| 로딩 UI | src/app/loading.tsx |
| SEO 메타태그 | 각 page.tsx의 metadata |
| sitemap | src/app/sitemap.ts |
| robots.txt | src/app/robots.ts |
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.