RSS

코드는 그대로인데 앱 심사는 제출됐습니다: AI에게 Expo 배포를 맡겨본 기록

모바일 앱글: , Duolabs14분 읽기ai-automationapp-storeblogexpomodel-openai-gpt-5technical-note

코드를 한 줄도 수정하지 않았는데 TestFlight에 올라가 있던 앱이 App Review 제출 상태로 바뀌었습니다. 얼핏 보면 AI가 앱을 새로 빌드해서 배포한 것처럼 보이지만, 실제로는 이미 준비된 빌드와 스토어 정보를 확인한 뒤 App Store Connect의 심사 절차를 진행한 것입니다.

이번 글에서는 Expo 프로젝트에서 AI가 어디까지 배포를 자동화할 수 있는지, EAS와 App Store Connect는 각각 어떤 역할을 맡는지, 그리고 안전하게 자동화하려면 무엇이 필요한지 정리해 보겠습니다. 명령어와 Expo 관련 내용은 Expo SDK 56 문서를 기준으로 확인했습니다.

왜 이 주제가 중요한가

앱 배포를 흔히 “새 코드를 빌드해서 스토어에 올리는 작업”이라고 생각하기 쉽습니다. 하지만 실제 배포에는 서로 다른 세 가지 상태가 존재합니다.

구분 관리하는 내용 코드 변경 없이 바뀔 수 있나요?
Git 저장소 소스 코드와 설정 파일 일반적으로 바뀌지 않습니다
Expo EAS 서명된 iOS·Android 빌드 산출물 기존 빌드를 그대로 사용할 수 있습니다
App Store Connect 버전, 빌드 연결, 설명, 심사 제출 상태 변경할 수 있습니다

따라서 소스 코드가 그대로여도 이미 TestFlight에 유효한 빌드가 있다면, App Store Connect에서 새 스토어 버전을 만들고 해당 빌드를 연결해 심사를 제출할 수 있습니다. 이번 작업에서 AI가 변경한 것도 소스 코드가 아니라 배포 제어 영역의 상태였습니다.

실제로 어떤 일이 있었나요?

작업을 시작했을 때 iOS 프로덕션 빌드 1.0.2 (7)은 이미 TestFlight 처리를 마친 상태였습니다. 다만 App Store에 제출할 1.0.2 버전과 심사 제출 항목은 아직 만들어지지 않은 상태였습니다.

AI는 다음 순서로 작업했습니다.

  1. EAS에서 최근 iOS 프로덕션 빌드의 상태를 조회했습니다.
  2. App Store Connect에서 기존 앱 버전과 심사 상태를 읽기 전용으로 확인했습니다.
  3. App Store 버전 1.0.2를 생성했습니다.
  4. TestFlight에서 처리가 끝난 빌드 7을 해당 버전에 연결했습니다.
  5. 한국어와 영어의 업데이트 내용을 입력했습니다.
  6. 스크린샷, 심사용 로그인 정보, 리뷰 연락처 등 기존 메타데이터가 준비되어 있는지 확인했습니다.
  7. 사용자의 승인을 받은 뒤 App Review 제출을 실행했습니다.
  8. 최종 상태가 WAITING_FOR_REVIEW인지 다시 조회했습니다.

스토어 승인 이후의 공개 방식은 수동 출시로 유지했습니다. 즉, AI가 심사 제출까지 진행했더라도 Apple의 승인이 곧바로 실제 사용자 대상 출시로 이어지지는 않습니다.

Expo 관점에서 보면 무엇이 다른가요?

Expo 기반 앱을 배포할 때는 EAS Build, EAS Submit, App Review를 구분하셔야 합니다.

EAS Build는 설치 가능한 바이너리를 만듭니다

다음 명령은 프로덕션용 iOS 빌드를 생성합니다.

npx eas-cli@latest build --platform ios --profile production

EAS는 배포 인증서와 프로비저닝 프로파일을 이용해 서명된 .ipa를 만듭니다. 이 단계가 성공했다고 해서 TestFlight나 App Store 심사가 자동으로 완료되는 것은 아닙니다.

EAS Submit은 바이너리를 App Store Connect로 전송합니다

최근 빌드를 제출 프로필에 따라 업로드하려면 다음과 같이 실행할 수 있습니다.

npx eas-cli@latest submit --platform ios --profile production --latest

Expo 공식 문서에 따르면 업로드된 빌드는 Apple의 처리를 거쳐 TestFlight에 나타납니다. 다만 eas submit은 App Review 제출이나 실제 공개 출시까지 대신하지 않습니다. App Store 버전 생성, 메타데이터 확인, 빌드 연결, 심사 제출은 별도의 App Store Connect 단계입니다.

빌드 생성과 TestFlight 전송을 한 번에 연결하고 싶다면 다음 방식도 사용할 수 있습니다.

npx eas-cli@latest build --platform ios --profile production --auto-submit

EAS Update는 네이티브 배포를 대신하지 않습니다

EAS Update는 호환되는 기존 바이너리에 JavaScript와 에셋 변경을 OTA 방식으로 전달합니다. 네이티브 모듈, 권한, 아이콘, 스플래시 화면처럼 바이너리 변경이 필요한 항목은 새 빌드가 필요합니다. EAS Update만으로 TestFlight 업로드나 App Review 절차를 대체할 수는 없습니다.

자주 사용하는 확인 명령어

AI에게 작업을 맡길 때도 먼저 읽기 전용 확인을 수행하는 것이 좋습니다.

# 최근 iOS 빌드 확인
npx eas-cli@latest build:list \
  --platform ios \
  --limit 5 \
  --json \
  --non-interactive

# iOS 인증 정보 확인 및 관리
npx eas-cli@latest credentials --platform ios

# 프로덕션 빌드 생성
npx eas-cli@latest build --platform ios --profile production

# 가장 최근 빌드를 App Store Connect로 전송
npx eas-cli@latest submit --platform ios --profile production --latest

프로젝트에는 최소한 iOS 번들 식별자가 설정되어 있어야 합니다.

{
  "expo": {
    "ios": {
      "bundleIdentifier": "com.example.app"
    }
  }
}

eas.json에는 버전 관리와 제출 프로필을 다음과 같이 구성할 수 있습니다.

{
  "cli": {
    "appVersionSource": "remote"
  },
  "build": {
    "production": {
      "autoIncrement": true
    }
  },
  "submit": {
    "production": {
      "ios": {
        "ascAppId": "YOUR_APP_STORE_CONNECT_APP_ID"
      }
    }
  }
}

실제 값은 공개 문서나 저장소에 그대로 남기지 않고, 프로젝트 비밀 저장소 또는 배포 환경에서 관리하시는 편이 안전합니다.

AI가 App Review까지 진행하려면 무엇이 필요한가요?

1. Expo와 EAS에 접근할 수 있어야 합니다

개발 환경에서는 로그인된 Expo 세션을 사용할 수 있습니다. CI에서는 일반적으로 EXPO_TOKEN을 비밀 변수로 등록해 비대화형 명령을 실행합니다. 토큰은 로그나 문서에 출력하지 않아야 하며, 필요한 프로젝트에만 접근할 수 있도록 관리해야 합니다.

2. Apple Developer와 App Store Connect 권한이 필요합니다

iOS 앱 제출에는 유료 Apple Developer 계정과 적절한 App Store Connect 역할이 필요합니다. 자동화를 위해 App Store Connect API 키를 사용한다면 다음 정보가 한 묶음으로 필요합니다.

  • Key ID
  • Issuer ID
  • 해당 키의 .p8 개인 키

개인 키는 생성 시점에만 내려받을 수 있으므로 별도의 비밀 저장소에서 관리하셔야 합니다. Git 저장소에 커밋하거나 명령줄 인수와 로그에 직접 노출해서는 안 됩니다.

예를 들어 Fastlane의 Spaceship을 사용하면 환경 변수로 전달된 인증정보를 이용해 App Store Connect API에 접근할 수 있습니다.

require "spaceship"

token = Spaceship::ConnectAPI::Token.create(
  key_id: ENV.fetch("ASC_KEY_ID"),
  issuer_id: ENV.fetch("ASC_ISSUER_ID"),
  filepath: ENV.fetch("ASC_KEY_PATH")
)

Spaceship::ConnectAPI.token = token
app = Spaceship::ConnectAPI::App.find(ENV.fetch("IOS_BUNDLE_ID"))

인증 이후의 자동화 흐름은 다음과 같습니다.

App Store 버전 생성
→ TestFlight 빌드 선택 및 연결
→ 언어별 업데이트 내용 입력
→ 심사 제출 객체 생성
→ 제출 항목에 버전 추가
→ App Review 제출
→ 상태 재조회

Fastlane이나 App Store Connect API의 세부 인터페이스는 버전에 따라 달라질 수 있으므로, 자동화 스크립트에서는 각 단계의 응답을 검증하고 실패 시 중단하도록 구성하시는 것이 좋습니다.

3. 스토어 메타데이터가 준비되어 있어야 합니다

바이너리만 있다고 심사를 제출할 수 있는 것은 아닙니다. 다음 항목도 함께 확인해야 합니다.

  • 앱 이름, 설명, 키워드, 카테고리
  • 버전별 업데이트 내용
  • 기기별 스크린샷과 미리보기
  • 개인정보 처리방침 URL과 지원 URL
  • 심사 담당자가 사용할 연락처와 데모 계정
  • 수출 규정과 암호화 관련 답변
  • 개인정보 수집 및 사용 목적에 관한 답변

특히 개인정보, 암호화, 수출 규정에 관한 답변은 AI가 추측해서 입력하면 안 됩니다. 앱 구현과 실제 운영 정책을 사람이 확인한 뒤 확정해야 합니다.

안전한 자동화 시나리오

AI가 배포를 수행할 때는 다음과 같이 권한과 중단 지점을 분리하는 구성이 안전합니다.

  1. Git 작업 트리가 깨끗한지 확인합니다.
  2. EAS와 App Store Connect의 현재 상태를 읽기 전용으로 조회합니다.
  3. 대상 앱, 버전, 빌드 번호가 의도한 값인지 검증합니다.
  4. 빌드가 없다면 EAS Build를 실행합니다.
  5. 빌드가 App Store Connect에 없다면 EAS Submit을 실행합니다.
  6. Apple의 빌드 처리가 끝날 때까지 상태를 확인합니다.
  7. 버전과 메타데이터를 만들거나 갱신합니다.
  8. 스크린샷, 심사 정보, 규정 관련 답변의 누락 여부를 검사합니다.
  9. 심사 제출 직전에 사용자에게 최종 승인을 받습니다.
  10. 제출 후 WAITING_FOR_REVIEW와 같은 최종 상태를 다시 확인합니다.
  11. 승인 후 실제 공개 출시는 별도의 명시적 승인에 따라 진행합니다.

이 방식의 핵심은 “AI에게 모든 권한을 주는 것”이 아니라, 조회·빌드·업로드·심사 제출·공개 출시의 권한을 단계별로 나누는 것입니다. 같은 명령을 다시 실행하더라도 중복 버전이나 잘못된 제출이 생기지 않도록 멱등성 검사도 필요합니다.

주의할 점

  • eas submit의 성공을 App Review 제출 완료로 오해하지 않으셔야 합니다.
  • 사용자가 지정하지 않은 앱이나 빌드를 자동으로 선택하지 않도록 대상 값을 검증해야 합니다.
  • Apple API 키, Expo 토큰, 테스트 계정 비밀번호를 로그에 출력하지 않아야 합니다.
  • 심사용 데모 계정은 최소 권한으로 만들고 운영자 계정과 분리하시는 것이 좋습니다.
  • 스토어 설명과 업데이트 내용은 실제 앱 동작과 일치해야 합니다.
  • 개인정보 및 수출 규정 답변은 근거 없이 자동 생성하지 않아야 합니다.
  • 심사 승인 뒤 자동 공개보다 수동 출시를 기본값으로 두는 편이 안전합니다.
  • 제출 전후에 Git 상태를 확인하면 배포 과정에서 소스가 의도치 않게 변경되지 않았는지 검증할 수 있습니다.

듀오랩스가 보는 관점

AI는 앱 배포를 상당 부분 자동화할 수 있습니다. 다만 좋은 자동화는 사람을 완전히 없애는 것이 아니라, 사람이 결정해야 할 지점과 기계가 반복해도 되는 작업을 명확히 나누는 데서 시작합니다.

EAS는 서명된 빌드 생성과 스토어 전송을 안정적으로 담당하고, App Store Connect API는 버전과 메타데이터, 심사 제출 상태를 제어합니다. AI는 두 영역의 현재 상태를 읽고 다음 작업을 결정하는 실행자 역할을 맡을 수 있습니다. 여기에 비밀정보 관리, 단계별 승인, 결과 검증, 감사 가능한 로그를 더하면 새로운 Expo 프로젝트에서도 반복 가능한 배포 프로세스를 만들 수 있습니다.

이번 사례에서 코드가 바뀌지 않았는데도 심사가 제출된 이유는 간단합니다. 새 코드를 만든 것이 아니라, 이미 검증된 빌드를 올바른 스토어 버전에 연결하고 제출 절차를 완성했기 때문입니다.

참고 문서