본 사이트는 파트너스 활동으로 수수료를 받으며, 서버 운영과 무료 앱 개발에 사용됩니다.
    본 사이트는 파트너스 활동으로 수수료를 받으며,서버 운영과 무료 앱 개발에 사용됩니다.
    CDB
    큐레이터 단비's 웹앱 아이디어 창고
    홈무료 앱 185종큐레이터 단비프롬프트칼럼PPT위키AI 이미지AI 툴프로그램쇼핑 핫딜부업 백과개발 명령어

    📑 목차

    PHASE 1. 인프라 준비

    PHASE 2. 개발 (바이브 코딩)

    PHASE 3. 버전 관리 및 배포

    부록

    ←칼럼 목록으로목록

    큐레이터 단비's 칼럼

    COMPLETE GUIDE바이브 코딩•2026.03

    바이브 코딩으로
    나만의 홈페이지 만들기

    💡 아주 자세한 설명과 실제 사용한 서비스 모두 공개

    도메인 구매 → Cloudflare → R2 → Turso → Cursor AI → GitHub → Vercel
    이 글 하나면 누구든 홈페이지를 가질 수 있습니다 🚀

    PHASE 1. 인프라 준비

    도메인, DNS, 저장소, 데이터베이스 — 집을 짓기 전에 땅을 다지는 단계

    PHASE 1. 인프라 준비

    1. 도메인 구매 — Iteasy (아이티이지)

    🌐왜 Iteasy인가

    Iteasy(아이티이지)는 구 코리아서버호스팅에서 사명을 변경한 국내 IT 인프라 전문 기업입니다. .kr, .co.kr, .com, .net 등 국내외 도메인을 등록할 수 있으며, KRNIC(한국인터넷진흥원) 공인 도메인 등록대행 우수기업입니다. 국내 업체이므로 한국어 고객지원이 편리하고, 세금계산서 발행이 가능하여 사업자에게 유리합니다.

    1도메인 구매 실제 과정

    📋 단계별 진행

    1. 1
      사이트 접속: PC 브라우저에서 https://www.iteasy.co.kr/domain/main에 접속합니다. (모바일은 일부 기능이 제한될 수 있으므로 PC 권장)
    2. 2
      회원가입 및 로그인: 상단 회원가입 버튼을 눌러 계정을 생성하고 로그인합니다.
    3. 3
      도메인 검색: 검색창에 원하는 도메인명 입력. 예: myproject → myproject.com, myproject.co.kr 등 등록 가능 목록 표시.
    4. 4
      선택 및 결제: 원하는 도메인 선택 → "등록하기" → 등록기간(1년~) 선택 → 결제 완료.

    💡 도메인 선택 팁

    • .com — 전 세계적으로 가장 범용적. 해외 사용자도 고려한다면 1순위.
    • .co.kr — 한국 서비스임을 명확히 보여줌. 국내 타겟이라면 좋은 선택.
    • .dev, .io — Iteasy에서 취급하지 않을 수 있음. 필요하다면 Cloudflare Registrar나 Namecheap 등 해외 등록기관 고려.

    2네임서버를 Cloudflare로 변경

    도메인 구매 직후에는 Iteasy의 기본 네임서버(ns1.ksdom.kr, ns2.ksdom.kr)가 설정되어 있습니다. 이것을 Cloudflare의 네임서버로 변경해야 합니다. (구체적인 Cloudflare 네임서버 주소는 STEP 2에서 확인 후 입력합니다.)

    📋 네임서버 변경 절차

    1. 1Iteasy 로그인 → 마이페이지 홈 → 도메인 클릭
    2. 2보유도메인 목록에서 변경할 도메인 체크
    3. 3"네임서버 변경" 버튼 클릭
    4. 41차/2차 네임서버 입력란에 Cloudflare 네임서버 주소 2개 입력 → "변경하기"

    ⚠️ 주의사항

    네임서버 변경은 전 세계 DNS에 전파되기까지 최대 24~48시간이 걸릴 수 있습니다. 실제로는 보통 30분~2시간 내에 반영되지만, 기다리는 동안 사이트에 접속되지 않을 수 있다는 점을 알고 있어야 합니다.

    ✅ STEP 1 완료 체크리스트

    • ☑️ Iteasy에서 도메인 구매 완료
    • ☑️ 네임서버 변경 정보 확인 (STEP 2에서 실제 입력)
    • ☑️ 도메인 관리 페이지 접근 방법 숙지
    PHASE 1. 인프라 준비

    2. DNS 및 보안 설정 — Cloudflare

    1Cloudflare 계정 생성 및 도메인 등록

    1. 1https://dash.cloudflare.com/sign-up에서 무료 계정 생성
    2. 2대시보드에서 "+ Add a site" 클릭, Iteasy에서 구매한 도메인 입력 (예: myproject.com)
    3. 3플랜 선택 화면에서 Free (무료) 선택
    4. 4기존 DNS 레코드 자동 스캔 → 아직 서비스 연결 전이므로 비어 있을 수 있음 → 그냥 "Continue"

    2네임서버 확인 및 Iteasy에 적용

    Cloudflare가 2개의 네임서버를 안내합니다:

    # Cloudflare가 랜덤으로 배정 (계정마다 다름)

    1차: xxx.ns.cloudflare.com

    2차: yyy.ns.cloudflare.com

    이 두 값을 복사해서 STEP 1에서 설명한 Iteasy 네임서버 변경 화면에 입력합니다. 변경 후 Cloudflare 대시보드로 돌아와 "Check nameservers" 버튼을 누릅니다. 전파가 완료되면 이메일 알림이 오고, 도메인 상태가 "Active"로 변경됩니다.

    🔴SSL/TLS 설정 — 가장 중요한 설정

    왼쪽 메뉴에서 SSL/TLS → Overview에서 암호화 모드를 반드시 "Full" 또는 "Full (strict)"로 설정합니다.

    🚨 왜 이것이 중요한가

    Cloudflare의 기본 설정은 "Flexible"입니다. 이 상태에서 Vercel(HTTPS 기본 강제)과 연동하면:

    1. 1. Flexible → Cloudflare↔Vercel 구간이 HTTP로 연결
    2. 2. Vercel이 HTTP 요청을 HTTPS로 리다이렉트
    3. 3. 다시 Cloudflare 거치면서 무한 반복

    결과: ERR_TOO_MANY_REDIRECTS — 사이트 접속 불가!
    "Full"로 설정하면 Cloudflare↔Vercel 구간도 HTTPS로 연결되어 해결됩니다.

    4추가 보안 및 성능 설정

    🔒 Always Use HTTPS

    SSL/TLS → Edge Certificates에서 ON. 모든 HTTP 요청을 자동으로 HTTPS로 리다이렉트합니다.

    ⚡ Auto Minify

    Speed → Optimization에서 JavaScript, CSS, HTML 자동 축소 활성화. 파일 크기를 줄여 로딩 속도 향상.

    📦 Brotli 압축

    Speed → Optimization에서 Brotli ON. gzip보다 더 높은 압축률을 제공합니다.

    ⏱️ Browser Cache TTL

    Caching → Configuration에서 브라우저 캐시 만료 시간 설정. 정적 자산이 많다면 4시간~1일.

    🤖 Bot Fight Mode

    Security → Bots에서 Bot Fight Mode 활성화. 악성 봇의 접근을 자동으로 차단합니다.

    5DNS 레코드 — 나중에 추가할 것들 (미리 파악)

    이 시점에서는 아직 Vercel 배포 전이므로 DNS 레코드를 추가하지 않습니다. 하지만 나중에 추가해야 할 레코드를 미리 정리해둡니다:

    # STEP 14에서 추가할 Vercel용 레코드

    A @ 76.76.21.21 (루트 도메인)

    CNAME www cname.vercel-dns.com (www 서브도메인)

    # STEP 3에서 추가될 R2용 레코드 (자동 생성됨)

    CNAME cdn <자동 설정> (이미지 CDN)

    ✅ STEP 2 완료 체크리스트

    • ☑️ Cloudflare 무료 계정 생성 및 도메인 등록
    • ☑️ Iteasy에 Cloudflare 네임서버 입력 → Active 확인
    • ☑️ SSL/TLS → Full 모드 설정 (필수!)
    • ☑️ Always HTTPS, Brotli, Bot Fight Mode 활성화
    PHASE 1. 인프라 준비

    3. 파일/이미지 저장소 — Cloudflare R2

    💰R2 가격 구조 완전 이해

    🆓 무료 티어 (매월 갱신)

    • 저장 용량: 10GB
    • Class A (쓰기/목록): 100만 건
    • Class B (읽기): 1,000만 건
    • 이그레스(송신): 무제한 $0 🎉

    💵 무료 초과 시

    • 저장: $0.015/GB/월
    • Class A: $4.50/100만 건
    • Class B: $0.36/100만 건

    💡 핵심: 이그레스 $0

    AWS S3에서는 1TB 전송에 약 $90가 청구되지만, R2에서는 완전히 무료입니다. 다만 읽기 작업(Class B) 자체는 무료 티어 초과 시 비용 발생합니다. 이미지 하나를 사용자가 요청할 때마다 Class B 1건이 카운트됩니다.

    1R2 버킷 생성

    1. 1Cloudflare 대시보드 → R2 Object Storage → Overview 클릭. 처음이라면 결제 정보 등록 필요 (무료 티어만 사용해도 신용카드 등록 필요)
    2. 2"Create bucket" 클릭 → 이름 입력 (예: myproject-assets) — 본인 계정 내에서만 고유하면 됨
    3. 3Location: APAC (아시아 태평양) 선택 → 한국 사용자에게 가장 빠름
    4. 4Storage Class: Standard → "Create bucket" 클릭

    2퍼블릭 액세스 — 두 가지 방법

    생성된 버킷 → Settings 탭 → Public access 섹션:

    방법 A — R2.dev 서브도메인 (테스트용)

    • • pub-xxxx.r2.dev 형태 URL 생성
    • • 별도 도메인 설정 없이 즉시 사용
    • • ❌ Cloudflare 캐싱 미적용
    • • ❌ URL이 길고 브랜딩 부적합
    • • 개발 단계에서만 임시로 사용 권장

    방법 B — Custom Domain (권장 ⭐)

    • • "Connect Domain" → cdn.myproject.com 입력
    • • DNS CNAME 레코드 + SSL 자동 발급
    • • ✅ Cloudflare CDN 캐싱 자동 적용
    • • ✅ 깔끔한 URL: cdn.myproject.com/images/photo.jpg
    • • ⚠️ Cloudflare DNS 관리 도메인이어야 함 (STEP 2에서 이미 완료)

    3R2 API 토큰 생성

    1. 1R2 Overview 화면 우측 → "Manage R2 API Tokens" 클릭
    2. 2"Create API token" → 권한: "Object Read & Write"
    3. 3특정 버킷만 지정: "Specify bucket(s)" → myproject-assets 선택

    생성 완료 시 3가지 값이 표시됩니다:

    Access Key ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    Secret Access Key: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

    Endpoint (S3 API): https://<ACCOUNT_ID>.r2.cloudflarestorage.com

    🚨 Secret Access Key는 이 화면에서 한 번만 표시됩니다!

    반드시 즉시 안전한 곳에 복사하여 저장하세요. 분실하면 토큰을 삭제하고 새로 만들어야 합니다. Account ID는 Cloudflare 대시보드 우측 사이드바 또는 Account Home 화면 오른쪽에서 확인할 수 있습니다.

    4환경변수 정리

    R2_ACCOUNT_ID=xxxxxxxxxxxxxxxx

    R2_ACCESS_KEY_ID=xxxxxxxxxxxxxxxx

    R2_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxx

    R2_BUCKET_NAME=myproject-assets

    R2_PUBLIC_URL=https://cdn.myproject.com

    💡 R2 endpoint 조합 방식

    R2 endpoint는 코드에서 https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com 형태로 조합하므로 별도 R2_ENDPOINT 환경변수는 불필요합니다. R2_PUBLIC_URL은 이미지 공개 URL의 베이스(프로토콜 포함)입니다. R2는 AWS S3 호환 API이므로 @aws-sdk/client-s3 패키지를 사용하며, region은 "auto"로 설정합니다.

    ✅ STEP 3 완료 체크리스트

    • ☑️ R2 버킷 생성 (APAC 리전)
    • ☑️ 커스텀 도메인(cdn.myproject.com) 연결
    • ☑️ API 토큰 생성 및 Secret Key 안전 보관
    • ☑️ 5개 환경변수 메모 완료
    PHASE 1. 인프라 준비

    4. 데이터베이스 생성 — Turso

    🗄️Turso 가격 구조

    🆓 Free 플랜

    • 데이터베이스: 100개
    • 월간 활성 DB: 100개
    • 총 저장: 5GB
    • 월간 행 읽기: 5억 건
    • 월간 행 쓰기: 1,000만 건

    💎 Developer ($4.99/월)

    • 데이터베이스: 무제한
    • 월간 활성 DB: 500개
    • 총 저장: 9GB
    • 월간 행 읽기: 25억 건
    • 월간 행 쓰기: 2,500만 건

    1Turso CLI 설치

    # macOS (Homebrew)

    brew install tursodatabase/tap/turso

    # Linux / WSL

    curl -sSfL https://get.tur.so/install.sh | bash

    # Windows (npm으로 설치)

    npm install -g @tursodatabase/cli

    # 설치 확인

    turso --version

    2인증 및 데이터베이스 생성

    # 브라우저가 열리며 GitHub 계정으로 로그인

    turso auth signup

    # 또는 이미 계정이 있다면

    turso auth login

    # 데이터베이스 생성 (가장 가까운 리전에 자동 배치)

    turso db create myproject-db

    # 특정 리전 지정 (한국에 가장 가까운 곳)

    turso db create myproject-db --location nrt

    # nrt = 도쿄 (한국에서 가장 가까운 Turso 리전)

    3데이터베이스 URL 및 인증 토큰 확인

    # 데이터베이스 URL 확인

    turso db show --url myproject-db

    # 출력 예: libsql://myproject-db-username.turso.io

    # 인증 토큰 생성

    turso db tokens create myproject-db

    # 출력: eyJhxxxxxxxx... (긴 JWT 토큰 문자열)

    4환경변수 정리

    TURSO_DATABASE_URL=libsql://myproject-db-username.turso.io

    TURSO_AUTH_TOKEN=eyJhxxxxxxxxxxxxxxxxxxxxxxxx

    5로컬 개발 환경에서의 Turso 사용

    개발할 때마다 원격 DB에 접속하면 느리고, 무료 쿼리 할당량도 소모됩니다. Turso는 로컬 개발용 모드를 제공합니다:

    # 로컬에서 Turso 개발 서버 실행

    turso dev

    # 출력: Listening on http://127.0.0.1:8080

    # .env.local (개발용)

    TURSO_DATABASE_URL=http://127.0.0.1:8080

    TURSO_AUTH_TOKEN= # 로컬에서는 빈 값 또는 생략

    💡 핵심: .env와 .env.local 분리

    프로덕션 환경의 .env와 개발 환경의 .env.local을 분리해서 관리하는 것이 핵심입니다. .env.local은 .env보다 우선 적용되므로, 로컬에서는 자동으로 로컬 DB를 사용하게 됩니다.

    6Turso 데이터베이스 쉘 접속

    데이터가 잘 들어갔는지 직접 확인하고 싶을 때:

    turso db shell myproject-db

    # SQLite 쉘이 열립니다

    .tables # 테이블 목록 확인

    SELECT * FROM users; # 쿼리 실행

    .quit # 종료

    ✅ STEP 4 완료 체크리스트

    • ☑️ Turso CLI 설치 및 인증 완료
    • ☑️ 데이터베이스 생성 완료 (nrt 리전)
    • ☑️ DB URL 및 인증 토큰 확보
    • ☑️ 로컬 개발 모드 (turso dev) 테스트
    • ☑️ 환경변수 2개 정리 완료

    🎉 PHASE 1 완료!

    인프라가 모두 준비되었습니다. 도메인, DNS, 파일 저장소, 데이터베이스가 세팅되었습니다.
    다음은 PHASE 2: 개발 환경을 구축하고 바이브 코딩을 시작합니다.

    PHASE 2. 개발 (바이브 코딩)

    Cursor AI IDE로 자연어로 코드를 작성하는 새로운 방식의 개발

    PHASE 2. 개발 (바이브 코딩)

    5. AI 코딩 에디터 — Cursor 설치와 구독

    Cursor는 VS Code 기반의 AI 코딩 에디터입니다. 자연어로 요청하면 AI가 코드를 작성하고 수정합니다. 이것이 "바이브 코딩"의 핵심 도구입니다.

    1Cursor 설치

    1. 1https://cursor.com 접속
    2. 2OS에 맞는 설치 파일 다운로드 (Windows / macOS / Linux)
    3. 3설치 후 계정 생성 → 로그인

    💡 VS Code에서 마이그레이션

    기존 VS Code 사용자라면 설치 후 "Import from VS Code"를 선택하면 확장, 테마, 키바인딩 등 설정이 그대로 옮겨집니다.

    2구독 플랜

    Hobby (무료)

    월 2,000회 자동완성 + 50회 느린 프리미엄 요청. 체험용.

    $0

    Pro (권장 ✅)

    무제한 자동 완성, 500회 빠른 프리미엄 요청 (Claude, GPT 등), Agent 모드 무제한.

    $20/월

    Ultra

    최대 성능 모델, 더 많은 Agent 요청.

    $200/월

    3핵심 기능 — Agent Mode

    Cursor Agent Mode는 자연어로 지시하면 코드 작성, 파일 생성/수정, 터미널 명령어 실행까지 자동으로 처리하는 모드입니다. 바이브 코딩의 핵심이며, 우리가 주로 사용할 모드입니다.

    ⌨️ 핵심 단축키 3+1

    단축키기능설명
    Ctrl+IAgent Mode 열기가장 많이 쓰는 단축키. AI 채팅 창을 열고 요청을 입력합니다.
    Ctrl+LChat 열기코드 수정 없이 질문하거나 설명을 요청할 때.
    Ctrl+KInline Edit선택한 코드 블록을 자연어로 수정. "에러 핸들링 추가해줘" 등 특정 부분만 빠르게 수정.
    Tab자동 완성 수락AI가 제안하는 코드를 수락합니다.
    Ctrl+`터미널 열기(보너스) 터미널을 열어 명령어를 실행합니다.

    ✅ STEP 5 완료 체크리스트

    • ☑️ Cursor 설치 및 계정 생성
    • ☑️ Pro 플랜 구독 ($20/월)
    • ☑️ Agent Mode 단축키(Ctrl+I) 숙지
    PHASE 2. 개발 (바이브 코딩)

    6. Cursor Rules — AI에게 프로젝트 문맥 알려주기

    Cursor Rules는 AI에게 "이 프로젝트의 기술 스택과 코딩 규칙은 이렇다"라고 알려주는 설정 파일입니다. 프로젝트 루트에 .cursor/rules/ 폴더를 만듭니다.

    1디렉토리 구조

    프로젝트_루트/

    ├── .cursor/

    │ └── rules/

    │ ├── project-overview.mdc

    │ ├── tech-stack.mdc

    │ └── coding-conventions.mdc

    └── ... (나머지 프로젝트 파일)

    2.mdc 파일 형식

    각 규칙 파일은 .mdc 확장자를 사용합니다. YAML 프론트매터 + 마크다운 본문으로 구성됩니다:

    # 예시: tech-stack.mdc

    ---

    description: "기술 스택 및 의존성 가이드"

    globs: "**/*.ts, **/*.tsx"

    alwaysApply: true

    ---

     

    # 기술 스택

    - Framework: Next.js 16 (App Router)

    - Language: TypeScript

    - Styling: Tailwind CSS v4

    - Database: Turso (libSQL) — raw SQL만 사용, ORM 금지

    - Storage: Cloudflare R2 (S3 호환 API)

    - Deployment: Vercel

     

    # 코딩 규칙

    - 모든 컴포넌트는 TypeScript로 작성

    - 서버 컴포넌트 우선 (클라이언트 최소화)

    - DB 쿼리는 @libsql/client로 raw SQL 실행

    - 보안: API Key, Token 등은 환경변수로 관리

    description

    이 규칙 파일이 무엇에 대한 것인지 설명. AI가 관련 질문 시 참조 여부를 판단하는데 사용.

    globs

    이 규칙이 적용되는 파일 패턴. **/*.ts는 모든 TypeScript 파일에 적용.

    alwaysApply

    true면 모든 AI 요청에 항상 포함. false면 관련 파일 작업 시에만 적용.

    3실전 규칙 파일 예시

    # project-overview.mdc

    ---

    description: "프로젝트 전체 구조와 아키텍처 개요"

    alwaysApply: true

    ---

     

    # 프로젝트 아키텍처

     

    ## 인프라

    - 도메인: Iteasy (myproject.com)

    - DNS/CDN: Cloudflare (Free)

    - 파일 저장: Cloudflare R2 (cdn.myproject.com)

    - 데이터베이스: Turso (libSQL, nrt 리전)

    - 배포: Vercel (Hobby)

     

    ## 디렉토리 구조

    app/ → Next.js App Router 페이지들

    lib/ → 유틸리티, DB 연결, R2 클라이언트

    components/ → 공통 UI 컴포넌트

    public/ → 정적 파일 (favicon, robots.txt 등)

    💡 팁: 규칙을 구체적으로 작성하세요

    "TypeScript를 사용해주세요" 같은 모호한 규칙보다 "ORM(Prisma, Drizzle 등)을 사용하지 마세요. @libsql/client의 execute() 메서드로 raw SQL 쿼리를 실행하세요"처럼 구체적으로 쓰면 AI가 더 정확한 코드를 생성합니다. 규칙 간 @ 기호로 다른 파일을 참조할 수 있어 규칙 연결도 가능합니다.

    4database.mdc — 파일 패턴으로 자동 적용

    ---

    description: "데이터베이스 관련 규칙"

    globs: ["**/lib/db*", "**/api/**/*.ts"]

    alwaysApply: false

    ---

     

    # 데이터베이스 규칙

    - ORM 사용하지 않는다. @libsql/client, raw SQL만

    - DB 클라이언트는 lib/db.ts의 getDb() 싱글톤

    - 스키마는 ensureMigration()에서 CREATE TABLE IF NOT EXISTS

    - 쿼리 결과: row as unknown as { column: type }

    - 날짜: SQLite datetime('now') 또는 ISO 문자열

    alwaysApply: false + globs 패턴 → lib/db*나 api/**/*.ts 파일을 작업할 때만 AI에 자동 적용됩니다.

    ✅ STEP 6 완료 체크리스트

    • ☑️ .cursor/rules/ 디렉토리 생성
    • ☑️ 기술 스택 규칙 파일 (alwaysApply: true)
    • ☑️ DB 규칙 파일 (alwaysApply: false + globs)
    • ☑️ 프로젝트 개요 규칙 파일
    PHASE 2. 개발 (바이브 코딩)

    7. MCP 서버 설정 — AI가 DB에 직접 접근

    MCP(Model Context Protocol)를 사용하면 Cursor AI가 Turso 데이터베이스에 직접 SQL을 실행할 수 있습니다. 예: "DB 현황 보여줘", "products 테이블 행 수 조회" 등.

    A방법 A — 프로젝트 설정 파일 (.cursor/mcp.json)

    프로젝트 루트에 .cursor 폴더를 만들고 그 안에 mcp.json 파일을 생성합니다:

    // .cursor/mcp.json

    { "mcpServers": { "user-site-mb-db-v1": { "command": "node", "args": ["mcp-server-turso.js"], "cwd": "${workspaceFolder}", "env": { "TURSO_DATABASE_URL": "<본인 Turso URL>", "TURSO_AUTH_TOKEN": "<본인 Turso 인증 토큰>" } } } }

    command: node (Node.js로 서버 실행)

    args: 프로젝트 루트에 있는 mcp-server-turso.js 파일

    cwd: ${workspaceFolder} → 프로젝트 루트에서 실행

    env: TURSO_DATABASE_URL, TURSO_AUTH_TOKEN 필수

    B방법 B — Cursor 설정 UI

    1. 1Cursor Settings 열기: Ctrl+, (Windows) / Cmd+, (Mac)
    2. 2Features 또는 Tools & MCP → MCP 섹션으로 이동
    3. 3"Add new MCP server" 클릭
    4. 4

      Name: user-site-mb-db-v1, Type: command

      Command: node, Args: mcp-server-turso.js

    5. 5Env에 TURSO_DATABASE_URL, TURSO_AUTH_TOKEN 값 설정 → 저장 → Cursor 재시작

    📄mcp-server-turso.js 파일 구조

    프로젝트 루트의 이 파일은 Turso DB에 대한 MCP 서버 역할을 하는 Node.js 스크립트입니다. Cursor가 자식 프로세스로 실행하고 stdio로 JSON 메시지를 주고받습니다.

    구성 요소설명
    MCP SDK@modelcontextprotocol/sdk — Server, StdioServerTransport, ListToolsRequestSchema 등
    Turso 클라이언트@libsql/client의 createClient — 환경변수로 연결
    제공 도구execute_query 하나. 인자: sql(필수), args(선택). Turso에 client.execute 호출 후 결과 JSON 반환
    전송 방식Stdio — 표준 입출력. 별도 포트나 HTTP 서버 불필요

    🚨 보안 주의

    mcp.json에 TURSO 실제 값을 넣었다면 .gitignore에 추가하여 저장소에 올리지 마세요. 팀 공유 시에는 env를 비우고 각자 로컬 환경변수로 전달하는 방식을 권장합니다. mcp-server-turso.js 파일 자체는 비밀정보를 코드에 적지 않으므로 공개 저장소에 포함해도 됩니다.

    ✅ 동작 확인

    설정 후 Cursor를 완전히 종료했다가 다시 실행합니다. 채팅에서 "Turso DB 테이블 목록 조회해줘" 또는 "execute_query 사용해서 SELECT 1" 등으로 요청해 보세요. MCP 도구 execute_query가 호출되어 결과가 반환되면 성공입니다.

    PHASE 2. 개발 (바이브 코딩)

    8. 프로젝트 초기화 — Next.js 16 시작하기

    이제 실제 프로젝트를 만들 차례입니다. 바이브 코딩의 핵심 — Cursor Agent Mode에서 자연어로 프로젝트를 생성합니다.

    1빈 프로젝트 폴더 열기

    1. 1원하는 위치에 프로젝트 폴더 생성 (예: D:\Projects\myproject)
    2. 2Cursor에서 File → Open Folder → 해당 폴더 선택

    2Agent Mode로 프로젝트 생성 (Ctrl+I)

    Cursor Agent Mode를 열고 다음과 같이 입력합니다. 이것이 바이브 코딩의 첫 번째 프롬프트입니다:

    # Cursor Agent Mode (Ctrl+I)에 입력할 프롬프트:

    "Next.js 16 (App Router)와 TypeScript, Tailwind CSS v4로 새 프로젝트를 생성해 주세요.
    npx create-next-app@latest ./ 명령어를 사용하되, 대화형 프롬프트 없이 자동으로 진행해 주세요.
    TypeScript, ESLint, Tailwind CSS, App Router를 사용하고, src/ 디렉토리는 사용하지 않습니다.
    import alias는 @/*를 사용합니다."

    💡 Agent가 실행할 실제 명령어

    npx create-next-app@latest ./ --typescript --tailwind --eslint --app --no-src-dir --import-alias "@/*" --use-npm

    Agent가 터미널에서 이 명령어를 실행하면 "Run command?" 확인이 나타납니다. 확인을 눌러 실행을 허용하세요.

    3생성된 프로젝트 구조 확인

    myproject/

    ├── app/

    │ ├── layout.tsx # 루트 레이아웃

    │ ├── page.tsx # 메인 페이지

    │ └── globals.css # 전역 스타일

    ├── public/ # 정적 파일

    ├── .gitignore

    ├── next.config.ts # Next.js 설정

    ├── package.json

    ├── tailwind.config.ts # Tailwind 설정

    └── tsconfig.json

    4로컬 개발 서버 실행

    npm run dev

    # → http://localhost:3000 에서 확인

    브라우저에서 http://localhost:3000에 접속하면 Next.js 기본 페이지가 나타납니다. 여기까지 되면 프로젝트 초기화는 성공입니다!

    ✅ STEP 8 완료 체크리스트

    • ☑️ Next.js 16 프로젝트 생성 완료
    • ☑️ TypeScript + Tailwind CSS + App Router 설정
    • ☑️ npm run dev로 localhost:3000 확인
    PHASE 2. 개발 (바이브 코딩)

    9. Turso DB 연동 코드 — @libsql/client로 raw SQL

    1패키지 설치

    npm install @libsql/client

    2DB 연결 싱글톤 — lib/db.ts

    싱글톤 패턴으로 DB 연결을 관리합니다. 매 요청마다 새 연결을 만들지 않고, 하나의 연결을 재사용합니다:

    // lib/db.ts

    import { createClient, Client } from '@libsql/client';

     

    let client: Client | null = null;

     

    export function getDb(): Client {

    if (!client) {

    client = createClient({

    url: process.env.TURSO_DATABASE_URL!,

    authToken: process.env.TURSO_AUTH_TOKEN,

    });

    }

    return client;

    }

    3자동 마이그레이션 — ensureMigration()

    앱이 처음 실행될 때 필요한 테이블이 없으면 자동으로 생성하는 패턴입니다:

    // lib/db.ts (계속)

    let migrated = false;

     

    export async function ensureMigration() {

    if (migrated) return;

    const db = getDb();

     

    await db.execute(`

    CREATE TABLE IF NOT EXISTS posts (

    id INTEGER PRIMARY KEY AUTOINCREMENT,

    title TEXT NOT NULL,

    content TEXT,

    created_at DATETIME DEFAULT CURRENT_TIMESTAMP

    )

    `);

     

    migrated = true;

    }

    4실제 사용 예제 — API Route에서

    // app/api/posts/route.ts

    import { getDb, ensureMigration } from '@/lib/db';

    import { NextResponse } from 'next/server';

     

    export async function GET() {

    await ensureMigration();

    const db = getDb();

     

    const result = await db.execute(

    'SELECT * FROM posts ORDER BY created_at DESC'

    );

     

    return NextResponse.json(result.rows);

    }

    ⚠️ ORM을 사용하지 마세요

    Prisma, Drizzle 등 ORM은 사용하지 않습니다. @libsql/client의 execute() 메서드로 raw SQL만 사용합니다. ORM은 빌드 시간을 늘리고, Vercel 서버리스 환경에서 콜드 스타트가 느려지며, 이 프로젝트 규모에서는 불필요한 복잡성을 추가합니다.

    ✅ STEP 9 완료 체크리스트

    • ☑️ @libsql/client 패키지 설치
    • ☑️ lib/db.ts 싱글톤 연결 함수 작성
    • ☑️ ensureMigration() 자동 마이그레이션 함수 작성
    • ☑️ API Route에서 DB 쿼리 실행 확인
    PHASE 2. 개발 (바이브 코딩)

    10. R2 업로드 코드 — S3 호환 API로 파일 업로드

    1패키지 설치

    npm install @aws-sdk/client-s3

    Cloudflare R2는 AWS S3 호환 API를 제공하므로, AWS SDK의 S3 클라이언트를 그대로 사용합니다.

    2S3 클라이언트 설정 — lib/r2.ts

    // lib/r2.ts

    import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

     

    const r2 = new S3Client({

    region: 'auto',

    endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,

    credentials: {

    accessKeyId: process.env.R2_ACCESS_KEY_ID!,

    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,

    },

    });

    3업로드 API Route

    // app/api/upload/route.ts

    import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

    import { NextRequest, NextResponse } from 'next/server';

     

    const r2 = new S3Client({ /* 위와 동일 */ });

     

    export async function POST(req: NextRequest) {

    const formData = await req.formData();

    const file = formData.get('file') as File;

     

    if (!file) {

    return NextResponse.json(

    { error: 'No file' }, { status: 400 }

    );

    }

     

    const buffer = Buffer.from(await file.arrayBuffer());

    const key = `uploads/${Date.now()}-${file.name}`;

     

    await r2.send(new PutObjectCommand({

    Bucket: process.env.R2_BUCKET_NAME!,

    Key: key,

    Body: buffer,

    ContentType: file.type,

    }));

     

    const url = `${process.env.R2_PUBLIC_URL}/${key}`;

    return NextResponse.json({ url });

    }

    💡 CDN URL 구조

    업로드된 파일은 https://cdn.myproject.com/uploads/1709280000000-photo.jpg 형태의 URL로 접근 가능합니다. Cloudflare CDN이 자동으로 캐싱하므로 빠릅니다.

    ✅ STEP 10 완료 체크리스트

    • ☑️ @aws-sdk/client-s3 패키지 설치
    • ☑️ S3Client 설정 (R2 endpoint 사용)
    • ☑️ 업로드 API Route 구현
    • ☑️ CDN URL로 파일 접근 확인
    PHASE 2. 개발 (바이브 코딩)

    11. 바이브 코딩 워크플로우 — AI와 대화하며 개발하기

    인프라와 개발 환경이 모두 준비되었습니다. 이제 진짜 바이브 코딩을 시작합니다. 핵심은 "요청 → 확인 → 수정" 반복 사이클입니다.

    🔄기본 사이클: 요청 → 확인 → 수정

    💬

    1. 기능 요청

    Agent Mode(Ctrl+I)에서 자연어로 원하는 기능을 설명합니다. 구체적일수록 좋습니다.

    👀

    2. 결과 확인

    AI가 코드를 작성/수정하면 브라우저에서 결과를 확인합니다. npm run dev가 실행 중이면 자동 새로고침됩니다.

    🔧

    3. 수정 요청

    마음에 안 드는 부분이 있으면 다시 요청합니다. "버튼을 왼쪽으로 옮겨줘", "색상을 더 진하게" 등.

    📝효과적인 프롬프팅 원칙

    ✅ 좋은 프롬프트

    "게시글 목록 페이지를 만들어줘. /posts 경로에서 Turso DB의 posts 테이블을 조회해서 제목, 작성일, 내용 미리보기를 카드 형태로 보여줘. 최신순으로 정렬하고, 카드를 클릭하면 /posts/[id] 상세 페이지로 이동하게 해줘."

    → 경로, 데이터 소스, UI 형태, 정렬, 동작이 명확

    ❌ 나쁜 프롬프트

    "블로그 만들어줘"

    → 너무 모호. AI가 무엇을 만들어야 할지 판단이 어렵고 엉뚱한 결과가 나올 수 있음

    💡바이브 코딩 실전 팁

    🎯 한 번에 하나씩

    한 번에 너무 많은 기능을 요청하지 마세요. "로그인 + 게시판 + 프로필 + 결제"를 한 번에 요청하면 혼란이 옵니다. 하나씩 쌓아가세요.

    📸 스크린샷 활용

    문제가 생기면 브라우저 스크린샷을 찍어서 Agent에게 보여주세요. Cursor는 이미지를 이해하고 문제를 진단할 수 있습니다.

    📂 파일 참조 (@)

    프롬프트에서 @파일명으로 특정 파일을 참조할 수 있습니다. "@lib/db.ts 를 참고해서 사용자 목록 API를 만들어줘."

    🔄 자주 커밋하세요

    작동하는 상태가 되면 바로 Git 커밋. AI가 이상한 방향으로 갈 때 돌아갈 수 있는 세이브 포인트입니다.

    🎉 PHASE 2 완료!

    개발 환경이 완성되었고, 바이브 코딩 워크플로우를 이해했습니다.
    다음은 PHASE 3: 코드를 GitHub에 올리고 Vercel로 세상에 배포합니다.

    PHASE 3. 버전 관리 및 배포

    GitHub으로 코드를 관리하고 Vercel로 전 세계에 공개합니다

    PHASE 3. 버전 관리 및 배포

    12. 버전 관리 — GitHub 연동

    🐙GitHub 계정 및 Repository 생성

    1. 1https://github.com/signup에서 계정 생성 (무료)
    2. 2오른쪽 상단 "+" → New repository 클릭
    3. 3Repository name 입력 (예: myproject), Private 선택 (Vercel 무료에서도 비공개 배포 가능)
    4. 4"Add a README", ".gitignore", "License"는 체크하지 않음! (이미 로컬에 프로젝트가 있으므로 빈 저장소로 만들어야 충돌 없음) → Create repository

    2로컬 프로젝트를 GitHub에 연결

    Cursor의 내장 터미널(Ctrl+`)에서 다음 명령을 실행합니다:

    # 1. Git 초기화 (이미 되어 있을 수 있음)

    git init

    # 2. 모든 파일을 스테이징

    git add .

    # 3. 첫 번째 커밋

    git commit -m "초기 프로젝트 설정: Next.js + Turso + R2"

    # 4. 메인 브랜치 이름 설정

    git branch -M main

    # 5. GitHub 원격 저장소 연결

    git remote add origin https://github.com/본인계정/myproject.git

    # 6. 코드 푸시

    git push -u origin main

    3.gitignore — 절대 커밋하면 안 되는 파일들

    # 🚨 환경변수 (절대 커밋하면 안 됨!)

    .env

    .env.local

    .env.production

    # 의존성

    node_modules/

    # 빌드 결과물

    .next/

    out/

    # OS 파일

    .DS_Store

    Thumbs.db

    # Turso 로컬 DB

    *.db

    *.db-journal

    # 🚨 Cursor MCP 설정 (토큰 포함 시)

    .cursor/mcp.json

    🚨 .env 파일을 GitHub에 올리면?

    누구나 당신의 데이터베이스와 스토리지에 접근할 수 있습니다. 만약 실수로 커밋했다면 즉시 해당 토큰을 폐기하고 새로 발급받아야 합니다. Git 이력에 한 번이라도 남으면 되돌려도 노출된 것입니다.

    4이후 작업 흐름 — 기능 단위 커밋

    개발을 계속하면서 기능 단위로 커밋합니다:

    # 기능 개발 완료 후

    git add .

    git commit -m "feat: 블로그 게시글 CRUD 구현"

    git push

    Vercel과 연동하면(STEP 13), git push를 할 때마다 자동으로 새 버전이 배포됩니다.

    ✅ STEP 12 완료 체크리스트

    • ☑️ GitHub 계정 및 Private 저장소 생성 (빈 저장소)
    • ☑️ 로컬 프로젝트 → GitHub 첫 Push 완료
    • ☑️ .gitignore에 .env, mcp.json, *.db 포함 확인
    • ☑️ 기능 단위 커밋 흐름 이해
    PHASE 3. 버전 관리 및 배포

    13. 전 세계에 공개 — Vercel 배포

    🚀Vercel 가격 구조

    🆓 Hobby (무료, 권장)

    • 비상업적 개인용도에만 허용!
    • 대역폭: 100GB/월
    • 빌드: 6,000분/월
    • 서버리스 함수: 10초 제한

    💼 Pro ($20/월)

    • 상업적 사용 가능
    • 대역폭: 1TB/월 (초과 $0.15/GB)
    • 서버리스 함수: 60초
    • 팀 멤버 추가 가능

    1Vercel 계정 생성 및 프로젝트 Import

    1. 1https://vercel.com/signup → GitHub 계정으로 로그인
    2. 2대시보드에서 "Add New... → Project" 클릭
    3. 3"Import Git Repository" → GitHub 저장소 목록에서 myproject 선택 → Import. 보이지 않으면 "Adjust GitHub App Permissions"로 권한 부여

    2환경변수 설정 — 가장 중요한 단계

    Import 화면에서 "Environment Variables" 섹션을 펼치고 모든 환경변수를 입력합니다:

    # Turso

    TURSO_DATABASE_URL = libsql://myproject-db-username.turso.io

    TURSO_AUTH_TOKEN = eyJhxxxxxxxxxx

    # R2

    R2_ACCOUNT_ID = xxxxxxxxxx

    R2_ACCESS_KEY_ID = xxxxxxxxxx

    R2_SECRET_ACCESS_KEY = xxxxxxxxxx

    R2_BUCKET_NAME = myproject-assets

    R2_PUBLIC_URL = https://cdn.myproject.com

    # 보안 & 관리자

    JWT_SECRET = (openssl rand -base64 32 로 생성)

    ADMIN_USERNAME = admin

    ADMIN_PASSWORD = (프로덕션용 강한 비밀번호)

    💡 환경변수 입력 팁

    각 변수에는 적용 범위(Environment)를 선택할 수 있습니다: Production, Preview, Development. 모든 환경에 체크하는 것이 일반적이지만, Preview에는 테스트용 별도 DB를 쓰면 프로덕션 오염 방지가 됩니다.

    3빌드 및 배포 확인

    Deploy를 누르면 Vercel이 자동으로 빌드를 시작합니다. 빌드 로그를 실시간으로 확인할 수 있으며, 성공하면 myproject.vercel.app 도메인으로 사이트가 공개됩니다. 🎉

    ✅ STEP 13 완료 체크리스트

    • ☑️ Vercel 계정 생성 (GitHub 로그인)
    • ☑️ GitHub 저장소 Import
    • ☑️ 모든 환경변수 입력 완료
    • ☑️ 첫 배포 성공 및 .vercel.app 접속 확인
    PHASE 3. 버전 관리 및 배포

    14. 커스텀 도메인 연결 — 내 도메인으로 접속

    현재는 myproject.vercel.app으로 접속 가능합니다. 이제 STEP 1에서 구매한 도메인을 연결합니다.

    1Vercel에 도메인 추가

    1. 1Vercel 대시보드 → 프로젝트 선택 → Settings → Domains
    2. 2도메인 입력: myproject.com → "Add"
    3. 3www.myproject.com도 추가 (www → 루트 도메인으로 리다이렉트 설정)

    2Cloudflare DNS 레코드 추가

    Cloudflare 대시보드 → DNS → Records에서 다음 레코드를 추가합니다:

    TypeNameContentProxy
    A@ (루트)76.76.21.21☁️ Proxied
    CNAMEwwwcname.vercel-dns.com☁️ Proxied

    ⚠️ SSL/TLS 모드 재확인

    STEP 2에서 설정한 SSL/TLS → Full 모드가 아직 유지되고 있는지 반드시 확인하세요. Flexible로 되어 있으면 무한 리다이렉트(ERR_TOO_MANY_REDIRECTS)가 발생합니다.

    3확인

    DNS 전파 후 Vercel 대시보드의 Domains 섹션에서 초록색 체크 ✅ 표시가 나타나면 성공입니다. 이제 https://myproject.com으로 접속하면 사이트가 표시됩니다!

    ✅ STEP 14 완료 체크리스트

    • ☑️ Vercel에 커스텀 도메인 추가
    • ☑️ Cloudflare DNS A/CNAME 레코드 추가
    • ☑️ SSL/TLS Full 모드 확인
    • ☑️ https://myproject.com 접속 확인
    PHASE 3. 버전 관리 및 배포

    15. 자동 배포와 트러블슈팅 — 문제 해결 가이드

    🔄자동 배포 (CI/CD) 흐름

    GitHub와 Vercel이 연동되면 자동 배포가 작동합니다:

    💻

    Cursor에서 코드 수정

    📤

    git push origin main

    ⚙️

    Vercel 자동 빌드

    🌍

    30초~3분 후 반영!

    💡 브랜치별 배포

    • main 브랜치에 push → 프로덕션 배포 (myproject.com에 반영)
    • 다른 브랜치에 push → Preview 배포 (고유한 URL 생성, 예: myproject-git-feature-login.vercel.app)
    • Pull Request 생성 → Preview 배포 URL이 PR 코멘트에 자동 추가되어, 리뷰어가 실제 동작 확인 가능

    🐛자주 발생하는 문제와 해결법

    ❌ ERR_TOO_MANY_REDIRECTS

    원인: Cloudflare SSL/TLS가 "Flexible"으로 설정되어 있음

    해결: Cloudflare → SSL/TLS → "Full"로 변경 (STEP 2-3 참조)

    ❌ 빌드 실패: Environment variable not found

    원인: Vercel에 환경변수가 입력되지 않음

    해결: Vercel → Settings → Environment Variables에서 누락된 변수 추가. 추가 후 Redeploy 필요

    ❌ next/image: Invalid src "cdn.xxx.com/..."

    원인: Next.js Image 컴포넌트에서 외부 도메인을 허용하지 않음

    해결: next.config의 images.remotePatterns에 CDN 도메인 추가. R2 커스텀 도메인은 new URL(process.env.R2_PUBLIC_URL).hostname으로 hostname 추출하여 동적으로 넣을 수 있음

    ❌ Serverless Function Timeout

    원인: Hobby 플랜 서버리스 함수 제한 시간 10초 초과 (Pro는 60초)

    해결: R2에 대용량 파일 업로드 시 → 클라이언트에서 R2에 직접 업로드하는 Presigned URL 방식 사용 (@aws-sdk/s3-request-presigner), 또는 Pro 플랜 업그레이드

    ❌ TypeScript 타입 에러

    원인: 로컬에서는 작동하지만 빌드 시 strict 타입 검사에서 실패

    해결: Vercel 빌드 로그의 에러 메시지를 복사하여 Cursor Agent에게 붙여넣기 → AI가 타입 수정 제안

    🎉 PHASE 3 완료! 축하합니다!

    코드가 GitHub에 올라가고, Vercel로 전 세계에 배포되었으며, 커스텀 도메인이 연결되었습니다!
    앞으로는 코드를 수정하고 git push만 하면 자동으로 배포됩니다.

    부록

    아키텍처, 환경변수, 보안, 비용 등 참고 자료 모음

    부록

    16. 전체 아키텍처 — 시스템 구성도 정리

    1. 프롬프트 지시Tool Call DB 분석git push 배포웹훅 → 자동 빌드execute_query 제어libSQL raw 쿼리Presigned 업로드HTTPS 페이지 요청CDN 캐시된 응답App 동적 서버 렌더링이미지 소스 연동👨‍💻 기획자 (관리자)✨ Cursor AI 에디터클라이언트/서버 코드 작성Vibe Coding & Agent Mode🐙 GitHub 원격 저장소전체 소스코드 버전 트래킹보안 환경변수 분리 보관🔌 MCP 서버AI ↔︎ 원격 데이터 연동 도구▲ Vercel (Next.js 핵심)App Router (React 서버 컴포넌트)글로벌 무중단 Edge NetworkAPI Route Serverless Functions미들웨어 JWT 인증 / 세션 관리🗄️ Turso Database분산 SQLite 엔진 (libSQL)단일 도쿄(nrt) 리전 배치게시물, 관리자 계정, 통계 저장ORM 없이 직접 raw SQL 최적화☁️ Cloudflare 인프라도메인 DNS / 글로벌 엣지 CDNSSL/TLS Full, Bot Fight Mode (WAF)Brotli 압축 및 정적 리소스 캐싱🪣 Cloudflare R2S3 호환 Object Storage이미지 및 대용량 파일 영구 보관데이터 이그레스(송출) 완전 무료!💻 일반 사용자웹 브라우저 접속 (데스크톱, 모바일)

    데이터 및 프로세스 흐름 요약

    👨‍💻 1. 개발 & 베포 흐름 (Vibe Coding)

    관리자가 Cursor AI 에디터에서 프롬프트로 지시합니다. Cursor는 MCP 서버를 통해 Turso DB 스키마를 직접 조회/생성합니다. 코드가 완성되면 GitHub로 레포지토리 푸시를 진행하고, Vercel이 웹훅을 감지하여 전 세계 노드에 프론트/백엔드 코드를 자동 배포합니다.

    📄 2. 데이터 사용자 요청 흐름

    사용자가 도메인에 접속하면 Cloudflare가 가장 먼저 요청을 받습니다. 캐시된 파일과 보안(WAF) 검증을 거친 후, 동적 페이지라면 Vercel의 서버리스 함수가 실행됩니다. Vercel은 Turso에서 효율적인 raw SQL로 DB 데이터를 조회한 후 렌더링 된 문서를 반환합니다.

    🖼️ 3. 미디어 파일 서빙 및 업로드

    관리자 페이지에서 보안 JWT 토큰으로 인증한 뒤, 브라우저가 직접 Cloudflare R2로 파일/이미지를 업로드합니다 (Presigned URL 방식 사용). 업로드 된 이미지는 Cloudflare의 전 세계 CDN 엣지에 복제 캐싱되어 어마어마한 트래픽에도 서버 이그레스 비용 없이 서빙됩니다.

    🔒 4. 보안 및 인증 파이프라인

    API 경로들은 Vercel Middleware 계층에서 JWT 검증을 거칩니다. 최고 관리자 계정은 Vercel의 안전한 서버 환경변수에서 초기화되며, 서브 관리자들은 Turso DB의 Hash 비밀번호로 대조/처리됩니다. 모든 DB 트랜잭션과 Storage 쓰기는 Edge에서 완벽히 통제됩니다.

    부록

    17. 환경변수 전체 목록 — .env 완전판

    # ═══════════════ .env (프로덕션) ═══════════════

    # Turso Database

    TURSO_DATABASE_URL=libsql://myproject-db-username.turso.io

    TURSO_AUTH_TOKEN=eyJhxxxxxxxxxxxxxxxx

    # Cloudflare R2

    R2_ACCOUNT_ID=your_cloudflare_account_id

    R2_ACCESS_KEY_ID=your_r2_access_key_id

    R2_SECRET_ACCESS_KEY=your_r2_secret_access_key

    R2_BUCKET_NAME=myproject-assets

    R2_PUBLIC_URL=https://cdn.myproject.com

    # 보안

    JWT_SECRET=랜덤32자이상의영문숫자특수문자조합

    ADMIN_PASSWORD=관리자비밀번호

    # 사이트 설정

    NEXT_PUBLIC_SITE_URL=https://myproject.com

    🚨 3가지 규칙

    1. Git에 절대 커밋하지 마세요. .gitignore에 .env 포함 여부를 반드시 확인.
    2. Vercel에 동일하게 입력하세요. Settings → Environment Variables에 모든 변수 등록.
    3. NEXT_PUBLIC_ 접두사가 붙은 변수만 브라우저에서 접근 가능합니다. 비밀 키에는 절대 붙이지 마세요.
    부록

    18. 관리자 설정 — 인증 시스템 구축

    관리자 로그인은 두 가지 방식을 동시에 지원합니다. 로그인 시 먼저 메인 관리자(환경변수)를 검사하고, 일치하지 않으면 Turso의 admins 테이블에서 추가 관리자 계정을 조회합니다.

    1메인 관리자 — 환경변수 방식

    최상위 관리자 1명. Vercel Settings → Environment Variables에서 등록:

    ADMIN_USERNAME=admin

    ADMIN_PASSWORD=mySecureP@ssw0rd2026!

    • • 코드에서 process.env.ADMIN_USERNAME, process.env.ADMIN_PASSWORD로 읽음
    • • 비밀번호는 평문 비교 (환경변수에만 저장되므로 DB에는 넣지 않음)
    • • 미설정 시 기본값 admin / admin123 → 실서비스에서는 반드시 변경!
    • • 일치 시 JWT에 role: 'main', isMain: true 발급 → 메인 전용 API 사용 가능

    2추가 관리자 — Turso DB 방식

    여러 명의 관리자가 필요할 때 Turso에 admins 테이블을 만듭니다:

    CREATE TABLE IF NOT EXISTS admins (

    id TEXT PRIMARY KEY,

    username TEXT UNIQUE NOT NULL,

    password_hash TEXT NOT NULL,

    role TEXT DEFAULT 'editor',

    is_active INTEGER DEFAULT 1,

    created_by TEXT,

    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,

    last_login DATETIME

    );

    로그인 동작 흐름

    1. 1. 아이디/비밀번호가 환경변수(ADMIN_*) 와 일치 → role: 'main' JWT 발급
    2. 2. 불일치 → SELECT * FROM admins WHERE username = ? AND is_active = 1
    3. 3. bcrypt.compare(password, password_hash) 검증
    4. 4. 성공 → 해당 행의 role로 JWT 발급 (isMain: false)

    💡 비밀번호 해싱 필수!

    비밀번호를 평문으로 저장하면 안 됩니다. bcryptjs로 해시값만 저장합니다. 메인 관리자와 동일한 username은 DB에 등록 불가 (코드에서 중복 체크).

    요약 비교

    구분메인 관리자Turso DB 관리자
    설정 위치Vercel 환경변수Turso admins 테이블
    비밀번호env에 평문DB에 bcrypt 해시
    추가/삭제환경변수 수동 변경/manager/admins에서
    권한main (전용 API)admin 또는 editor
    용도최초 최상위 1명팀원·편집자 여러 명
    부록

    19. 월간 비용 시뮬레이션 — 약 ₩28,250/월

    서비스플랜월 비용
    ☁️ CloudflareFree$0
    📦 Cloudflare R2Free (10GB 내)$0
    🗄️ TursoFree → Developer$0 ~ $4.99
    🚀 VercelHobby$0
    ⌨️ CursorPro$20
    🌐 도메인연간 ÷ 12~₩1,500
    합계 (Turso Free 기준)≈ ₩28,250/월

    💡 핵심: 실 비용의 대부분은 Cursor 구독

    인프라 비용 자체는 도메인 + Turso 정도 (월 ~₩6,500)입니다. Cursor $20이 전체의 70% 이상을 차지합니다. Hobby 플랜으로 시작해서 트래픽이 늘면 Vercel Pro, Turso Developer로 업그레이드하면 됩니다.

    부록

    20. 보안 강화 방법 — 내 사이트를 지키는 법

    1. 인증·세션

    JWT 만료 시간: 프로덕션에서는 expiresIn: '1d' 이하로 설정. 만료가 길수록 탈취 시 노출 기간 증가. refresh token 방식도 검토.
    JWT_SECRET 생성: 32자 이상 랜덤 문자열 사용. openssl rand -base64 32 로 생성해 Vercel env에만 넣고, 코드/문서/Git에는 절대 넣지 않음.
    관리자 비밀번호: 메인(ADMIN_PASSWORD)과 DB 관리자 모두 12자 이상, 대소문자·숫자·기호 조합 권장. 주기적 변경도 좋음.
    로그인 시도 제한: 동일 IP/계정에서 짧은 시간 다수 실패 → 일시 잠금 또는 CAPTCHA. 브루트포스 공격 완화 (구현 시 Redis 또는 DB에 실패 횟수 저장).

    2. HTTPS·쿠키

    Always HTTPS: Cloudflare "Always Use HTTPS" + Vercel 기본 HTTPS. HTTP는 HTTPS로 리다이렉트.
    쿠키 옵션: mb_admin_token은 httpOnly, sameSite: lax, 프로덕션 secure: true. 필요 시 sameSite: strict로 더 엄격히 설정.

    3. API·경로 보호

    관리자 API 보호: 로그인/로그아웃 제외 모든 관리자 API에 requireAuth JWT 검증 미들웨어 적용. 메인 전용 API는 requiredRole: 'main'으로 제한.
    middleware: /manager/* (로그인 제외)는 middleware에서 JWT 검사 후 없거나 만료면 /manager/login으로 리다이렉트. 민감 경로(/api/init-db, /api/admins)는 메인만 호출 가능.

    4. 환경변수·저장소

    .env 커밋 금지. Vercel 환경변수만 사용. Preview 환경은 테스트용 별도 DB·비밀번호를 쓰면 프로덕션 데이터 덮어쓰기 방지. MCP·스크립트에도 Turso URL·토큰을 직접 적지 않고 환경변수로만 전달.

    5. R2·정적 자산

    버킷 정책: 퍼블릭 읽기는 필요 경로만 허용. 업로드·삭제는 API 통해서만, API는 인증된 관리자만 호출.
    업로드 파일 검증: 서버에서 확장자·MIME 타입·파일 크기 제한(예: 10MB) 다시 검사. 클라이언트 검사만으로는 우회 가능. Presigned URL 만료 시간은 짧게(예: 5분).

    6. Cloudflare·네트워크

    DDoS·봇: Bot Fight Mode, Rate Limiting 켜두면 스크래핑·무차별 요청 완화. WAF 규칙: /api/auth/login 등 특정 경로에 IP당 요청 수 제한 → 브루트포스·스팸 방지.
    부록

    21. DB 효율 관리 — 쿼리 최적화와 인덱스

    1. 쿼리·인덱스

    인덱스 추가: 자주 WHERE, ORDER BY, JOIN에 쓰는 컬럼에 인덱스. ensureMigration에서 한 번만 실행.
    CREATE INDEX IF NOT EXISTS
    idx_posts_created_at
    ON posts(created_at DESC);
    SELECT * 지양: 필요한 컬럼만 나열. 네트워크·메모리 절약.
    SELECT id, title, created_at
    FROM posts
    WHERE category = ?
    페이지네이션: 목록 API는 LIMIT + OFFSET (또는 커서 기반)으로 페이지 단위만 가져옴. 한 번에 수백 행 반환하지 않기.
    중복 조회 줄이기: 같은 요청 안에서 동일 테이블 여러 번 읽지 않기. 한 번 조회한 결과를 변수에 담아 재사용.

    2. 쓰기·트랜잭션

    배치 INSERT: 여러 행을 넣을 때 하나씩 execute 대신 트랜잭션으로 묶어 executeMultiple 또는 여러 execute를 한 트랜잭션에서 실행.
    불필요한 UPDATE 최소화: 변경이 잦은 컬럼(마지막 로그인 시각 등)만 업데이트하고, 나머지는 건드리지 않기.
    소프트 삭제 vs 하드 삭제: is_active=0, deleted_at으로 표시하면 복구 쉬움. 하지만 테이블이 계속 커지므로 주기적으로 오래된 "삭제됨" 행을 실제 DELETE 하거나 아카이브 테이블로 이동.

    3. 스키마·데이터

    JSON 컬럼: 단순 저장·표시만 하면 JSON 문자열 OK. 검색·정렬이 자주 필요하면 별도 컬럼이나 정규화된 테이블로 나누기.
    텍스트 길이: 수 MB 단위 본문은 R2에 파일로 올리고 DB에는 URL만 저장하는 방식이 DB 부담을 줄임.

    4. 연결·클라이언트

    getDb() 싱글톤 유지: 요청마다 새 연결 만들지 않기. 현재 방식(한 번만 생성 후 재사용)이 최선.
    ensureMigration 호출 시점: 앱 시작 시 또는 첫 API 호출 시 한 번만 실행되도록. 불필요한 반복 마이그레이션 체크 방지.

    5. 비용·한도

    💡 무료 티어 효율 관리

    Turso 무료 행 읽기 5억 건, 쓰기 1,000만 건은 개인 프로젝트에 충분합니다. 트래픽이 늘면 Next.js fetch cache + revalidate로 동일 데이터 재조회를 줄이세요. 변경이 잦지 않은 데이터(제품 목록, 설정)는 ISR 또는 revalidate로 캐시하면 매 요청마다 DB를 치지 않습니다. 백업·복원: Turso 대시보드에서 스냅샷·백업 정책을 확인하고, 중요한 변경 전에는 수동 백업을 해두는 습관을 권장합니다.

    부록

    22. npm 의존성 목록 — 2026.03 기준

    런타임 의존성 (dependencies)

    패키지버전(^)용도설치
    next^16.1.6React 프레임워크 (App Router, API Routes, SSR)기본 포함
    react / react-dom^19.2.4UI 라이브러리 / DOM 렌더링기본 포함
    @libsql/client^0.17.0Turso(libSQL) DB 연결 및 raw SQL 실행npm i @libsql/client
    @aws-sdk/client-s3^3.1000.0R2(S3 호환) 업로드·삭제·목록 APInpm i @aws-sdk/client-s3
    @aws-sdk/s3-request-presigner^3.1000.0R2 Presigned URL 발급 (대용량/비디오 직접 업로드용)npm i @aws-sdk/s3-request-presigner
    @modelcontextprotocol/sdk^1.27.1Cursor MCP 서버 구현용 SDKnpm i @modelcontextprotocol/sdk
    jsonwebtoken^9.0.2JWT 발급·검증 (관리자 인증)npm i jsonwebtoken
    bcryptjs^3.0.3비밀번호 해시·검증 (DB admins)npm i bcryptjs
    sharp^0.34.5서버 측 이미지 리사이즈·WebP 변환npm i sharp
    zod^4.3.6스키마 검증 (폼·API 요청)npm i zod
    lucide-react^0.575.0아이콘 컴포넌트npm i lucide-react
    clsx^2.1.1조건부 className 조합 유틸npm i clsx
    tailwind-merge^3.5.0Tailwind 클래스 병합·중복 제거npm i tailwind-merge
    framer-motion^12.34.3애니메이션·트랜지션 UI (선택)npm i framer-motion

    개발 의존성 (devDependencies)

    패키지버전(^)용도
    typescript^5.9.3TypeScript 컴파일·타입 검사
    tailwindcss^4.2.1Tailwind CSS v4
    @tailwindcss/postcss^4.2.1Tailwind v4 PostCSS 플러그인
    postcss^8.4.49PostCSS 파이프라인
    autoprefixer^10.4.27CSS 벤더 프리픽스
    eslint^10.0.2코드 린팅
    eslint-config-next^16.1.6Next.js 권장 ESLint 설정
    @types/jsonwebtoken^9.0.7JWT 타입
    @types/bcryptjs^2.4.6bcrypt 타입
    @types/node^22.19.13Node.js API 타입
    @types/react^19.0.7React 타입
    @types/react-dom^19.0.2React DOM 타입
    engines: node >= 18.17.0 — 위 버전은 package.json의 ^ 범위 기준이며, 실제 설치 버전은 package-lock.json에 고정됩니다. 최신화 시점: 2026년 3월 1일.
    부록

    23. 기타 팁과 배포 후 체크리스트 — 마무리

    1. SEO·메타·공유

    메타 태그: 각 페이지별 title, description, og:image를 Next.js Metadata에서 설정. 공유 미리보기와 검색 결과에 영향.
    sitemap/robots: app/sitemap.ts, app/robots.ts로 검색엔진 수집 범위 안내. 관리자 경로는 Disallow: /manager로 제외. Google Search Console에 사이트맵 제출.
    구조화 데이터: 제품·글·조직 정보에 맞는 JSON-LD 스키마를 넣으면 검색 결과에 리치 스니펫 노출 가능.

    2. 성능·체감 속도

    이미지 최적화: Next.js <Image>로 크기·포맷(WebP/AVIF) 자동 조정. sizes로 레이아웃에 맞는 크기만 전달. R2 URL은 next.config images.remotePatterns에 등록 확인.
    폰트: next/font로 폰트를 로컬에서 서빙하면 FOUT/FOIT를 줄이고 체감 속도 향상.
    LCP 개선: 첫 화면 큰 이미지·텍스트는 미리 로드하고, 아래쪽 콘텐츠는 lazy load → 첫 페이지만 빠르게.
    코드 분할: dynamic import로 필요할 때만 로드. 서버 컴포넌트 우선 사용.

    3. 반응형·접근성

    미디어 쿼리: Tailwind sm:, md:, lg:, xl:로 모바일→태블릿→데스크톱 레이아웃 구분. 모바일 퍼스트 접근 — 기본이 모바일, 큰 화면에서 오버라이드.
    터치·포커스: 버튼·링크 터치 영역 충분히. 키보드 포커스 시 outline 보이도록 (focus:ring, focus-visible). 이미지에 의미 있는 alt, 장식용은 alt="".

    4. 폼·문의·스팸

    문의 폼: 서버에서 이메일 형식·길이·필수 필드 다시 검사. 저장 후 이메일 알림(Resend, SendGrid 등) 연동 가능.
    스팸 방지: Honeypot 필드(사람에게 안 보이는 입력란) + reCAPTCHA v3 또는 Cloudflare Turnstile 도입. Rate limit도 함께.

    5. 모니터링·로그

    Vercel Analytics: 배포 사이트에 연결하면 방문 수·성능 지표(Web Vitals: LCP, FID, CLS)를 대시보드에서 모니터링.
    에러 추적: Sentry, LogRocket 등으로 클라이언트/서버 에러 수집. API 키는 환경변수에만 저장. console.log에 비밀번호·토큰·개인정보 출력하지 않기.

    6. 도메인·이메일

    이메일 발신: 자동 발송 시 도메인에 SPF/DKIM을 설정해야 스팸 차단 방지. Iteasy·Cloudflare에서 DNS 레코드 안내 제공.
    서브도메인: 블로그·쇼핑 등을 blog.myproject.com으로 둘 경우, Vercel에서 서브도메인 추가하고 DNS에 CNAME 연결.

    7. 버전·배포

    브랜치 전략: 기능 개발은 feature/xxx 브랜치에서. main에 머지 시에만 프로덕션 배포. Vercel은 main → Production, 그 외 → Preview 자동 설정.
    환경별 설정: 개발(local), Preview(Vercel), Production(Vercel)에서 서로 다른 Turso DB·R2 버킷 사용 → 테스트 데이터가 프로덕션 오염 방지.

    8. 콘텐츠·운영

    관리자 가이드: "이미지는 10MB 이하", "제목은 50자 이내" 같은 간단한 운영 가이드를 문서로 두면 품질 유지 용이.
    백업 주기: Turso 스냅샷·R2 중요 파일은 주기적으로 내려받거나 다른 리전/스토리지에 복사.

    ✅ 배포 후 체크리스트

    • ☑️ https://myproject.com 접속 정상 확인
    • ☑️ http://로 접속 시 자동 HTTPS 리다이렉트
    • ☑️ www.myproject.com → myproject.com 리다이렉트
    • ☑️ SSL 인증서 (자물쇠 아이콘) 확인
    • ☑️ R2 이미지 (cdn.myproject.com/...) 정상 로드
    • ☑️ Turso DB 읽기/쓰기 기능 정상 동작
    • ☑️ 모바일에서 페이지 레이아웃 확인
    • ☑️ Google Search Console에 사이트 등록 및 사이트맵 제출
    • ☑️ Cloudflare Analytics에서 트래픽·보안 이벤트 모니터링
    • ☑️ Vercel Analytics에서 Web Vitals (LCP, FID, CLS) 확인
    • ☑️ Git push 후 자동 배포 확인

    이 체크리스트를 모두 통과하면, 바이브 코딩으로 구축한 전체 스택 웹사이트가 프로덕션 준비 완료된 상태입니다.

    🎉 축하합니다!

    이 가이드의 모든 과정을 완료했다면, 이제 당신만의 홈페이지가 전 세계에 공개되어 있습니다.

    도메인 구매 → DNS → 저장소 → 데이터베이스 → AI 코딩 → GitHub → Vercel 배포
    이 모든 것을 직접 해냈습니다. 바이브 코딩으로. 🚀

    FAQ | 자주 묻는 질문

    Q

    도메인을 꼭 Iteasy에서 사야 하나요?

    A.아닙니다. Iteasy는 국내 도메인(.kr, .co.kr) 등록 시 한글 지원이 완벽하고 세금계산서 발행이 간편하여 초기 진입 장벽을 낮추기 위해 추천한 것입니다. 원하신다면 Cloudflare Registrar, Namecheap, Google Domains 등 저렴한 해외 서비스를 이용하셔도 전혀 문제없습니다. 핵심은 "구매한 도메인의 네임서버(Name Server)를 Cloudflare로 변경하여 연결하는 과정"을 이해하는 것입니다.

    Q

    Cloudflare SSL/TLS를 Full 대신 Flexible로 설정하면 안 되나요?

    A.Vercel, 서버리스 환경과 연동할 때 Flexible 모드는 절대로 피하셔야 합니다. Flexible 모드에서는 Cloudflare와 Vercel 사이의 통신이 암호화되지 않은 HTTP로 이루어집니다. 이 때 Vercel은 보안 정책상 무조건 HTTPS로 접근을 강제하며 리다이렉트를 발생시키고, 이로 인해 끝없는 리다이렉트 루프(ERR_TOO_MANY_REDIRECTS) 에러가 발생하여 사이트 접속이 불가능해집니다. 반드시 Full 또는 Full (strict) 모드를 유지하세요.

    Q

    R2 무료 티어(10GB) 용량이 부족해지면 어떻게 되나요? 갑자기 요금이 폭탄처럼 청구되진 않나요?

    A.걱정하지 않으셔도 됩니다. 자동 결제나 요금 폭탄은 없습니다. R2 사용량이 무료 한도를 초과할 위기에 처하면 Cloudflare에서 경고 알림 메일을 발송합니다. 기본적으로 무료 한도를 넘으면 저장소 추가 작업이 제한될 뿐, 사전 승인 없이 카드로 요금을 자동 청구하지 않습니다. 또한 텍스트 중심의 개인 블로그나 일반적인 포트폴리오 사이트에서 10GB는 수만 장의 이미지를 저장할 수 있을 만큼 매우 넉넉한 공간입니다.

    Q

    Turso 대신 Supabase나 Firebase 등 다른 데이터베이스를 써도 되나요?

    A.물론 가능합니다. Supabase(PostgreSQL 기반)나 PlanetScale(MySQL) 등 원하는 서버리스 DB를 연결하셔도 됩니다. 다만 이 가이드에서 Turso(SQLite 기반)를 채택한 이유는 설정이 매우 직관적이고 가벼워 초기 구축 속도가 압도적으로 빠르기 때문입니다. 더불어 Vercel의 엣지 함수(Edge Functions) 환경과 결합했을 때 콜드 스타트 딜레이가 거의 없어 완벽한 궁합을 보여줍니다.

    Q

    Cursor Pro(유료) 결제 없이 무료 플랜(Hobby)으로도 이 가이드를 따라 할 수 있나요?

    A.Hobby 플랜으로도 기본적인 코딩과 수정은 가능합니다만, "바이브 코딩(AI의 자동화된 에이전트 모드를 활용한 전방위적 개발)"을 제대로 경험하기에는 무료 제공되는 프리미엄 모델 요청 횟수가 금방 고갈됩니다. 중간에 흐름이 끊기면 학습 의욕이 저하될 수 있으므로, 최소한 웹사이트를 구축하는 첫 1개월 정도는 Pro($20/월 구독) 플랜을 결제하여 막힘없이 개발 속도를 체감해보시는 것을 강력히 권장합니다.

    Q

    GitHub Private(비공개) 저장소가 아닌 Public(공개)으로 둬도 해킹의 위험이 없나요?

    A.가장 중요한 원칙은 .env, .env.local과 같이 API 키나 비밀번호가 담긴 환경 변수 파일이 소스 코드에 포함(Commit)되지 않도록 .gitignore 파일에 명시하는 것입니다. 이 원칙만 확실히 지켰다면 Public으로 공개해도 해킹의 위험은 없습니다. 하지만 본인만의 고유한 비즈니스 로직이나 디자인 자산이 포함된 상업용 프로젝트라면 안전하게 Private으로 설정하는 것이 좋습니다.

    Q

    Vercel Hobby(무료) 플랜으로 상업적 수익을 창출하는 사이트를 운영해도 되나요?

    A.불가합니다. Vercel의 서비스 약관상 Hobby 플랜은 개인 포트폴리오, 비영리 블로그, 토이 프로젝트 등 "비상업적(Non-commercial) 용도"로만 제한됩니다. 만약 해당 사이트에 결제 모듈을 붙여 상품을 판매하거나, 구글 애드센스 등 광고를 달아 수익을 낸다면 명백한 약관 위반에 해당하여 경고 없이 계정이 정지될 수 있습니다. 상업용 사이트는 반드시 Pro($20/월) 플랜으로 업그레이드해야 합니다.

    Q

    프로그래밍 경험이 전무한 완전 비전공자도 정말 가능한가요?

    A.충분히 가능합니다. 바이브 코딩의 핵심 프로세스는 "자연어로 요구사항을 묘사(Prompting)하고, AI가 작성한 코드를 승인(Accept)하는 것"입니다. 코드를 직접 한 줄 한 줄 짤 필요는 없습니다. 다만, AI가 뱉어내는 용어들(라우터, 컴포넌트, 프론트엔드, API 등)에 대한 아주 기초적인 웹 생태계 지식이 있다면 에러 상황에서 당황하지 않고 훨씬 수월하게 AI를 지휘할 수 있습니다.

    Q

    유지보수 등 월 고정 비용은 대략 어느 정도 드나요?

    A.Cursor Pro 구독($20)을 제외한 순수 인프라 호스팅 유지 비용은 월 6,500원 미만입니다(도메인 유지비 연간 약 2만원 기준). 트래픽이 초대형 규모로 성장하지 않는 이상 클라우드플레어, 터소, 베르셀의 넉넉한 서버리스 무료 티어 덕분에 서버 유지비용이 거의 발생하지 않는 매우 효율적인 아키텍처입니다.

    CDB
    큐레이터 단비's 웹앱 아이디어 창고

    🧰 웹앱 · 📺 단비 · 📰 이슈트래커 · 📄 기타 페이지를 한 곳에서. 모든 도구를 쉽고 빠르게 사용하세요.

    사이트 방문
    전체-오늘-고유 전체-고유 오늘-
    방문 통계 / 인기 앱 순위 보러 가기→

    제품

    • 모든 도구
    • 카테고리
    • 인기 도구
    • 새로운 도구
    • 사이트맵

    지원

    • 통계
    • 업데이트
    • 도움말
    • 문의하기
    • 버그 신고
    • FAQ

    법적 고지

    • 개인정보처리방침
    • 이용약관
    • 쿠키 정책

    웹앱 아이디어 창고 - 모든 도구를 한 곳에서 © 2025 큐레이터 단비. All right reserved.

    Built with ❤️ using Next.js & Vercel