← 전체 글로 돌아가기

웹 개발

데이터베이스 시드(seed) 데이터를 다룰 때 실수 줄이는 방법

데이터베이스 개발 환경을 셋업할 때 시드 스크립트가 제대로 작동하고 운영에 영향을 주지 않도록 관리하는 방법을 다룬다.

개발할 때 테스트 데이터가 필요하다. 보통 시드(seed) 스크립트로 초기 데이터를 넣는데, 이 과정에서 실수하면 로컬과 운영 환경의 데이터가 꼬인다.

시드 스크립트는 반드시 개발 환경에서만 작동하도록

시드 스크립트가 실수로 운영 환경에서 실행되는 상황을 방지해야 한다:

// prisma/seed.ts
const prisma = new PrismaClient();

// 반드시 환경 체크
if (process.env.NODE_ENV === 'production') {
  console.error('❌ Seeding is not allowed in production!');
  process.exit(1);
}

async function main() {
  console.log('Seeding database...');

  // 시드 데이터 생성
  const user = await prisma.user.create({
    data: {
      email: '[email protected]',
      name: 'Test User'
    }
  });

  console.log(`Created user: ${user.id}`);
}

main()
  .catch(e => console.error(e))
  .finally(async () => await prisma.$disconnect());

시드 스크립트 실행 전에 확인사항

# 1. 현재 환경 변수 확인
echo $NODE_ENV
echo $DATABASE_URL

# 2. 데이터베이스 연결 확인
psql -U postgres -d mydb -c "SELECT version();"

# 3. 기존 데이터가 있는지 확인 (중복 피하기)
psql -U postgres -d mydb -c "SELECT COUNT(*) FROM users;"

멱등성(idempotency): 몇 번 실행해도 같은 결과

시드를 여러 번 실행해도 중복 데이터가 생기지 않도록:

async function seedUsers() {
  const testUser = await prisma.user.upsert({
    where: { email: '[email protected]' },
    update: {},  // 이미 있으면 업데이트 안 함
    create: {
      email: '[email protected]',
      name: 'Test User'
    }
  });
  return testUser;
}

Or with explicit deletion:

async function seedUsers() {
  // 기존 데이터 삭제
  await prisma.user.deleteMany({
    where: {
      email: { startsWith: 'test-' }
    }
  });

  // 새 데이터 생성
  const user = await prisma.user.create({
    data: {
      email: '[email protected]',
      name: 'Test User'
    }
  });

  return user;
}

관계 있는 데이터(Foreign Key) 다루기

테이블 간 관계가 있으면 순서가 중요하다:

async function main() {
  // 1. 부모 데이터 먼저
  const user = await prisma.user.upsert({
    where: { email: '[email protected]' },
    update: {},
    create: {
      email: '[email protected]',
      name: 'Test User'
    }
  });

  // 2. 그 다음 자식 데이터
  const post = await prisma.post.upsert({
    where: { id: 'post-1' },
    update: {},
    create: {
      id: 'post-1',
      title: 'Test Post',
      authorId: user.id
    }
  });
}

역순으로 하면 외래키 제약 위반 에러가 난다.

큰 데이터셋을 효율적으로 로드

수천 개의 테스트 데이터가 필요한 경우:

async function seedLargeDataset() {
  const users = Array.from({ length: 1000 }, (_, i) => ({
    email: `user${i}@example.com`,
    name: `User ${i}`
  }));

  // 한 번에 여러 개 생성 (더 빠름)
  await prisma.user.createMany({
    data: users,
    skipDuplicates: true
  });
}

운영 환경으로의 실수 전환 방지

시드 데이터는 보통 특별한 마크를 해서 구분한다:

// 모든 시드 데이터에 특별한 플래그
const user = await prisma.user.create({
  data: {
    email: '[email protected]',
    name: 'Test User',
    isTestData: true  // ← 이 플래그로 필터링 가능
  }
});

이렇게 하면 운영 환경에서 실수로 테스트 데이터를 조회하지 않도록 쿼리를 짤 수 있다:

// 운영 환경에서는 테스트 데이터 제외
const users = await prisma.user.findMany({
  where: {
    isTestData: false
  }
});

시드 스크립트 실행 기록

いつ、誰が、뭘 했는지 기록해두면 나중에 문제를 추적할 때 도움된다:

#!/bin/bash
# seed.sh

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting seed..." >> seed.log
echo "User: $(whoami)" >> seed.log
echo "Environment: $NODE_ENV" >> seed.log

node prisma/seed.ts >> seed.log 2>&1
if [ $? -eq 0 ]; then
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] Seed completed successfully" >> seed.log
else
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] Seed failed" >> seed.log
  exit 1
fi

테스트 데이터 정리

테스트 후 정리하는 것도 중요하다:

# 모든 테스트 데이터 삭제
npx prisma db seed  # 현재 정의된 시드로 재설정

# 또는 개발 DB 초기화
npx prisma migrate reset

시드 스크립트를 제대로 다루면 로컬 환경을 항상 깨끗하게 유지할 수 있고, 운영 데이터를 실수로 손상시키는 일을 방지할 수 있다.