먼저, 무엇을 어디로 옮기는지 정합니다

쭈니박스는 서비스별 GitHub 저장소를 Cloudflare Pages에 연결해 프론트엔드를 배포합니다. 이 글이 있는 본도메인은 빌드 없는 정적 HTML이고, 아케이드는 빌드를 거치는 앱이며 Supabase를 인증과 데이터 저장에 사용합니다. 같은 브랜드 안에서도 사이트의 실행 방식은 다릅니다.

새 사이트를 받는다면 별도 저장소와 Pages 프로젝트로 분리하는 방식을 권합니다. 독립된 회원·데이터를 갖는 서비스는 별도 Supabase 프로젝트를 우선 검토합니다. 이는 이관 범위와 장애 영향을 줄이기 위한 설계 제안이며, 모든 사이트가 반드시 Supabase를 써야 한다는 뜻은 아닙니다. 기존 백엔드를 계속 쓰면서 화면만 옮기는 것도 선택지입니다.

첫 판단은 프레임워크 이름보다 “운영 중 요청을 처리할 서버가 필요한가?”입니다. 빌드할 때 Node.js를 쓰는 것과, 방문할 때마다 Node.js 서버가 필요한 것은 다릅니다. Cloudflare Pages가 게시할 출력 폴더를 만들 수 있다면 프론트 이전을 검토할 수 있습니다. 서버 기능은 실행 환경을 따로 확인합니다.

세 가지 폴더를 받았다고 가정해 봅시다

다음은 구조를 비교하기 위한 가상 사례입니다. 실제 고객 사이트나 쭈니박스의 이관 실적을 뜻하지 않습니다.

예 A. 소개 페이지 파일이 public 폴더에 있습니다

site/
  public/
    index.html
    about.html
    404.html
    assets/
  README.md

HTML·CSS·이미지가 완성된 상태이고 회원가입이나 서버 저장이 없다면, 게시할 폴더는 public입니다. 빌드 단계가 없으므로 설치 명령을 새로 만들 필요도 없습니다. Cloudflare 설정의 프로젝트 루트와 게시 출력 폴더를 구별해야 합니다. 루트는 소스가 있는 곳이고, 출력 폴더는 외부에 공개할 파일이 있는 곳입니다.

이 경우 확인할 핵심은 파일 누락, 대소문자가 다른 이미지 경로, 페이지 링크, 문의 버튼의 실제 수신처입니다. 화면에 문의 폼이 있다는 이유만으로 정적 사이트라고 결론내리면 안 됩니다. 폼이 원래 제작 플랫폼의 서버로 전송된다면 그 연결을 유지할지 교체할지 정해야 합니다. 모두 확인되면 프론트 이관 시험을 바로 시작할 수 있는 유형입니다.

예 B. Vite 소스가 있고 빌드하면 dist가 생깁니다

site/
  src/
  public/
  package.json
  pnpm-lock.yaml
  vite.config.ts
  dist/                 ← 빌드 결과

이 예에서 package.json의 build 스크립트가 Vite 빌드이고 실제 결과가 dist라면 Pages 출력 폴더도 dist입니다. src를 게시하지 않습니다. 또 Vite의 public은 빌드에 복사될 정적 자산을 담는 폴더이므로, 예 A의 게시 폴더와 이름이 같다고 역할까지 같지는 않습니다. 이름보다 생성된 파일을 확인해야 합니다.

새로 받은 소스를 별도 작업 폴더에서 잠금 파일에 맞는 도구와 버전으로 설치하고, 문서에 적힌 빌드를 실행해 봅니다. 빌드는 성공했지만 로그인 버튼이 원래 사이트의 API를 호출할 수도 있습니다. API와 로그인까지 작동해야 전체 이관을 판단할 수 있습니다. 표준 Vite 출력 예시는 Cloudflare의 빌드 설정 문서에서 확인할 수 있습니다. 설정 위치는 Cloudflare Dashboard → Workers & Pages → 해당 Pages 프로젝트 → Settings → Builds & deployments의 빌드 설정입니다. 화면 개편에 따라 세부 항목명이 달라질 수 있습니다.

예 C. Node 서버가 SQLite와 uploads 폴더에 씁니다

site/
  server.js             ← 운영 중 계속 실행
  data/site.sqlite      ← 요청을 받을 때 수정
  uploads/              ← 사용자가 올린 원본 파일
  package.json

이 사이트는 폴더를 Pages에 올리는 것만으로 같은 동작을 얻을 수 없습니다. 정적 파일 게시와 서버 프로세스·영구 저장소 운영은 다른 일입니다. 서버를 기존 호스팅에 유지할지, 데이터를 Supabase 등으로 옮기고 API를 고칠지 먼저 결정합니다. DB 이전에는 자료형, 자동 증가 ID, SQL 문법 차이도 포함됩니다.

Next.js라는 이름만으로 정적 사이트라고 판단해서도 안 됩니다. 정적 export인지, SSR·서버 동작이 필요한지 확인해야 합니다. 현재 Cloudflare도 정적 Next.js는 Pages, 풀스택 앱은 Workers 경로로 안내합니다. Cloudflare의 Next.js 배포 안내를 해당 버전과 함께 확인하세요. 이 예는 런타임과 데이터 대체 방안을 정한 뒤 이관 시험을 시작할 유형입니다.

제작자에게 받을 것은 소스와 재현 방법입니다

내려받기 버튼이 있어도 편집 가능한 소스, 배포된 정적 결과물, 데이터 export 중 무엇을 주는지 다릅니다. 결과 HTML만 받으면 현재 화면을 게시할 수는 있어도 다음 수정 때 같은 결과를 만들지 못할 수 있습니다. 소스·이미지·폰트의 사용 권리와 데이터 반출 권한을 확인하고, 제작 도구를 해지했을 때 사라지는 기능을 표시합니다.

  1. 현재 배포 버전: 운영 중인 소스 커밋 또는 내보내기 날짜와 파일 목록을 받습니다.
  2. 재현 방법: 런타임·패키지 관리자 버전, 잠금 파일, 설치·빌드·실행 명령과 결과 폴더를 받습니다. 빌드 없는 사이트는 그 사실을 적습니다.
  3. URL 목록: 첫 화면뿐 아니라 상세 페이지, 로그인, 관리자, API, 결제·이메일 callback과 webhook을 구별합니다.
  4. 데이터 위치: DB·사용자 계정·파일·브라우저 저장소에 무엇이 있는지 확인합니다.
  5. 외부 설정: DNS, 리다이렉트, 이메일 발송, OAuth 공급자, 결제, CAPTCHA 등 저장소 밖의 연결을 받습니다.

“제 컴퓨터에서는 됩니다”라는 답이 오면, 필요한 설정 하나가 문서에서 빠졌다고 생각하고 찾아야 합니다. 성공 여부만 받지 말고 실행 명령과 오류가 난 단계를 함께 남깁니다. API 키나 비밀번호의 실제 값은 보고서와 채팅에 넣지 않습니다.

화면에서 쓰는 키와 서버 권한을 분리합니다

Supabase의 publishable key와 기존 anon key는 브라우저에서 사용할 수 있습니다. secret key와 기존 service_role key는 서버 전용입니다. 서버 전용 키는 RLS를 우회할 수 있으므로 프론트엔드 코드·배포 파일에 넣으면 안 됩니다. “환경변수에 넣었다”는 말만으로는 충분하지 않습니다. 빌드 도구가 그 값을 브라우저용 JavaScript에 포함하는지 확인해야 합니다. Supabase API 키 구분에 각 키의 권한과 용도가 설명돼 있습니다.

인수인계표에는 VITE_SUPABASE_URL 같은 변수 이름, 사용 파일, 공개용/서버용 구분, preview/운영 주입 위치와 관리 담당자만 씁니다. 키를 확인하는 접근 경로는 Supabase Dashboard → 해당 프로젝트 → Settings → API Keys입니다. 실제 값은 권한 있는 담당자가 해당 환경에 직접 설정합니다.

공개 키의 안전성은 데이터 접근 정책까지 함께 검증해야 판단할 수 있습니다. RLS는 같은 테이블이라도 사용자에 따라 읽거나 바꿀 수 있는 행을 제한합니다. API로 노출되는 테이블의 권한과 RLS 정책을 확인하고, Storage에도 별도 접근 정책을 적용합니다. RLS 안내와 Storage 접근 정책을 기준으로 실제 요청을 시험합니다.

개인 메모 앱이라면 이 세 번의 요청을 비교합니다

가상 사용자 A가 자기 메모를 저장하고 다시 읽습니다. 다음으로 사용자 B가 같은 메모의 ID를 지정해 읽기와 수정을 시도합니다. 마지막으로 로그아웃 상태에서 같은 요청을 보냅니다. 개인 메모라면 A만 성공해야 합니다. 화면의 버튼을 숨겼더라도 B의 직접 요청이 성공한다면 권한 이전은 끝나지 않았습니다. 관리자 키로만 테스트하면 이 차이를 놓칠 수 있습니다.

DB, 계정, 파일, 브라우저 데이터를 따로 셉니다

“백업 완료”를 한 칸으로 표시하면 사진 원본이나 로그인 설정이 빠지기 쉽습니다. 각 묶음마다 무엇을 복사했고 어떻게 복구를 확인했는지 적습니다. 예를 들어 가상 서비스에 메모 120건과 첨부 파일 40개가 있다면, 메모 120건을 옮겼다는 결과만으로 파일 이관까지 끝났다고 볼 수 없습니다.

데이터베이스: 행 수와 관계를 함께 확인합니다

스키마와 데이터, 함수·트리거·권한을 구별해 내보내고 시험용 대상에서 복구합니다. 테이블별 행 수뿐 아니라 사용자 ID, 첨부 연결, 시간대, 중복·누락을 대조합니다. SQL 변경 이력을 migration으로 남기면 새 환경에서도 같은 구조를 재현하기 쉽습니다. Supabase migration 안내를 적용하되, 운영 DB를 초기화하는 명령을 이관 확인용으로 실행하지 않습니다.

Auth: 계정 데이터와 로그인 설정은 별도입니다

기존 계정 ID를 유지할 수 있는지, 비밀번호 방식이 호환되는지, 기존 로그인 제공자 연결을 옮길 수 있는지 확인합니다. 비밀번호를 평문으로 받는 방식은 쓰지 않습니다. 호환되지 않는다면 재설정·재인증 절차를 정하고 사용자에게 안내합니다. DB에 사용자 행이 있다고 OAuth 공급자 설정, 이메일 템플릿, callback 주소와 기존 세션까지 자동 이전되는 것은 아닙니다. 이관 후 로그인한 사용자가 예전 자기 데이터를 볼 수 있어야 합니다. Supabase 프로젝트 간 이전이라면 공식 백업·복원 절차에서 DB 복원 이후 별도로 옮길 설정을 함께 확인합니다.

Storage: 파일 목록과 파일 내용은 다릅니다

Supabase의 DB 백업에는 Storage 파일의 메타데이터가 포함되지만 파일 원본 자체는 포함되지 않습니다. 파일 원본은 별도로 옮겨야 합니다. 객체 수·크기·경로·소유자와 공개 여부를 대조하고, 실제 파일을 열어 보며 필요하면 checksum도 비교합니다. 이전 프로젝트 주소가 들어 있는 파일 URL과 만료되는 서명 URL도 확인합니다. 이 구분은 Supabase 백업 문서에 명시돼 있습니다. 확인 위치는 Supabase Dashboard → 해당 프로젝트 → Database → Backups, 파일 위치는 같은 프로젝트 → Storage → 해당 bucket입니다.

브라우저 저장소: 도메인을 바꾸면 별도 이전이 필요합니다

localStorage는 출처(origin)에 묶입니다. 예를 들어 https://old.example.com에 저장한 설정을 https://new.example.com에서 자동으로 읽지 못합니다. HTML 표준의 localStorage 정의도 이 경계를 따릅니다. IndexedDB의 초안이나 오프라인 데이터, 서비스 워커 캐시가 있는 앱도 별도 확인 대상입니다. 사용자에게 필요한 기록이 여기에만 있다면 기존 주소에서 내보내기, 새 주소에서 가져오기 같은 경로를 먼저 마련해야 합니다. 같은 origin을 유지하는 호스팅 이전이라도 저장 형식·캐시 버전의 호환성은 검사합니다. IndexedDB와 Cache API의 저장 경계는 웹 저장소 표준에서도 확인할 수 있습니다.

운영 주소를 옮기기 전에 시험 주소에서 끝까지 써봅니다

Cloudflare Dashboard → Workers & Pages → 해당 Pages 프로젝트 → Deployments에서 배포 결과와 pages.dev 주소를 확인합니다. 우선 테스트용 데이터와 계정으로 새 사이트의 핵심 흐름을 끝까지 수행합니다. 첫 화면이 정상이어도 상세 경로를 새로고침하거나 로그인 후 돌아올 때 실패할 수 있습니다.

  • 주소창에서 상세 페이지에 직접 진입하고 새로고침합니다. 없는 주소는 실제 HTTP 404인지 확인합니다.
  • 공개 글은 초기 HTML에 본문이 있는지, 제목·설명·canonical과 사이트맵 주소가 맞는지 확인합니다.
  • 가입·로그인·로그아웃·비밀번호 재설정, 저장·수정·삭제, 파일 업로드를 서비스가 지원하는 범위에서 시험합니다.
  • 비공개 페이지와 타인 데이터에 대한 거부 동작, 이전 도메인으로 나가는 API 요청도 확인합니다.

Supabase 로그인 복귀 주소는 Supabase Dashboard → 해당 프로젝트 → Authentication → URL Configuration에서 Site URL과 Redirect URLs를 확인합니다. preview와 운영 주소를 구별하고 운영 callback은 필요한 정확한 경로를 등록합니다. 운영 프로젝트의 Site URL을 시험 주소로 바꾸면 실제 사용자의 이메일 로그인 흐름에도 영향을 줄 수 있습니다. Supabase Redirect URLs 안내를 기준으로 설정합니다.

Google 같은 OAuth 공급자에 등록하는 Supabase callback과, Supabase에서 브라우저를 돌려보내는 사이트 URL은 서로 다른 단계입니다. Supabase 프로젝트를 바꾸면 공급자 쪽 설정도 확인해야 합니다. Edge Function의 CORS 허용 출처, 결제 webhook, CAPTCHA 허용 호스트도 같은 방식으로 대조합니다. CORS는 로그인이나 데이터 권한을 대신하지 않습니다.

전환 계획에는 되돌아갈 때의 데이터도 포함합니다

데이터가 있는 서비스라면 최종 복사 시점과 쓰기 중지 시간을 먼저 정합니다. 사이트 화면을 점검 중으로 바꿔도 API나 webhook이 계속 저장할 수 있으므로 실제 쓰기 경로 전체를 확인합니다. 잠시 멈출 수 없다면 변경분을 추적·동기화하는 방법을 별도로 설계해야 합니다.

  1. 기존 배포 버전, 도메인 연결과 필요한 DNS 레코드, DB·파일 백업 기준 시각을 기록합니다.
  2. 합의한 시점에 쓰기를 제한하고 최종 변경분을 이관한 뒤 건수와 관계를 대조합니다.
  3. 새 운영 도메인과 Auth·API·webhook 설정을 적용하고 실제 주소에서 핵심 흐름을 확인합니다.
  4. 로그인 실패, 데이터 누락, 저장 오류처럼 복구를 시작할 조건과 결정 담당자를 정해 관찰합니다.

Pages 도메인 연결 경로는 Cloudflare Dashboard → Workers & Pages → 해당 Pages 프로젝트 → Custom domains → Set up a domain입니다. 같은 Cloudflare 계정에서 관리하는 존이면 안내에 따라 DNS 연결을 확인합니다. DNS에 CNAME만 추가하고 Pages의 도메인 등록을 생략하지 않습니다. 자세한 조건은 Cloudflare Custom domains 문서에 있습니다. 기존 메일용 MX·TXT 등 웹 호스팅과 무관한 레코드는 유지합니다.

DNS를 되돌린다고 새 글이 옛 DB에 생기지는 않습니다

앞의 가상 메모 앱에서 새 사이트로 전환한 뒤 사용자가 메모 3건을 더 썼다고 가정해 봅시다. 옛 사이트로 즉시 되돌리면 그 3건은 보이지 않을 수 있습니다. 복구 전에 새 쓰기를 멈추고 전환 이후 추가·수정·삭제된 기록과 파일을 보존한 뒤, 어떤 DB를 최종 기준으로 삼을지 정해야 합니다. ID와 충돌 해결 규칙에 따라 변경분을 대조·반영하고 난 후 다시 쓰기를 엽니다.

따라서 복구 계획은 프론트 배포, 도메인 연결, Auth 설정, DB·파일을 각각 다룹니다. DNS 캐시와 인증서 활성화 때문에 되돌림이 즉시 모든 사용자에게 반영된다고 가정하지 않습니다. 이전 버전이 새 DB 구조를 읽을 수 있는지도 확인합니다. 원본 사이트와 백업을 종료할 시점은 새 데이터까지 대조한 뒤 결정합니다.

이 정도 인수인계표가 있으면 다음 작업을 정할 수 있습니다

아래 항목을 한 문서에 채워 두면 제작자와 운영자가 같은 이전 범위를 보고 이야기할 수 있습니다. 모르는 항목은 빈칸 대신 “미확인”과 확인 담당자를 적습니다. 비밀값이나 사용자 원본 데이터는 넣지 않습니다.

사이트 / 현재 URL / 목표 URL:
소스·콘텐츠 반출 권한 / 배포 버전:
런타임·버전 / 설치·빌드 명령 / 출력 폴더:
서버가 필요한 기능 / 유지할 외부 서비스:
주요 URL / 이전 URL 처리 / 404 확인 결과:
환경변수 이름 / 공개·서버용 / 주입 위치 / 담당자:
DB / Auth / 파일 / 브라우저 데이터의 이전 범위:
백업 기준 시각 / 시험 복구·건수 대조 결과:
로그인·권한 허용 및 거부 테스트 결과:
시험 주소 / 남은 문제 / 확인 담당자:
전환 시점 / 쓰기 중지·최종 동기화 방법:
복구 조건 / 새 쓰기 보존·대조 방법 / 결정 담당자:
원본 보존 기간 / 완료 판단 기준:

판정은 세 단계로 정리하면 됩니다. 이전 가능은 시험 배포와 데이터·권한·복구 확인이 끝난 상태입니다. 보완 후 재검토는 필요한 수정과 검증 방법이 구체적으로 정해진 상태입니다. 현재 전환 보류는 반출 권한, 실행 환경, 백업·복구, 사용자 접근 권한 가운데 핵심이 미확인인 상태입니다. 보류한 항목도 “무엇을 확인하면 다시 판단할 수 있는가”를 붙이면 다음 일이 분명해집니다.

이 글의 판단과 절차는 소규모 사이트를 옮길 때 확인할 설계 기준입니다. 사이트별 데이터와 연결 서비스는 다르므로, 실제 운영 전환은 시험 결과를 보고 결정합니다. 제품 동작과 메뉴는 2026년 9월 10일 확인한 공식 문서를 기준으로 적었습니다.

실제 예시: 이 사이트를 인수한다면 무엇을 넘길까?

빈 점검표만 있으면 모든 칸을 “확인 완료”로 채우기 쉽습니다. 아래는 2026년 9월 22일 쭈니박스 본도메인 저장소를 읽고 작성한 인수인계 예시입니다. 다른 사이트를 실제로 이전했다는 후기가 아니며, 아케이드와 박물관의 데이터는 포함하지 않습니다.

확인한 사실과 아직 필요한 증거를 분리한 인수인계표
항목이 저장소에서 확인한 내용인수 전에 더 확인할 것
게시물루트의 평면 HTML, assets, robots.txt, sitemap.xml, ads.txt.게시할 폴더의 문서와 예제까지 검토. docs도 공개될 수 있음.
실행 환경프레임워크·설치·빌드 명령 없음. HTML·CSS를 제공.새 호스팅에서도 /notes가 notes.html로 연결되는지 확인.
데이터루트 코드에는 로그인, DB SDK, 입력 양식, 서버용 환경변수 없음.별도 서비스의 계정·파일은 이 정적 파일 이전의 대상이 아님.
대표 URL본문 URL과 canonical, sitemap은 jjunybox.com 기준.같은 도메인을 유지할지 결정. 도메인 변경 시 세 항목과 이전 URL 처리를 함께 검토.
운영 설정README에 Pages의 main 연동과 루트 게시가 문서화됨.새 계정의 실제 연결, www 리디렉션, TLS, 크롤러 접근은 관리 화면과 응답으로 확인.
복구 단위이 루트는 사용자 쓰기 DB가 아니라 파일 버전이 복구 대상.이전 배포 보존과 도메인 연결 복구 권한·담당자를 정하고 시험.

작은 화면에서는 표를 좌우로 스크롤할 수 있습니다. 키보드로는 표에 포커스를 둔 뒤 방향키를 사용합니다.

이 표로 내릴 수 있는 결론은 “루트 프론트엔드는 정적 호스팅에 맞는 구조”까지입니다. 인수 권한, 새 주소의 실제 응답과 복구 시험을 끝내지 않았다면 “이전 완료”가 아닙니다. 또 루트가 DB를 쓰지 않는다는 사실을 브랜드 전체가 데이터를 수집하지 않는다는 말로 확대하면 안 됩니다.

담당자가 돌려줄 결과는 명령과 판정을 한 쌍으로 받습니다

파일 점검 예제를 내려받았다면, 공개 폴더의 터미널에서 다음과 같이 검사합니다. check-static-site.py는 내려받은 파일 위치에 맞춰 지정하세요. 이 검사는 호스팅 계정에 접근하지 않습니다.

py -3 ./check-static-site.py ./public --origin https://jjunybox.com

파일 검사 결과에는 검사한 버전과 오류 수를 적습니다. 이어 시험 주소의 정상 페이지, 상세 페이지 새로고침, 없는 주소를 각각 열어 HTTP 상태와 본문의 고유한 문장을 대조합니다. 주소가 열렸다는 화면 한 장만으로 이 세 결과를 대신하지 않습니다.

최종 답변을 “가능합니다”로만 받지 마세요. 예를 들어 “파일 대응 확인, 시험 주소의 상세 페이지 확인, www 이동은 미확인, 복구 담당 미지정이므로 전환 보류”라면 남은 두 작업이 분명합니다. 이 문장은 결과를 적는 가상 예시이며 현재 쭈니박스 계정의 상태 판정은 아닙니다.

이전 후 본문이 전달되는 방식은 화면에는 보이는데 HTML에는 없는 글 확인하기, 경로와 상태 코드 확인은 Cloudflare Pages의 URL과 404를 점검하는 법에서 이어서 볼 수 있습니다.

제작 노트 목록으로 돌아가기