이 소스 코드 인수인계 체크리스트를 사용해 코드 내보내기, 문서화, 비밀 키 교체, 마이그레이션 실행, 빌드 검증, 그리고 클라이언트와의 배포 소유권 확인을 하세요.

소스 코드 인수인계는 프로젝트가 "에이전시가 운영하는 것"에서 "클라이언트가 소유하는 것"으로 바뀌는 순간입니다. 명확한 인수인계가 없으면 흔한 문제가 금방 드러납니다: 앱이 한 대의 노트북에서만 빌드된다든가, 운영에 필요한 시크릿이 아무도 찾지 못하는 곳에 있다든가, 작은 업데이트가 며칠간의 추측 작업으로 번지는 경우입니다.
인수인계 체크리스트의 목적은 단순합니다: 이전 후 클라이언트가 에이전시에 수시로 도움을 청하지 않아도 제품을 빌드하고 실행하며 배포할 수 있어야 합니다. 이는 "항상 지원이 필요 없다"는 뜻이 아니라, 기본적인 절차가 반복 가능하고 문서화되어 다음 사람이 자신 있게 이어받을 수 있다는 뜻입니다.
전달물(딜리버러블)이 무엇인지 명확히 해야 합니다. 최소한 완전한 인수인계에는 보통 다음이 포함됩니다:
범위(scope)는 내용만큼 중요합니다. 어떤 인수인계는 한 환경(예: production)만 다루고, 다른 인수인계는 dev, staging, production을 각각의 설정과 절차와 함께 포함합니다. 포함되는 환경을 명시하지 않으면 사람들이 각자 다르게 가정하고, 그 결과 장애가 발생합니다.
성공을 정의하는 현실적인 방법은 검증 테스트입니다: 해당 앱을 빌드하지 않은 사람이 코드를 내보내(예: Koder.ai 같은 플랫폼에서), 문서를 따르고, 환경 변수를 설정하고, 마이그레이션을 실행하고, 빌드하고, 합의된 환경에 배포할 수 있어야 합니다.
이 체크리스트는 기술적 준비성(environment variables, secrets rotation, database migrations, deployment scripts, build verification)에 집중합니다. 법적 조건, 계약, IP 조항, 대금 분쟁 등은 중요하지만 별도의 합의서에서 다루어야 합니다.
깨끗한 인수인계는 어떤 내보내기도 하기 전에 시작됩니다. 누가 무엇을 언제 소유하는지 합의하면 배포 중단, 미지급 호스팅, 접근 권한 누락 같은 막판 깜짝 상황을 피할 수 있습니다.
인수인계 날짜를 정하고(보통 24~72시간) 그동안은 긴급한 수정만 허용하는 동결 창(freeze window)을 정의하세요. 이렇게 하면 내보낸 코드와 실행 중인 시스템의 상태를 일치시킬 수 있습니다. 동결 기간 중 핫픽스가 필요하면 어떤 변경이 있었는지 정확히 기록하고 최종 내보내기에 포함되었는지 확인하세요.
DNS, 클라우드 호스팅, 유료 서비스의 소유권이 인수인계 이후 누가 가질지 결정하세요. 단순한 서류 작업이 아닙니다. 청구가 에이전시 카드에 남아 있으면 서비스가 예고 없이 중단될 수 있습니다.
간단하게 정리하는 방법:
이 내용을 양측이 따라할 수 있도록 쉬운 언어로 문서화하세요.
존재하는 환경(local, staging, production)과 각 환경이 어디에서 운영되는지 합의하세요. staging이 별도 서버인지, 별도 DB인지, 단순한 기능 플래그인지도 적어두세요. Koder.ai 같은 플랫폼을 사용해 내보냈다면 그곳에 호스팅된 것과 내보낸 후 클라이언트 인프라에서 운영될 것으로 예상되는 것을 구분해 명시하세요.
마지막 날까지 접근 권한을 요청하지 마세요. 리포, CI, 호스팅, 데이터베이스, 이메일 공급자 등 필요한 사람이 적절한 접근을 미리 갖추도록 하세요.
또한 최종 승인 테스트와 서명 프로세스를 합의하세요. 예: “클라이언트가 깨끗한 머신에서 빌드하고, 마이그레이션을 실행하고, 스테이징에 배포해 스모크 테스트를 통과하면 양측이 서면으로 서명한다.”
좋은 소스 코드 인수인계 체크리스트는 새 팀이 몇 분 안에 리포를 열어 이해할 수 있도록 시작합니다. 무엇이 포함되어 있는지(앱 코드, 설정 템플릿, 스크립트)와 의도적으로 제외된 것(실제 시크릿, 개인 키, 큰 생성 파일)을 확인하고, 제외된 항목이 있다면 그것이 어디에 있고 누가 소유하는지 적어두세요.
구조는 예측 가능하게 유지하세요. 최상위 폴더는 frontend/, backend/, mobile/, infra/, scripts/, docs/처럼 명확히 하세요. 모노레포인 경우 각 부분이 어떻게 연관되는지와 각 부분을 어떻게 실행하는지 설명하세요.
README는 프로젝트를 만든 사람이 아닌 사람이 사용해도 되어야 합니다. 전제 조건과 가장 빠르게 개발 환경을 띄우는 방법을 추측 없이 커버해야 합니다.
짧고 사람 중심의 README 섹션에는 다음 질문에 대한 답이 있어야 합니다:
간단한 아키텍처 설명을 평이한 언어로 추가하세요: 무엇이 무엇과 통신하고 그 이유는 무엇인지. 작은 다이어그램은 선택사항이며 보통 몇 문장으로 충분합니다. 예: “React 프론트엔드가 Go API를 호출합니다. API는 PostgreSQL을 읽고 씁니다. 백그라운드 잡은 별도의 워커 프로세스로 실행됩니다.”
마지막으로 인수인계 빌드에 대한 버전된 변경 로그나 릴리스 노트를 포함하세요. CHANGELOG.md 또는 인수인계 릴리스 노트 파일에 정확한 커밋/태그, 배포된 내용, 알려진 이슈를 적습니다.
Koder.ai 같은 플랫폼에서 코드를 내보낸 경우 생성된 프로젝트 타입(웹, 서버, 모바일), 예상 툴체인(예: React, Go, PostgreSQL, Flutter)과 클라이언트가 빌드를 재현할 때 사용해야 하는 지원되는 OS/툴 버전을 명시하세요.
환경 변수는 인수인계 직후 "작동하던 앱"이 실패하는 주된 이유입니다. 좋은 체크리스트는 환경 변수를 제품의 일부로 다루며, 사소한 일이 아니라 필수로 문서화합니다.
먼저 새 팀이 추측하지 않고 따라할 수 있는 목록을 작성하세요. 쉬운 언어로 예시 값 형식(실제 시크릿 아님)을 포함하세요. 변수가 선택 사항이면 누락되었을 때 어떤 일이 발생하는지와 사용되는 기본값을 적어두세요.
간단한 제시 방식은 다음과 같습니다:
환경별 차이를 명확히 표시하세요. 예를 들어 staging은 테스트 DB와 샌드박스 결제 제공자를 가리키고, production은 라이브 서비스를 가리킬 수 있습니다. 콜백 URL, 허용 출처, 모바일 앱 번들 식별자처럼 여러 시스템에서 일치해야 하는 값도 명시하세요.
각 값이 현재 어디에 저장되어 있는지도 문서화하세요. 많은 팀이 값들을 여러 장소에 나눠 둡니다: 개발용 로컬 .env 파일, 빌드를 위한 CI 변수, 런타임을 위한 호스팅 설정 등. Koder.ai에서 내보냈다면 .env.example 파일과 첫 빌드 전에 채워야 할 변수를 짧게 메모하세요.
마지막으로 리포에 시크릿이 숨겨져 있지 않음을 증명하세요. 현재 파일만 확인하지 말고 커밋 히스토리도 검토해 실수로 올라간 키, 오래된 .env 파일, 샘플 설정에 복사된 자격 증명이 없는지 확인하세요.
구체적 예: React 프론트엔드와 Go API가 있다면 웹앱에는 API_BASE_URL이 필요하고 백엔드에는 DATABASE_URL과 JWT_SIGNING_KEY가 필요할 수 있습니다. staging이 다른 도메인을 쓰면 두 값을 모두 적어 어디를 바꿔야 하는지 명시해 새 팀이 실수로 스테이징 설정을 프로덕션에 배포하지 않도록 하세요.
인수인계가 완료되려면 클라이언트가 앱에 필요한 모든 자격 증명을 제어해야 합니다. 이는 단순 공유가 아니라 시크릿의 교체(rotation)를 의미합니다. 에이전시나 이전 계약자가 여전히 작동하는 키를 가지고 있으면 감사를 할 수 없는 열린 문이 됩니다.
먼저 전체 시크릿 목록을 작성하세요. 데이터베이스 비밀번호에 그치지 말고 서드파티 API 키, OAuth 클라이언트 시크릿, 웹훅 서명 시크릿, JWT 서명 키, SMTP 자격증명, 스토리지 접근 키, CI에 남아 있는 임시 토큰까지 포함하세요.
다음은 교체 당일의 간단한 체크리스트입니다:
교체 후엔 문제가 없는지 증명하세요. 로그만 확인하지 말고 간단한 "실사용자" 테스트를 실행하세요.
시크릿에 의존하는 흐름에 집중하세요:
예: Koder.ai에서 내보낸 프로젝트가 결제 제공자와 이메일 전송을 사용한다면 두 키를 교체하고 재배포한 뒤 소규모 테스트 거래와 테스트 이메일을 보내보세요. 이들이 성공하면 에이전시 소유 키를 폐기하세요.
마지막으로 시크릿이 앞으로 어디에 보관될지(vault, CI 변수, 호스팅 설정), 누가 변경할 수 있는지, 교체 시 오류가 발생하면 안전하게 롤백하는 방법을 문서화하세요.
인수인계가 끝난 것처럼 보여도 데이터베이스가 먼저 깨질 수 있습니다. 마이그레이션과 데이터는 별도의 제품처럼 다루세요: 버전 관리되고 반복 가능하며 테스트되어야 합니다.
현재 데이터베이스 버전과 마이그레이션이 리포 어디에 있는지 적어두세요. 폴더 경로, 명명 규칙, 최신 마이그레이션 ID(또는 타임스탬프)를 구체적으로 적습니다. PostgreSQL을 사용한다면(Go 백엔드에서 흔함) 필요한 확장(extension)도 명기하세요.
짧은 런북에 다음 질문에 대한 답을 포함하세요:
롤백은 솔직해야 합니다. 일부 변경은 백업 복원으로만 되돌릴 수 있습니다. 이를 명확히 적고 백업 단계(배포 전 스냅샷, 복원 절차 확인)를 함께 제시하세요.
인수인계가 완료되기 전에 가능하면 프로덕션 데이터 복사본에서 마이그레이션을 실행하세요. 이 방법으로 느린 쿼리, 누락된 인덱스, "빈 데이터에서만 동작하는" 문제를 발견할 수 있습니다. 현실적인 테스트는 코드를 내보내고, 환경 변수를 설정하고, 익명화한 덤프를 복원한 다음 처음부터 마이그레이션을 적용해 보는 것입니다. 이 하나의 연습이 인수인계 체크리스트의 큰 부분을 검증합니다.
Koder.ai에서 생성 후 내보낸 앱이라면 마이그레이션 파일과 시드 스크립트가 내보내기에 포함되어 있고 백엔드 시작 프로세스에서 올바르게 참조되는지 다시 확인하세요.
인수인계는 누군가가 빈 머신에서 앱을 처음부터 다시 빌드할 수 있을 때에야 완료됩니다. 체크리스트에는 정확한 빌드 명령, 필요한 버전, 기대 출력(예: "/dist에 웹 번들", "API 바이너리 이름", "Flutter APK 위치")을 포함하세요.
실제로 사용하는 도구와 패키지 매니저를 적으세요. 일반적인 스택의 예: React 웹 앱엔 Node.js(및 npm 또는 pnpm), 서버엔 Go 툴체인, 로컬 설정용 PostgreSQL 클라이언트 도구, 모바일엔 Flutter SDK 등이 필요할 수 있습니다.
의존성 설치를 예측 가능하게 만드세요. 락파일(package-lock.json, pnpm-lock.yaml, go.sum, pubspec.lock)이 커밋되어 있는지 확인하고 새 컴퓨터나 깨끗한 컨테이너에서 새로 설치해 작동을 증명하세요.
CI가 무엇을 하는지 단계별로 캡처해 다른 CI 제공자에게 복제할 수 있게 하세요:
빌드 시점의 설정(build-time config)과 런타임 설정(runtime config)을 분리하세요. 빌드 시점 설정은 컴파일되는 내용을 바꾸고(예: 웹 번들에 베이크된 API 베이스 URL), 런타임 설정은 앱 시작 시 주입됩니다(예: DB URL, API 키, 기능 플래그). 이 둘을 섞는 것이 "CI에서는 작동하는데 배포 후 실패"하는 흔한 원인입니다.
간단한 로컬 검증 레시피를 제공하세요. 짧은 명령어 모음으로도 충분합니다:
# Web
pnpm install
pnpm test
pnpm build
# API
go test ./...
go build ./cmd/server
# Mobile
flutter pub get
flutter test
flutter build apk
Koder.ai에서 내보냈다면 배포 중 사용된 생성된 CI 파일이나 빌드 프리셋을 포함해 클라이언트가 플랫폼 밖에서도 동일한 빌드를 재현할 수 있게 하세요.
좋은 인수인계 체크리스트는 "리포지토리 여기 있습니다"로 끝나지 않습니다. 코드가 소스에서 실행 서비스로 가는 방법과 누가 버튼을 누르는지 설명해야 합니다.
현재 배포하는 방식이 수동(서버에서 명령 실행), CI 기반(파이프라인이 빌드 후 배포), 혹은 호스팅 플랫폼을 통한 것인지 적으세요. 설정이 어디에 있는지, 어떤 환경이 존재하는지도 포함하세요.
릴리스 절차를 반복 가능하게 만드세요. 프로세스가 누군가가 12개의 명령어를 기억해야만 한다면 그걸 스크립트로 만들고 필요한 권한을 명시하세요.
클라이언트가 1일차에 배포할 수 있을 만큼 다음을 제공하세요:
다운타임 기대치를 합의하세요. "제로 다운타임"이 필요하면 실제로 어떤 방식(블루-그린, 롤링, 마이그레이션 시 읽기 전용 창)이 필요한지 명시하세요. 다운타임이 허용된다면 명확한 시간 창을 정의하세요.
정적 자산과 캐시는 흔한 실패 지점입니다. 자산이 어떻게 빌드되고 제공되는지, 캐시 무효화 시점, CDN 사용 여부를 적어두세요.
롤백은 태그나 릴리스 ID와 연결된 짧고 테스트된 레시피여야 합니다. 예: 이전 태그 배포, 필요 시 이전 DB 스냅샷 복원, 캐시 무효화.
앱이 Koder.ai에서 생성되어 내보내졌다면 마지막 정상 스냅샷과 정확한 내보내기 버전을 언급해 클라이언트가 코드와 동작하는 릴리스를 빠르게 매칭할 수 있게 하세요.
검증은 인수인계가 진짜인지 확인하는 순간입니다. 목표는 단순합니다: 새 사람이 내보낸 코드를 받아 설정하고 추측 없이 같은 앱을 실행할 수 있어야 합니다.
시작하기 전에 "정상"이 무엇인지 기록하세요: 실행 중인 앱의 버전, 현재 커밋/태그(있다면), 비교할 주요 화면이나 API 응답 한두 가지. Koder.ai에서 내보냈다면 스냅샷이나 내보내기 타임스탬프도 적어 최신 상태를 테스트했음을 증명하세요.
스모크 테스트는 짧고 위험에 연관된 항목들로 구성하세요:
문제가 발견되면 정확한 명령어, 오류 출력, 사용한 환경 변수를 캡처하세요. 이는 소유권이 바뀔 때 수시간을 절약해 줍니다.
"코드만으로 충분하다"고 가정하면 인수인계는 화재 진압으로 변합니다. 좋은 체크리스트는 클라이언트가 실제로 앱을 운영하고 변경할 수 있게 하는 작은, 지루한 세부사항에 집중합니다.
흔한 패턴은 다음과 같습니다:
교체와 접근 정리는 "시간 될 때" 하는 작업이 아니라 일정에 잡힌 작업으로 만드세요. 에이전시 계정이 제거되고 서비스 키가 재생성되며 클라이언트가 자신의 자격증명만으로 배포할 수 있음을 확인하는 날짜를 정하세요.
환경 변수는 리포, CI 시스템, 호스팅 UI 세 곳에서 간단한 목록을 만들어 검증하세요. 그런 다음 새 머신이나 컨테이너에서 깨끗한 빌드를 수행해 확인하세요.
마이그레이션은 프로덕션 배포에 사용할 동일한 DB 역할로 테스트하세요. 프로덕션에서 권한 상승이 필요하면(확장 활성화 등) 그 절차를 기록하고 소유권을 명확히 하세요.
현실적 예: Koder.ai에서 프로젝트를 내보낸 뒤 클라이언트는 배포에 성공하지만 백그라운드 잡이 실패합니다. 그 이유는 한 큐 URL이 호스팅 대시보드에만 설정되어 있었기 때문입니다. 간단한 env var 감사가 이를 잡아냈을 것입니다. 태그된 릴리스와 문서화된 롤백(예: "태그 v1.8.2를 재배포하고 마지막 스냅샷 복원")을 함께하면 다운타임을 피할 수 있습니다.
이 인수인계 체크리스트에서 한 페이지만 남긴다면 이 페이지를 남기세요. 목표는 단순합니다: 깨끗한 클론이 새 머신에서 실행되고, 새 시크릿으로 동작하며, 데이터베이스가 안전하게 앞으로 진행될 수 있어야 합니다.
처음 보는 리포나 클린 컨테이너/VM에서 다음을 실행하세요. 이것이 누락된 파일, 숨은 가정, 오래된 자격증명을 가장 빨리 찾아냅니다.
에이전시가 React 프론트엔드, Go API, PostgreSQL DB를 인수인계합니다. 클라이언트 팀은 리포를 클론하고 제공된 .env.example을 실제 환경 변수로 복사한 뒤 DB, 이메일 제공자, 서드파티 API용 새 자격증명을 생성합니다. go test(또는 합의된 테스트 명령)를 실행하고 React 앱을 빌드하며 익명화한 Postgres 인스턴스에 마이그레이션을 적용한 후 두 서비스를 시작합니다. 마지막으로 문서화된 스크립트로 배포하고 동일한 커밋을 나중에 다시 빌드할 수 있음을 확인합니다.
인수인계를 짧고 소유권이 명확하게 유지하세요. 30~60분짜리 워크스루가 긴 문서보다 효과적인 경우가 많습니다.