단계별 코딩 에이전트 프롬프트 팩

마크다운 자료 · 본문에 다운로드 링크 포함

3강 프롬프트 팩 — 코딩 에이전트 단계별 복붙 프롬프트

코딩 에이전트(Claude Code / Codex)에게 단계별로 줄 수 있는 복붙용 프롬프트 모음입니다. 각 프롬프트는 다음 원칙을 따릅니다.

  • 보안 우선: API 키는 서버(Next.js API Route)에서만, 브라우저 노출 금지
  • RLS 필수: Supabase 테이블은 반드시 Row Level Security 활성화
  • 입문자 친화: 에이전트가 설치·설정·코드를 모두 처리하도록 지시

A. Supabase 프로젝트 연결 / 클라이언트 셋업

목표: Next.js 프로젝트에 Supabase를 연결하고, 서버/브라우저 클라이언트를 분리 설정한다.

A-1. 패키지 설치 및 초기 셋업

Supabase를 이 Next.js 프로젝트에 연결해줘.

1. @supabase/supabase-js 와 @supabase/ssr 패키지를 설치해줘.
2. lib/supabase/client.ts 에 브라우저용 클라이언트를 만들어줘 (createBrowserClient 사용).
3. lib/supabase/server.ts 에 서버용 클라이언트를 만들어줘 (createServerClient 사용, cookies()로 세션 처리).
4. 필요한 환경변수는 .env.local.example 파일에 정리해줘:
   - NEXT_PUBLIC_SUPABASE_URL
   - NEXT_PUBLIC_SUPABASE_ANON_KEY
5. .gitignore에 .env, .env.local 이 포함되어 있는지 확인하고, 없으면 추가해줘.

[보안] service_role 키는 지금 사용하지 않으니 .env에 넣지 마. 나중에 필요할 때 서버 전용 변수로만 추가할게.

A-2. 미들웨어로 세션 자동 갱신

Supabase 세션을 자동으로 갱신하는 Next.js 미들웨어를 추가해줘.

- middleware.ts 파일을 루트에 만들어줘.
- @supabase/ssr 의 createServerClient 를 사용해 세션 쿠키를 갱신해줘.
- matcher는 API 라우트와 정적 파일을 제외한 모든 경로로 설정해줘.
- 세션 갱신 후 요청을 그대로 통과시켜줘 (지금은 redirect 없이).

B. 로그인 / 회원가입 + 로그인 상태 UI

목표: 이메일/비밀번호와 Google 소셜 로그인을 구현하고, 상단에 로그인 상태를 표시한다.

B-1. 이메일 로그인 + 회원가입 폼

Supabase Auth로 이메일/비밀번호 로그인과 회원가입 기능을 추가해줘.

- app/auth/page.tsx 에 로그인/회원가입 폼을 만들어줘.
- 탭이나 버튼으로 "로그인"과 "회원가입" 모드를 전환할 수 있게 해줘.
- signInWithPassword(), signUp() 을 사용해줘.
- 에러 메시지(잘못된 비밀번호, 이미 가입된 이메일 등)를 한국어로 표시해줘.
- 로그인 성공 후 메인 페이지(/)로 이동해줘.
- 비밀번호 표시/숨기기 토글 버튼도 넣어줘.

B-2. Google 소셜 로그인 + 로그인 상태 표시 UI

Google 소셜 로그인 버튼과 상단 네비게이션의 로그인 상태 UI를 만들어줘.

[Google 로그인]
- 기존 로그인 폼에 "Google로 로그인" 버튼을 추가해줘.
- signInWithOAuth({ provider: 'google', options: { redirectTo: window.location.origin + '/auth/callback' } }) 를 사용해줘.
- app/auth/callback/route.ts 에 OAuth 콜백 핸들러를 만들어줘 (code를 session으로 교환).

[상단 UI]
- 네비게이션에 로그인 상태를 보여주는 컴포넌트를 추가해줘.
- 로그인된 상태: 사용자 이메일 + "로그아웃" 버튼 표시.
- 로그인 안 된 상태: "로그인" 버튼 표시, 클릭하면 /auth 로 이동.
- signOut() 으로 로그아웃 처리해줘.

[보안] 세션은 Supabase가 쿠키로 관리하니까 별도 토큰 저장 코드는 필요 없어.

C. 테이블 만들기 + RLS "내 행만" 정책

목표: 로그인 사용자의 데이터를 저장할 테이블을 만들고, 본인 행만 접근 가능한 RLS 정책을 추가한다.

C-1. 테이블 생성 + RLS 설정 SQL

Supabase 프로젝트에 아래 테이블을 만드는 SQL을 작성해줘.
Supabase 대시보드 → SQL Editor에 붙여넣어 실행할 수 있게 해줘.

테이블: chat_logs
컬럼:
- id: uuid, PRIMARY KEY, DEFAULT gen_random_uuid()
- user_id: uuid, NOT NULL, REFERENCES auth.users(id) ON DELETE CASCADE
- role: text, NOT NULL (값은 'user' 또는 'assistant')
- content: text, NOT NULL
- created_at: timestamptz, DEFAULT now()

RLS 설정:
1. ALTER TABLE chat_logs ENABLE ROW LEVEL SECURITY;
2. 정책 추가:
   - "본인 행만 조회" (SELECT): user_id = auth.uid()
   - "본인만 삽입" (INSERT): user_id = auth.uid()
   - "본인 행만 삭제" (DELETE): user_id = auth.uid()

[중요] RLS를 반드시 활성화해야 해. 없으면 다른 로그인 사용자가 내 대화 내역을 볼 수 있어.

C-2. TypeScript 타입 생성

Supabase에서 TypeScript 타입을 생성하는 방법을 알려줘.

1. supabase gen types typescript 명령어 예시를 보여줘.
2. 생성된 타입을 lib/supabase/database.types.ts 에 저장하는 방법을 알려줘.
3. 이 타입을 Supabase 클라이언트에 적용하는 방법도 보여줘.

타입 없이 진행해도 되니까, 지금 당장 안 되면 넘어가도 됩니다.

D. 데이터 INSERT / SELECT

목표: 로그인된 사용자의 데이터를 Supabase DB에 저장하고 불러오는 코드를 작성한다.

D-1. INSERT (데이터 저장)

로그인된 사용자의 채팅 메시지를 Supabase chat_logs 테이블에 저장하는 함수를 만들어줘.

- 저장할 때 user_id 는 supabase.auth.getUser() 로 가져온 uid() 를 사용해줘.
- user_id 를 직접 파라미터로 받지 말고, 항상 서버/클라이언트에서 세션으로 확인해줘.
- insert 에러가 나면 콘솔에 에러를 출력하고 사용자에게 "저장 실패" 메시지를 보여줘.
- 저장 성공하면 저장된 row 를 반환해줘.

예시 사용:
const saved = await saveChatMessage({ role: 'user', content: '안녕하세요' });

D-2. SELECT (데이터 조회)

로그인된 사용자의 채팅 내역을 불러오는 함수를 만들어줘.

- chat_logs 테이블에서 현재 로그인한 사람의 행만 가져와줘 (RLS가 자동으로 필터링하지만 명시적으로도 .eq('user_id', user.id) 추가).
- created_at 기준 오름차순 정렬 (오래된 것부터).
- 최근 50개만 가져와줘 (.limit(50)).
- React hook 형태(useChatLogs)로 만들어줘. 로딩 상태와 에러 상태를 포함해줘.

E. 서버 API Route로 Gemini 키 숨겨 호출

목표: Gemini API 키를 서버(Next.js API Route)에서만 사용하고, 브라우저에 절대 노출하지 않는다.

E-1. Gemini API Route 만들기 (핵심 보안 단계)

Gemini API를 안전하게 호출하는 Next.js API Route를 만들어줘.

[파일 위치] app/api/chat/route.ts

[구현 요구사항]
1. POST 요청을 받아서 body에서 { message, history } 를 꺼내줘.
2. 환경변수 process.env.GEMINI_API_KEY 로 Gemini API를 호출해줘.
   - 사용 모델: gemini-2.0-flash-exp (없으면 gemini-1.5-flash)
   - @google/generative-ai 패키지 사용
3. 시스템 프롬프트 기본값: "당신은 친절한 어시스턴트입니다. 한국어로 답변하세요."
4. 응답을 JSON { reply: '...' } 형태로 반환해줘.
5. 에러 시 { error: '...' } 와 적절한 HTTP 상태코드 반환해줘.

[중요 보안]
- GEMINI_API_KEY 는 NEXT_PUBLIC_ 접두어 없이 .env 에만 보관해줘.
- 이 키는 서버 코드에서만 쓰이고 브라우저 번들에 포함되지 않아야 해.
- .env.local.example 에 GEMINI_API_KEY= 라고 예시 줄을 추가해줘.

[설치] @google/generative-ai 패키지도 설치해줘.

E-2. 커스텀 시스템 프롬프트 적용

위에서 만든 app/api/chat/route.ts 의 시스템 프롬프트를 수정해줘.

시스템 프롬프트:
"{여기에 원하는 AI 역할과 지시사항을 넣으세요. 예: 당신은 [사이트명]의 전문 상담사입니다. 방문자의 질문에 친절하고 간결하게 답변하세요. 모르는 내용은 솔직하게 모른다고 하고, 전문가 상담을 권유하세요.}"

이 프롬프트는 서버 코드에만 있어야 하고, 브라우저에서 수정할 수 없게 해줘.
대화 히스토리도 시스템 프롬프트와 함께 Gemini에 전달해줘.

F. 챗봇 UI

목표: 사용자가 AI와 대화할 수 있는 챗봇 컴포넌트를 만든다.

F-1. 챗봇 UI 컴포넌트

AI 챗봇 UI 컴포넌트를 만들어줘.

[파일] components/ChatBot.tsx (또는 app/chat/page.tsx 에 바로 구현)

[UI 요소]
- 대화 메시지 목록 (사용자 메시지: 우측 파란 말풍선 / AI 메시지: 좌측 흰 말풍선)
- 하단 입력창 + 전송 버튼
- 전송 중일 때 로딩 인디케이터 (예: "..." 애니메이션)
- 채팅 영역은 새 메시지가 오면 자동 스크롤 아래로

[동작]
- 전송 버튼 클릭 또는 Enter 키로 메시지 전송
- 메시지 전송 후 입력창 초기화
- /api/chat 로 POST 요청 (body: { message, history })
- AI 응답을 받아 대화 목록에 추가

[UX]
- 로그인 안 된 상태면 "로그인 후 이용할 수 있습니다" 표시
- 빈 메시지는 전송 불가

F-2. 챗봇을 기존 페이지에 추가

기존 사이트의 특정 페이지 또는 섹션에 챗봇을 추가해줘.

- [원하는 위치: 예를 들어 "메인 페이지 하단 섹션" 또는 "별도 /chat 페이지"] 에 챗봇을 배치해줘.
- 기존 디자인(색상, 폰트, 레이아웃)과 자연스럽게 어울리게 스타일을 맞춰줘.
- 모바일에서도 잘 보이게 반응형으로 만들어줘.
- "AI 코너" 또는 원하는 이름의 섹션 헤딩을 추가해줘.

G. 대화를 회원 DB에 저장 (통합)

목표: 챗봇 대화 내용이 로그인된 사용자의 DB에 자동으로 저장되도록 통합한다.

G-1. 메시지 전송과 동시에 DB 저장

챗봇에서 메시지를 주고받을 때 자동으로 Supabase chat_logs 에 저장하도록 수정해줘.

[흐름]
1. 사용자가 메시지 입력 → UI에 표시
2. /api/chat 로 AI 호출
3. AI 응답 받음 → UI에 표시
4. 사용자 메시지(role: 'user') + AI 응답(role: 'assistant') 두 행을 chat_logs 에 INSERT

[주의사항]
- 로그인된 사용자만 저장할 수 있어. 미로그인 상태면 저장 시도하지 마.
- user_id 는 항상 세션에서 가져와. 직접 입력받거나 파라미터로 전달받지 마.
- 저장 실패해도 대화는 계속 동작해야 해 (저장 에러가 챗봇 기능을 막으면 안 돼).
- 저장 성공하면 UI에 "💾 저장됨" 같은 작은 배지를 잠깐 보여줘.

G-2. 이전 대화 내역 불러오기

페이지를 새로 열었을 때 이전 대화 내역을 Supabase에서 불러와서 보여줘.

- 로그인된 사용자의 chat_logs 를 created_at 오름차순으로 가져와줘.
- 최근 50개만 표시해줘.
- 로딩 중에는 스켈레톤 또는 "대화 내역 불러오는 중..." 표시해줘.
- 대화 내역이 없으면 "첫 대화를 시작해보세요!" 라는 안내 문구 표시해줘.
- 미로그인 상태면 내역 로드 시도하지 마.

G-3. 전체 통합 테스트 체크리스트

지금까지 만든 기능이 모두 잘 연결되는지 점검하고 수정해줘.

점검 항목:
1. 로그인 → 챗봇 UI 표시 → 메시지 전송 → AI 응답 표시 → DB 저장 → "저장됨" 배지
2. 페이지 새로고침 → 로그인 상태 유지 → 이전 대화 내역 표시
3. 로그아웃 → 챗봇 "로그인 후 이용" 표시 → 대화 내역 로드 안 됨
4. 다른 계정으로 로그인 → 기존 계정 대화가 보이지 않음 (RLS 검증)

각 항목을 코드에서 확인하고, 문제가 있으면 수정해줘.

H. 배포 전 보안 점검

목표: Vercel 배포 전에 API 키 노출, RLS 누락 등 보안 이슈를 최종 점검한다.

H-1. 환경변수 및 키 노출 점검

배포 전에 보안 이슈를 점검해줘.

점검 항목:
1. 코드 전체에서 GEMINI_API_KEY 가 직접 하드코딩된 곳이 없는지 grep 해줘.
2. 코드 전체에서 NEXT_PUBLIC_GEMINI_ 로 시작하는 환경변수가 없는지 확인해줘.
3. process.env.GEMINI_API_KEY 가 서버 코드(app/api/)에서만 사용되는지 확인해줘.
4. .gitignore 에 .env, .env.local 이 포함됐는지 확인해줘.
5. Supabase service_role 키가 코드에 하드코딩되지 않았는지 확인해줘.

문제가 발견되면 즉시 수정해줘.

H-2. Vercel 환경변수 설정 가이드

이 프로젝트를 Vercel에 배포할 때 필요한 환경변수 목록을 정리해줘.

[알려줘야 할 정보]
1. Vercel 대시보드 → Settings → Environment Variables 에서 설정할 변수 목록
2. 각 변수의 범위 (Production / Preview / Development)
3. NEXT_PUBLIC_ 변수와 서버 전용 변수를 구분해서 설명해줘
4. Vercel에서 변수를 추가한 후 반드시 재배포해야 한다는 안내도 포함해줘

[예시 변수]
- NEXT_PUBLIC_SUPABASE_URL → Production + Preview + Development (브라우저 노출 OK)
- NEXT_PUBLIC_SUPABASE_ANON_KEY → Production + Preview + Development (RLS가 보호)
- GEMINI_API_KEY → Production + Preview (서버 전용, 브라우저 절대 노출 금지)

H-3. RLS 최종 확인

Supabase 대시보드에서 RLS 설정을 확인하는 방법을 알려줘.

그리고 다음 두 가지 테스트를 위한 가이드를 만들어줘:

테스트 1: RLS 작동 확인
- 계정 A로 로그인해서 메시지 3개 저장
- 로그아웃
- 계정 B로 로그인
- 계정 A의 메시지가 보이지 않는지 확인
- (보이면 RLS 정책에 문제가 있는 것 → 해결 방법도 알려줘)

테스트 2: 미로그인 접근 차단 확인
- 로그아웃 상태에서 /api/chat 에 직접 POST 요청 보내기 (curl 또는 브라우저 fetch)
- 401 또는 403 응답이 오는지 확인
- (안 오면 인증 체크 코드를 추가해줘)

팁: 에이전트에게 더 잘 시키는 방법

  • 에러가 나면 에러 메시지 전체를 복사해서 "이 에러 고쳐줘"라고 붙여넣기
  • "다시 해줘" 대신 무엇이 잘못됐는지 구체적으로 말하기 (예: "로그아웃 후에도 대화가 보여, 미로그인 상태에서 빈 배열 보여줘")
  • 한 번에 너무 많이 시키지 말고 한 섹션씩 완성한 뒤 다음으로 이동
  • 보안 규칙은 매번 프롬프트에 포함: "API 키는 서버에서만, RLS 반드시 켜줘"