https://drive.google.com/file/d/1kI4g9ici-3R3o5lIJWV4LTnyi_Xug-6V/view?usp=drive_link

DB_SPEC_DEFINITION.md

App ↔ DB Integration Spec Definition

목적: Next.js(App Router) + Prisma ORM + PostgreSQL + Supabase(로컬 CLI / 호스티드 Cloud) + Vercel 배포 환경에서의 DB 연동 스펙을 도메인 비의존적으로 정의한다. 새 프로젝트를 시작할 때 이 문서를 그대로 적용하면 로컬 개발부터 운영 배포까지의 DB 파이프라인이 구성된다.


1. 기술 스택 및 버전

구성 요소 기술 버전 (최소) 비고
Runtime Node.js 24.x .nvmrc로 고정
Package Manager pnpm 9.x package.jsonpackageManager 필드
Framework Next.js (App Router) 16.x next.config.ts
ORM Prisma 6.x @prisma/client (런타임), prisma (devDep, CLI)
DB Engine PostgreSQL 17 Supabase CLI의 config.toml에서 major_version 지정
로컬 DB Supabase CLI (Docker) latest (pnpm dlx supabase) PostgreSQL + 최소 서비스
호스티드 DB Supabase Cloud Transaction Pooler + Direct Connection
배포 플랫폼 Vercel Git 연동 자동배포
환경변수 검증 Zod 4.x lib/env.ts에서 런타임 스키마 검증
CI/CD GitHub Actions prod 마이그레이션 자동화

2. 환경 모델 (3-tier)

로컬·Preview·Production 세 계층으로 분리한다. 로컬은 호스티드와 완전히 분리된 별도 DB 인스턴스이다.

계층 DB 인스턴스 앱 URL 마이그레이션 적용 방법
Local Supabase CLI (Docker, 127.0.0.1:54322) http://localhost:3000 pnpm db:migrate (자유롭게)
Preview 호스티드 Supabase (Production과 공유¹) PR별 Vercel Preview URL 별도 적용 안 함 (prod 스키마 공유)
Production 호스티드 Supabase Production URL main 머지 시 GitHub Action 자동 db:deploy

¹ 초기에는 Preview와 Production이 같은 DB를 공유한다. 실 사용자 데이터가 적재되기 시작하면 Preview용 별도 Supabase 프로젝트로 분리한다.

핵심 원칙: dev/prod 패리티는 "같은 엔진(PostgreSQL) + 같은 스키마"를 뜻하지, 같은 인스턴스를 공유한다는 뜻이 아니다.


3. 프로젝트 구조 (DB 관련 파일 맵)

<project-root>/
├── .env                        # 로컬 Supabase 기본값 (gitignore 대상)
├── .env.example                # 커밋 대상 — 로컬 기본값 템플릿
├── .env.local                  # Vercel CLI가 생성 (gitignore 대상)
├── .gitignore                  # .env, .env.local, .env.*.local 포함
├── prisma/
│   ├── schema.prisma           # Prisma 스키마 (SoT)
│   ├── migrations/             # Prisma 마이그레이션 SQL 디렉토리
│   │   ├── <timestamp>_<name>/ # 각 마이그레이션 (migration.sql)
│   │   └── migration_lock.toml # provider lock (postgresql)
│   └── seed.mjs                # 시드 스크립트 진입점
├── prisma.config.ts            # Prisma 설정 (schema 경로, seed 명령)
├── lib/
│   ├── db.ts                   # PrismaClient 싱글턴 팩토리
│   ├── env.ts                  # 환경변수 Zod 스키마 + getter 함수
│   └── health.ts               # DB 헬스체크 로직
├── app/
│   └── api/health/route.ts     # GET /api/health — DB 연결 검증 엔드포인트
├── scripts/
│   ├── db/
│   │   ├── guarded-migrate.mjs # 로컬 전용 마이그레이션 가드
│   │   └── test-integration-local.mjs  # 통합테스트 원스텝 러너
│   ├── load-env.ts             # CLI 스크립트용 .env 로더
│   ├── sync-env.mjs            # 워크트리 간 .env 복사
│   └── validate-env.mjs        # 빌드 시 환경변수 사전검증
├── supabase/
│   └── config.toml             # Supabase CLI 로컬 설정
├── vercel.json                 # Vercel 빌드/설치 명령
├── .github/
│   └── workflows/
│       └── migrate-prod.yml    # prod 마이그레이션 자동화 Action
└── package.json                # npm scripts (db:*, 빌드 훅)

4. Supabase CLI — 로컬 PostgreSQL

4.1 supabase/config.toml 설정

project_id = "<project-name>"

[api]
enabled = true
port = 54321
schemas = ["public", "graphql_public"]
extra_search_path = ["public", "extensions"]
max_rows = 1000

[db]
port = 54322
shadow_port = 54320
major_version = 17

[db.pooler]
enabled = false
port = 54329
pool_mode = "transaction"
default_pool_size = 20
max_client_conn = 100

[studio]
enabled = false
port = 54323

[auth]
enabled = false

[storage]
enabled = false