[사이드프로젝트] : DB 변경 - Neon → Supabase 이전 작업 (예정)
생성일 : 2026.09.30 14:49
inote-server(Prisma) 기준의 DB 이전 기록·작업 리스트. Notion·블로그 정리용 원본. AI 서버(inote-ai)에 해당하는 부분은inote-ai레포의docs/supabase-migration.md참고. 전체 호스팅 이전(Render → Vercel/Koyeb)은inote레포의docs/infra/hosting-migration.md참고. 작성: 2026-09-30 / 상태: 🟡 준비 중 (아직 이전 시작 전)
1. 결정 사항
항목 | 결정 |
|---|---|
이전 대상 | Neon PostgreSQL 2개 → Supabase |
프로젝트 개수 | 2개로 분리: |
AI DB | BE DB에 합친다 (별도 프로젝트를 만들지 않음) |
리전 | 미국 동부(us-east-1, 버지니아) — Koyeb(워싱턴 D.C.)·Vercel(iad1)과 가깝게 |
진행 시점 | BE가 Render 정지로 내려가 있어 사용자 영향 없음 → 지금 전환하기에 좋은 시점 |
왜 2개로 나누나
지금은 로컬 개발과 운영이 같은 Neon DB를 써서, 통합 테스트를 돌리면 운영 데이터를 건드릴 수 있었다.
dev 프로젝트가 생기면 이 위험이 사라지고, 통합 테스트용 DB도 함께 해결된다.
왜 AI DB를 합치나
현재 DB 2개: BE용 약 9.4MB(테이블 22개), AI용 약 7.8MB(테이블 2개, 행 21개) → 합쳐도 약 17MB.
관리할 DB·비밀번호·환경 변수가 1세트로 줄어든다.
2. 현재 상태 (2026-09-30 측정)
DB | 호스트(Neon) | 크기 | 테이블 | 확장 |
|---|---|---|---|---|
BE ( |
| 9.4MB | 22개 | 기본(plpgsql)만 |
AI ( |
| 7.8MB | 2개 ( | 기본만 |
특수 확장(pgvector 등)을 쓰지 않아 호환 문제가 적다.
Prisma 마이그레이션 폴더에는 3개(init, better_auth, money_models)만 있고, 이후 모델(PostCategory, Todo, ReadingLog, Post.isPrivate/pinned/thumbnailUrl 등)은
db push로 반영해 왔다. →migrate deploy만으로는 새 DB에 최신 스키마가 만들어지지 않는다 (아래 4-2 참고).
3. Supabase 연결 방식 정리
사용처 | 배포 형태 | 연결 주소 | 비고 |
|---|---|---|---|
BE (Koyeb, Prisma) | 상시 서버(컨테이너) | Session pooler, 포트 5432 | 서버 배포는 세션 풀러가 공식 권장 |
BE 마이그레이션(CLI) | 로컬/배포 시 | Session pooler 5432 (또는 직접 연결) | |
AI (Vercel, psycopg) | 서버리스 | Transaction pooler, 포트 6543 |
|
주소 형식(공식 문서):
postgres://[사용자].[프로젝트REF]:[비밀번호]@aws-0-us-east-1.pooler.supabase.com:5432/postgres(트랜잭션 모드는 포트 6543 + Prisma 사용 시?pgbouncer=true).Supabase 직접 연결(
db.xxx.supabase.co)은 IPv6 전용이라 Koyeb·Vercel에서 못 붙을 수 있다 → 풀러 주소를 쓴다.세션 풀러는 동시 연결 수가 제한적이므로 Prisma
connection_limit을 작게(예: 5) 둔다.Prisma 전용 DB 사용자(
prisma)를 만들어 쓰는 것이 공식 권장:create user "prisma" with password '...' bypassrls createdb;+public스키마 권한 부여.(확인 필요) 이 레포는 Prisma 6.19이고
prisma.config.ts에datasource.url이 있다. CLI가 어느 주소를 쓰는지,schema.prisma의directUrl이 필요한지는 실제로 돌려 보며 확인.
4. 작업 리스트
4-1. 준비
미완료Supabase 가입, 프로젝트 2개 생성 (
inote-prod,inote-dev), 리전 us-east-1, 강한 DB 비밀번호 (비밀번호는 문서·채팅에 붙이지 않는다)미완료두 프로젝트에서 Prisma용 DB 사용자(
prisma) 생성·권한 부여미완료연결 주소 확보(값은 적지 않음): prod·dev 각각 Session pooler 5432(BE), Transaction pooler 6543(AI)
미완료로컬에
pg_dump/psql설치 (현재 없음 — 예:brew install libpq). 버전은 Neon 서버 버전 이상이어야 덤프 가능미완료Neon 서버 버전 확인 (
show server_version)미완료이전 전 Neon 전체 백업 덤프를 로컬에 저장 (롤백용, 저장소에 커밋하지 않음 — 개인 데이터)
미완료Neon 데이터 행 수 기록 (이전 후 대조용): 테이블별
count(*)
4-2. 스키마 (BE)
미완료마이그레이션 기준선 정리: 기존 3개 마이그레이션은 최신 스키마를 못 만든다. 현재
schema.prisma로부터 새 기준선(baseline) 마이그레이션을 생성해 기존 것을 대체하고, 기존 DB에는 "적용됨"으로 표시하는 방식을 정한다 (prisma migrate diff --from-empty --to-schema-datamodel ... --script). → 별도 결정 필요미완료
inote-dev에서 먼저 스키마 생성·migrate deploy검증미완료
inote-prod에 같은 방식으로 스키마 생성미완료
start:prod의prisma migrate deploy와PRISMA_SCHEMA_DISABLE_ADVISORY_LOCK=1유지 여부 확인 (풀러 환경에서 lock 타임아웃이 재현되는지)
4-3. 데이터 이전
미완료BE 데이터: Neon(
ep-fancy-bar) →inote-prod(pg_dump --data-only --no-owner --no-acl→ 복원, 또는 테이블 순서(FK)를 지켜 복원)미완료시퀀스·제약 조건 확인 (id는 cuid 문자열이라 시퀀스 문제는 적음)
미완료행 수 대조: 이전 전·후 테이블별
count(*)비교미완료세션(Better Auth
session테이블) 처리 방침: 그대로 옮기면 로그인 유지, 안 옮기면 모두 재로그인 (둘 다 문제 없음 — 결정만)미완료dev 프로젝트에는 운영 데이터를 복사하지 않거나, 복사한다면 개인 정보(이메일 등)를 비우는 정책을 정한다
4-4. AI 테이블 합치기 (상세는 inote-ai 문서)
미완료prod DB에 **별도 스키마
ai**를 만들고 그 안에 AI 테이블 2개를 생성미완료Neon AI DB(
ep-wispy-moon)의 데이터(세션 5, 대화 16)를 이전이유: Prisma
db push는 스키마에 없는 테이블을 지우려 할 수 있다. AI 테이블을public에 두면 BE에서db push를 돌릴 때 위험 → 별도 스키마로 격리
4-5. 보안 (Supabase 특성)
미완료
public테이블이 REST(Data API)로 자동 노출되는지 확인, RLS 활성화 또는 Data API 노출 끄기미완료
ai스키마는 API 노출 대상에서 제외 확인미완료anon/service 키는 사용하지 않으므로 어디에도 노출되지 않게 함 (프로젝트는 DB 직접 연결만 사용)
미완료비밀번호 재설정: Neon 비밀번호는 채팅에 노출된 적이 있으니 Neon은 전환 후 삭제(또는 비밀번호 폐기)
4-6. 환경 변수 교체 (값은 적지 않는다)
서비스 | 변수 | 교체 내용 |
|---|---|---|
BE (Koyeb) |
|
|
AI (Vercel) |
|
|
로컬 BE |
|
|
로컬 AI |
|
|
미완료위 값 교체 후 BE·AI 재배포
미완료로컬과 운영이 서로 다른 DB를 쓰는지 최종 확인
4-7. 검증
미완료BE 헬스체크(
/api/v1/health), 로그인(Google OAuth), 글 작성·저장·목록·상세, 카테고리, 이미지 업로드미완료AI
/health/db= ok(테이블 존재 확인 포함), 요약·채팅 저장·세션 조회미완료글에 연결된 채팅(BE 작성자 확인) 동작
미완료BE 단위 테스트, FE 테스트 전체 통과
미완료행 수 대조 결과 일치
미완료Supabase 대시보드에서 연결 수·에러 로그 확인
4-8. 전환(컷오버)과 롤백
쓰기 중단 안내(개인 앱이라 본인만 안 쓰면 됨) — 현재는 BE 정지 상태라 자동으로 충족
Neon 최종 덤프 →
inote-prod복원 → 행 수 대조환경 변수를 Supabase 주소로 교체 → 재배포 → 검증(4-7)
롤백: 문제가 생기면 환경 변수를 Neon 주소로 되돌린다(전환 후 새로 쌓인 데이터는 별도 이전 필요). 안정화될 때까지 Neon은 삭제하지 않고 유지
1~2주 안정 운영 후 Neon 정리
4-9. 마무리
미완료
inote-server/inote-aiREADME·CLAUDE.md의 DB 정보(Neon → Supabase) 최신화,DATABASE.md·docs/갱신미완료Supabase 무료 플랜 일시정지 정책(1주 무활동 시 정지) 대응 방안 결정 — 정기 호출 또는 주기적 접속
미완료통합 테스트를
inote-dev에서 돌릴 수 있게 설정 (inoteCLAUDE.md의 "테스트 전용 DB" 항목 충족)미완료Notion·블로그 정리 (이 문서 기준)
5. 위험 요소와 대응
위험 | 대응 |
|---|---|
Supabase 무료 프로젝트가 1주 무활동 시 일시정지 | 정기 호출(예: BE 헬스체크가 DB를 조회), 정지되면 수동 재개 |
세션 풀러 연결 수 제한으로 "max clients" 에러 | Prisma |
새 DB에서 | 기준선 마이그레이션 재생성 (4-2) |
| AI 테이블을 |
테이블이 REST API로 공개 노출 | RLS 활성화 또는 Data API 노출 끄기 (4-5) |
덤프/복원 도구 버전 불일치 |
|
이전 후 문제 발견 | Neon을 유지해 두고 환경 변수로 즉시 롤백 (4-8) |
6. 예상 소요 (데이터 약 17MB)
단계 | 시간 |
|---|---|
프로젝트 생성·권한 설정 | 약 30분 |
스키마 기준선 정리·검증 | 1시간 전후 |
데이터 이전·대조 | 30분 이내 |
AI 스키마 분리·코드 수정·검증 | 1시간 전후 |
환경 변수 교체·재배포·전체 검증 | 1시간 전후 |
합계 | 약 반나절(3~5시간) |
7. 진행 로그
날짜 | 한 일 | 결과·메모 |
|---|---|---|
2026-09-30 | 데이터 규모 측정, 결정(프로젝트 2개·AI DB 합치기), 이 문서 작성 | 준비 완료, 이전 시작 전 |
8. 트러블슈팅 (겪으면 채우기)
9. 참고 자료
Supabase × Prisma 연결 가이드:
Supabase 요금·무료 한도:
무료 플랜 제한 정리: