Skip to content

빌드·배포 대상 표 — 웹·관리자·문서·Edge·API·iOS·Android 의 진입점·환경 값·도구·버전 원천 (이슈 #1332, B02)

저장소 분리 적용 범위 (#1463): 이 문서의 실행 코드·DB·앱 release 절차는 dekerd/Barbelic에 적용한다. 문서·관리자·랜딩은 각각의 독립 저장소 절차를 따른다. 과거 docs/admin 결합·앱 main 문서 직행 설명은 분리 전 이력이며 저장소 경계독립 운영·실제 전환 상태가 그 부분을 대체한다.

2026-09-09 개정 (이슈 #1456·#1457·#1458, 오너 결정) — 명령·워크플로 이름이 바뀌었다. 작업 PR 통합 요청 npm run merge:request(구 landing:request), PR 전 사전 검증 npm run ci:precheck-local(최신 release 합치기 → verify → 서버 변경 시 DB 단계, 브라우저 없음), 전체 검증 npm run ci:full-local(릴리스 큐 runner 안에서만; 세션은 --only <단계> 재현만). 워크플로 표시 이름: 3-Release Merge Request(release-merge-request.yml) · GitHub Full CI(policy-contract.yml) · 1-Production Deploy/2-Staging Deploy(production-deploy.yml·staging-deploy.yml, 단계 정의는 deploy-steps.yml) · Production smoke (manual) · Social login daily check · Daily data backup. landing:lock·db:preflight 스크립트는 폐기됐다(GitHub concurrency 가 잠금, DB 검사는 사전 검증과 큐가 한다). 아래 본문의 옛 이름은 그 개정 전 기록이다.

2026-09-09 배포 브랜치 전환: 작업 → release → staging → main(Production)의 정본은 릴리스 프로세스다. 아래 대상 표는 새 코드의 main=Production, staging=staging 매핑이다. 앱과 docs/admin은 같은 SHA·환경으로 DB·Edge 이후 Actions에서 배포한다. DEPLOYMENT_BRANCH_CUTOVER=true 활성화와 실제 배포 검증은 별도 완료 항목이며 기존 Supabase 프로젝트·secret·네이티브 연결 값은 유지한다. 앱·docs의 두 환경 브랜치, docs staging 공개 Supabase 값·BARBELIC_TARGET, VERCEL_DOCS_PROJECT_ID는 설정 확인을 마쳤다. 로컬 산출물 검증도 통과했지만 원격 main 설치·활성화·실제 Linux Deploy는 미완료다.

한 문장 — 같은 소스가 여러 곳으로 나갈 때 "어느 환경으로 나가는 빌드인가" 를 추측하지 않게 하는 표다. 배포 대상 값의 원천은 deployment-targets.json 하나이고, 그 값을 옮겨 적은 파일은 npm run check:deployment 가 대조한다. 빌드는 자기 대상을 선언해야 하고(BARBELIC_TARGET 또는 Vercel 시스템 변수), 대상과 Supabase 값이 어긋나면 빌드가 실패한다 — 값이 없다고 Production 으로 대체하지 않는다.

  • 이슈: #1332 (계획 ID B02). 코드: vite.deploymentTarget.mjs(대상 선언·검증·index.html 도장), scripts/check-build-artifact.mjs(산출물 검사), scripts/check-deployment-pipeline.mjs(복사본 대조). 테스트: tests/react/deploymentTargets.test.mjs·appConfigEnv.test.mjs.
  • 누가 쓰나: 배포 워크플로(deploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출)), CI(policy-contract.yml), npm run ci:local, N01(네이티브 셸)·R05(릴리스 리허설)·U05(번들 기준).
  • 관련 정본: 배포 파이프라인 · 환경 분리 런북 · HQ 운영 정본 §3·§4.

1. 읽는 법 — 운영자 A 의 하루로

운영자 A 가 staging 에 새 빌드를 올린다. 예전에는 Vercel staging 환경 변수에서 VITE_SUPABASE_URL 을 빠뜨려도 빌드가 조용히 성공했고, 앱은 Production 데이터베이스를 바라봤다. 테스트 계정으로 기록을 저장하면 Production 에 들어갔다. 지금은 빌드가 "staging 빌드에 VITE_SUPABASE_URL 이 없습니다. 값이 없다고 Production 을 바라보게 두지 않습니다" 라는 오류로 멈춘다. 빌드가 통과했다면 산출물의 index.html 첫 줄에 __BARBELIC_DEPLOYMENT__={"target":"staging","supabaseUrl":"https://ajqd….supabase.co",…} 가 새겨져 있고, 배포 워크플로는 배포 직전에 그 줄을 다시 읽어 대상이 맞는지, 잡 환경의 비밀값이 산출물에 없는지 확인한다(값은 출력하지 않는다).

2. 배포 대상 (deployment-targets.json)

대상Supabase 프로젝트Vercel 환경브랜치어떻게 정해지나VITE_SUPABASE_* 규칙
productionkobxeylancdimqhfkbnlproductionmaindeploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출) 이 BARBELIC_TARGET=production 으로 빌드없어도 됨(원천 파일 값 사용). 있으면 Production 값과 같아야 함
stagingajqddlglezvxzsawqukustaging(커스텀 환경)stagingdeploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출) 이 BARBELIC_TARGET=staging 으로 빌드필수, staging 프로젝트여야 함
previewajqddlglezvxzsawqukupreviewPR 브랜치(claude/ui-*)Vercel git 통합 빌드: VERCEL_ENV=preview 자동필수, staging 프로젝트여야 함
local(선택)developmentBARBELIC_TARGET=local npm run build · npm run dev 기본없으면 Production 값(로컬 미리보기·e2e 는 __BARBELIC_E2E_CONFIG__ 가 덮는다). 있으면 그대로

대상 판정 순서: BARBELIC_TARGET → (Vercel 이면) VERCEL_TARGET_ENVVERCEL_ENV → (vite dev 만) local. vite build 에 대상이 없으면 실패. Vercel 시스템 변수는 프로젝트 설정 "Enable access to System Environment Variables" 가 켜져 있어야 노출된다(기본 켜짐). GitHub Actions 배포는 시스템 변수에 기대지 않고 BARBELIC_TARGET 을 명시한다.

관리자 셸도 배포 환경을 따른다. Actions가 BARBELIC_TARGET=staging 또는 production을 명시하고, 관리자(별도 Vercel 프로젝트, 자체 주소 — deployment-targets.json 환경별 adminOrigin, Production https://admin.barbelic.com, #1666)는 해당 환경의 Supabase를 본다. 배포 뒤 deploy-steps.ymladminOrigin으로 앱 서버 관리자 API에 CORS 사전 요청을 보내 허용 목록(Vercel 변수 ADMIN_ALLOWED_ORIGINS)을 확인한다. staging 관리자 빌드에는 staging 공개 URL·키가 반드시 필요하다. vite.admin.config.mjsfixedTarget: "production"은 명시값이 없을 때의 기본값이며 BARBELIC_TARGET이 우선한다. 새 배포 경로는 이 기본값에 기대지 않고 앱과 같은 SHA·환경을 전달한다. main/staging 직접 Git 배포를 껐으므로 순수 Markdown을 CI·배포 생략 예외로 합친 경우 문서 사이트는 다음 해당 환경 배포에서 갱신된다.

3. target 표 — 진입점·환경 값·runtime·toolchain·버전 원천

target진입점·빌드 명령산출물·배포공개 환경 값(번들에 실림)비밀(서버 전용, 번들 금지)읽는 코드 → 전달 경로runtimetoolchain 원천버전 원천
web 앱index.htmlsrc/react/vite/main.tsx · npm run build(vite.config.mjs)dist-vite/ → Vercel barbelic(vercel.json; main/staging은 DB·Edge 이후 Actions CLI, PR 프리뷰는 git 통합)VITE_SUPABASE_URL·VITE_SUPABASE_PUBLISHABLE_KEY(선택, 대상과 일치해야 함) · BARBELIC_TARGET/VERCEL_*(대상 판정)없음 — VITE_ 이름에 SERVICE_ROLE·SECRET·PASSWORD·TOKEN 이 들어오면 빌드 실패vite.deploymentTarget.mjs 가 검증 → index.html __BARBELIC_DEPLOYMENT__app-config.jssupabaseAuth.ts·connectivityAppAdapter.ts·appErrorReporter.ts브라우저(iOS WKWebView·Android WebView 포함)Node 22(워크플로)·Vite package.json릴리스 SHA = __BARBELIC_RELEASE__(VERCEL_GIT_COMMIT_SHAGITHUB_SHAdev) · 마이그레이션 = deploymentManifest.ts EXPECTED_LATEST_MIGRATION
관리자 셸admin/index.htmlsrc/react/vite/admin/main.tsx · npm run build:admin(vite.admin.config.mjs)dist-admin/admin/ → docs 빌드가 BARBELIC_ADMIN_OUT_DIR=.vitepress/dist 로 동봉 → 해당 환경 docs 도메인 /admin/앱과 같은 BARBELIC_TARGET=staging 또는 production 및 해당 Supabase 공개 값없음위와 같음브라우저(데스크톱)Actions의 .nvmrc; 프리뷰는 docs Vercel 프로젝트 Node 설정앱과 같은 SHA·app-config.js·deploymentManifest.ts
문서 사이트docs/(VitePress) · npm run build(docs/package.json = vitepress build && node scripts/build-admin.mjs)docs/.vitepress/dist → Vercel barbelic-docs(main/staging은 DB·Edge 이후 Actions, 프리뷰는 git 통합; docs/vercel.json)문서 본문에는 없음; 동봉 관리자 셸에는 위 공개 값없음docs/scripts/build-admin.mjs 가 루트 vite 실행(루트 npm ci 필요); 별도 docs Vercel 프로젝트 ID는 저장소 변수로 전달정적docs/package-lock.json(vitepress)동봉 관리자 셸은 같은 배포 SHA
Vercel API 함수api/account/delete.js·api/admin/{users,impersonate}.js·api/auth/test-admin/session.js앱 프로젝트와 함께 배포(vercel.json 기본 함수 설정)없음SUPABASE_URL·SUPABASE_PUBLISHABLE_KEY·SUPABASE_SERVICE_ROLE_KEY·ADMIN_IMPERSONATION_ENABLED·TEST_ADMIN_*·KAKAO_ADMIN_KEY·APPLE_* — Vercel 환경 변수process.env 직접(env(name) || ""), 빠지면 500(코드만 기록)Node(Vercel 서버리스)Vercel 프로젝트 Node 설정앱과 같은 배포
Edge 함수(Supabase)supabase/functions/{wodup-start-import,wodup-process-import-jobs,stats-process-refresh-jobs} · supabase functions deploydeploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출) functions 잡 → 대상 프로젝트없음SUPABASE_URL·SUPABASE_ANON_KEY·SUPABASE_SERVICE_ROLE_KEY(플랫폼 자동 주입)Deno.env.get, 빠지면 500 supabase_env_missingDeno(Supabase Edge Runtime)Supabase CLI package.json supabaseToolchain.cli응답 헤더 x-barbelic-deployment-version = deploymentManifest.ts
iOS 셸ios/App(Capacitor, capacitor.config.json webDir: dist-vite) · Xcode ArchiveApp Store(수동, docs/platform/app-store-submission.md)ios/{Debug,Release}.xcconfigInfo.plist: 서버 origin·인증 origin·콜백 scheme·app-bound domain (원천 native 항목)없음(서명 = Xcode 계정)MainViewController.swift AppEnvironment(plist 없으면 같은 값 fallback) → WebView 가 https://www.barbelic.com/ 을 연다iOS 15+ WKWebViewXcode(macOS 전용), CocoaPods/SPMMARKETING_VERSION 1.0·CURRENT_PROJECT_VERSION 1(project.pbxproj) — 웹과 독립
Android 셸android/(Capacitor) · npm run android:bundle(gradlew.bat bundleRelease)Play(수동, docs/platform/android-release.md)android/app/build.gradle def barbelic*BuildConfig(원천 native 항목)서명 키 = android/keystore.properties(git 제외)AppEnvironment.kt(빈 값이면 같은 값 fallback) → WebViewAndroid minSdk 24 / target 36JDK 21·Android SDK(variables.gradle), Windows/macOS 로컬versionCode 1·versionName "1.0.0"(build.gradle) — 웹과 독립
Node 스크립트·테스트scripts/**·tests/**·e2e/**app-config.js Node 전용 기본값(= Production 공개 값)E2E_*·BARBELIC_DB_SANDBOX·SUPABASE_ACCESS_TOKEN 등 실행 환경process.envNode 22package.json engines·supabaseToolchain

import.meta.env 를 읽는 앱 코드는 app.tsx(DEVvite/main.tsx(DEVofflineServiceWorker.ts(PROD) 셋뿐이고 Supabase 값은 전부 app-config.js 한 곳을 지난다(2026-09-07 실측).

4. 경계 검사 — 무엇이 어디서 막히나

잘못막는 곳결과
vite build 에 대상이 없다vite.deploymentTarget.mjs resolveBuildTarget빌드 실패: "빌드 대상이 없습니다 … 기본값(Production)으로 대체하지 않습니다"
staging/preview 빌드에 VITE_SUPABASE_* 가 없다validateBuildEnvironment빌드 실패(Production 으로 대체하지 않음)
production 빌드에 staging 값, 또는 그 반대validateBuildEnvironment빌드 실패(어느 프로젝트가 왔는지 ref 로 표시)
VITE_SUPABASE_SERVICE_ROLE_KEY 처럼 서버 전용 이름이 VITE_ 로 들어온다validateBuildEnvironment빌드 실패(이름만 표시, 값은 읽지 않음)
플러그인 없이 만든 번들app-config.js resolveBarbelicConfig번들이 시작을 거부(__BARBELIC_DEPLOYMENT__ 없음)
산출물이 다른 대상용이거나 비밀값·source map 이 들어 있다scripts/check-build-artifact.mjs(deploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출) 배포 직전, CI check:artifacts)배포 중단
원천 값의 복사본이 어긋난다(config.toml·deploy.yml·xcconfig·gradle·Swift/Kotlin·스크립트)npm run check:deploymentcheck 실패
배포 비밀값(DB 비밀번호·smoke 계정·ref)이 없다deploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출) 각 잡의 이름 검사잡 실패(건너뜀 없음, 다른 환경 값으로 대체 없음)
Production smoke 가 다른 프로젝트를 친다deploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출) smoke: URL 을 고정 ref 에서 만든다PROD_SUPABASE_URL 이 있으면 일치 검사
앱 서버의 관리자 API 허용 목록(ADMIN_ALLOWED_ORIGINS)에 그 환경의 관리자 주소가 없다deploy-steps.yml frontend: 공개 주소 확인 뒤 adminOrigin에서 보낸 OPTIONS /api/admin/deployment-manifest가 204인지(최대 6회, #1666)배포 실행 실패(배포 자체는 완료된 뒤의 확인 단계)

4-1. 도구 버전의 원천과 CI 경계 (Phase 2)

도구원천읽는 곳검사
Node.nvmrc(22; package.json engines 범위 안)모든 워크플로 setup-nodenode-version-file, npm-install action 의 node_modules 캐시 키(hashFiles('.nvmrc'))tests/react/ciToolchain.test.mjs — 손으로 적은 node-version: 0곳
Vercel CLIpackage.json vercelToolchain.cli(정확 버전)deploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출) frontend 잡(npm install --global vercel@<버전>)같은 테스트 — @latest 금지
Supabase CLI·Postgres 이미지package.json supabaseToolchain(#1233)deploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출)·local-supabase-stack action·ci:localtests/react/ciLocal.test.mjs
supabase/setup-cli action커밋 SHA + 태그 주석(@ab05898… # v1.7.1)3곳같은 테스트 — 서드파티 action 은 SHA 핀만 허용
의존성 lock루트 package-lock.json(npm ci 만) · docs/package-lock.json(CI docs-build 잡이 npm ci --prefix docs + 빌드) · 랜딩은 Barbelic-landing의 package-lock.json으로 독립 설치·전용 CI 검증npm-install action 은 lock 해시로 캐시
Vercel 프로젝트의 Node대시보드 설정(.nvmrc 와 자동 연동되지 않음)Vercel 빌드오너 손 목록 §6

노출 경계(2026-09-07 검토 결과): source map 은 어느 빌드도 만들지 않는다(Vite 기본값 false, 독립 랜딩 설정은 명시 false). 빌드 산출물(dist-*·.vercel/output·.vitepress/dist)은 artifact 로 올리지 않는다. 비밀은 env: 로만 셸에 건네고 run: 본문에 워크플로 표현식(secrets.*)을 직접 끼우지 않으며 $GITHUB_ENV 로 잡 전체에 퍼뜨리지 않는다. Production 카나리(prod-smoke.yml)는 E2E_EVIDENCE=off 로 trace·video·screenshot 을 만들지 않고 결과 JSON 만 7일 보관한다. 모든 워크플로는 최상위 contents: read, 쓰기 권한은 실제로 쓰는 잡(release-tag 태그 생성, landing-queue 머지·댓글·workflow dispatch)에만 있다. 매일 사본(daily-data-backup.yml)의 90일 artifact 는 저장소 읽기 권한자 전원이 내려받을 수 있는 유저 데이터 사본이다 — 의도된 PITR 대체(S11 소유)이며 여기서 바꾸지 않는다.

2026-09-09 랜딩 분리 후속: 랜딩 전용 CI는 독립 저장소 main 16c6d32Landing CI에서 검증됐다. 앱의 이전 landing-page/ 복사본 제거는 #1477, 통합 PR #1484v0.17.7 release와 staging에 반영됐다. main·Production 완료는 이 기록에서 확정하지 않는다. 별도 호스팅 연결·공개 배포·도메인 이전의 완료를 의미하지 않는다(현재 실행·배포 안내).

5. 로컬에서 쓰는 법

bash
# 로컬 미리보기·e2e 빌드 (Production 공개 값, e2e 는 런타임 override)
BARBELIC_TARGET=local npm run build
# staging 번들을 손으로 만들어 보기 (값은 Vercel staging 환경과 같아야 한다)
BARBELIC_TARGET=staging VITE_SUPABASE_URL=https://ajqddlglezvxzsawquku.supabase.co VITE_SUPABASE_PUBLISHABLE_KEY=<staging 공개> npm run build
# 산출물 검사
node scripts/check-build-artifact.mjs --dir dist-vite --target staging

PowerShell 은 $env:BARBELIC_TARGET='local'; npm run build. npm run dev 는 대상 없이 local 로 뜨고 어느 프로젝트를 보는지 한 줄 알린다.

6. 오너 손이 필요한 것 (진행을 막지 않음)

  • Vercel barbelic·barbelic-docs 프로젝트의 "Enable access to System Environment Variables" 가 켜져 있는지(기본 켜짐). 꺼져 있으면 PR 프리뷰(git 통합) 빌드가 대상을 알 수 없어 실패한다 — 실패가 곧 안내다.
  • Vercel Production 환경에 VITE_SUPABASE_* 를 명시하면 원천 파일 기본값 의존이 사라진다(선택).
  • Vercel 두 프로젝트의 Node 버전이 .nvmrc(22.x)와 같은지 확인(대시보드 설정, 자동 연동 없음).

7. 호환 표 — 관리자 · 웹 · 서버 · 설치본 (Phase 4)

웹 앱과 docs/admin은 같은 SHA·환경의 DB·Edge가 준비된 뒤 배포하고, 네이티브 설치본은 별도로 출시한다. "지금 사용자가 보는 조합"은 아래 표의 행들이 만나는 것이다. npm run check:deployment 가 이 표의 설치본 버전·서비스 워커 캐시 버전·Edge 배포 버전 문자열을 실제 파일(gradle·pbxproj·sw.js·deploymentManifest.ts)과 대조한다 — 값을 올리면 표도 같은 PR 에서 고친다.

표면나가는 시점가리키는 서버버전 원천(현재 값)다른 표면과의 호환 규칙
웹 앱 (www.barbelic.com)staging → main 승격 PR 머지(오너) 후 DB·Edge 배포 성공Production Supabase릴리스 SHA(__BARBELIC_RELEASE__) · EXPECTED_LATEST_MIGRATION(deploymentManifest.ts, check:deployment 가 마이그레이션 꼬리와 대조)DB 먼저·함수·프론트 순으로 나가므로 프론트는 항상 자기보다 새롭거나 같은 DB 를 본다(deploy-steps.yml(1-Production Deploy·2-Staging Deploy 가 호출) 잡 의존). 열린 탭의 구 번들은 staleChunkRecovery 로 새 청크를 받는다
스테이징 앱release/vX.Y.Z → staging 승격 PR 머지 후 DB·Edge 배포 성공staging Supabase(ajqddlglezvxzsawquku)같은 SHA·같은 manifestProduction 과 만나지 않는다(대상 도장이 staging 이 아니면 배포 중단, §4)
관리자 셸 (각 환경 docs 도메인 /admin/)앱과 같은 SHA·환경의 DB·Edge 배포 성공 후 Actions 배포staging은 staging Supabase, Production은 Production Supabase앱과 같은 SHA·app-config.js·deploymentManifest.ts서버 계약 배포 뒤 관리자 셸이 나간다. 관리자 게이트 admin-hold/admin-compat-confirmed도 유지하여 지원 대상 서버 계약과의 호환을 검토한다
Edge 함수 (3개)릴리스 PR 머지(functions 잡)자기 프로젝트응답 헤더 x-barbelic-deployment-version = 20260821-admin-on-behalf-import-v1(wodup 2개) · 20260821-barbelic-headers-stats-v1(stats)관리자 운영 화면이 헤더를 읽어 manifest 와 대조. 함수 이름·목록은 config.toml·폴더·manifest 3자 일치를 check:deployment 가 강제
서비스 워커 (public/sw.js)웹 앱과 함께CACHE_VERSION = barbelic-offline-v1셸 자원만 캐시하고 API/auth 는 캐시하지 않는다. 캐시 형식을 바꾸면 버전을 올려 옛 저장소를 비운다(N01 소유)
iOS 설치본App Store 심사(오너 Mac, 수동)Production(origin 고정: www.barbelic.com·인증 origin, xcconfig)iOS 1.0 (1) = MARKETING_VERSION / CURRENT_PROJECT_VERSION(project.pbxproj)설치본은 웹 번들을 싣지 않고 origin 을 연다 → 항상 현재 Production 웹을 본다. 셸이 주입하는 capability: secureAuthSessionV1·securePkceVerifierV1·socialAuthV1·splashOwnerV1·appleAccountDeletionReauthV1·shareFileV1. 웹은 플래그가 없으면 브라우저 경로로 동작하고, 새 셸이 필요한 기능은 LG426(앱 업데이트 안내)로 막는다
Android 설치본Play 업로드(수동, docs/platform/android-release.md)Production(origin 고정, build.gradleBuildConfig)Android 1.0.0 (1) = versionName / versionCode(build.gradle)같은 규칙. capability: secureAuthSessionV1·securePkceVerifierV1·socialAuthV1(iOS 의 splashOwnerV1·appleAccountDeletionReauthV1·shareFileV1 는 없음 → 웹이 스플래시를 그린다)

허용 조합의 뜻: 설치본 × 웹 은 어떤 설치본이든 현재 Production 웹과 만난다(웹이 capability 로 분기). 관리자 × 서버 는 관리자 게이트가 지킨다. 웹 × 서버 는 배포 순서가 지킨다. 구·신 설치본과 열린 탭·IDB 의 실제 공존 실험은 R02 몫이다(이 표는 그 실험의 행 목록이다).

8. native release 빌드 증거와 인계 (Phase 4)

8-1. Android — 이 PC(Windows)에서 실제 실행

항목
명령BARBELIC_TARGET=production npm run buildnpx cap sync androidnpm run android:bundle(= android/gradlew.bat bundleRelease). Git Bash 에서 gradlew.bat 를 상대 이름으로 부르면 cmd 가 찾지 못한다 — PowerShell 이나 전체 경로로 부른다
toolchain(실측)Windows 11 · JDK 21.0.12(Microsoft, JAVA_HOME) · Android SDK build-tools 36.0.0 / platform android-36(ANDROID_HOME=%LOCALAPPDATA%\Android\Sdk) · Gradle wrapper 8.14.3(--no-daemon) · AGP 8.13.0 · Kotlin 2.2.0 · @capacitor/core 8.5.0·@capacitor/android 8.5.0·@capacitor/cli 8.4.0(설치본 기준)
서명android/keystore.properties 없음 → 서명 없는 번들. 업로드 키 서명·Play App Signing 검증은 R05(오너 keystore)
결과(2026-09-07 11:00Z, 세션 7cd84cdd)BUILD SUCCESSFUL in 1m 3s(122 tasks) → android/app/build/outputs/bundle/release/app-release.aab 6,289,676 bytes · SHA-256 9ec568f78db6210cbf44a7413fdefbe263e3929dfb8806646253c2bc4b2daa4b · 번들 안 base/assets/public/index.html 도장 = target:"production"·kobxeylancdimqhfkbnl·release:"dev"(로컬 빌드라 커밋 SHA 없음 — Actions/Vercel 빌드에서만 SHA 가 들어간다) · 서버 비밀 문자열 0건 · 최상위 META-INF/*.RSA·.SF 없음(= 서명 없음). 빌드 로그는 세션 scratchpad(레포 밖)
경고Kotlin 경고 10건(NativeBridge.kt 163·164·165·182·200·201·213·242·243·244 — Java 타입 Nothing?String 자리에 넘김). 빌드는 통과하며 셸 코드는 N01 소유라 여기서 고치지 않는다
설치본 버전versionName "1.0.0"·versionCode 1(§7 표와 check:deployment 대조) — Play 업로드마다 둘 다 올린다

8-2. iOS — Windows 라 미실행 (R05 인계)

Swift 컴파일·Archive 는 macOS Xcode 에서만 된다(docs/platform/ios-setup.md §"Windows"). Windows 의 웹 빌드나 config 문자열 검사로 대신하지 않는다. R05 가 오너 Mac 에서 아래를 실행하고 산출물 버전을 이 표에 적는다:

  1. BARBELIC_TARGET=production npm run build && npx cap sync ios
  2. Xcode: App 타깃 General → Version(MARKETING_VERSION)·Build(CURRENT_PROJECT_VERSION) 확인 → Product → Archive → Distribute → App Store Connect(docs/platform/app-store-submission.md §제출 절차).
  3. 기록할 것: Xcode 버전·macOS 버전·Archive 의 Version/Build·업로드 시각·ios/App/App.xcodeproj 의 두 값이 표와 같은지. 결과를 이 절과 R05 리허설 문서에 적는다.

8-3. N01 인계 — 설치본/웹/서버 조합과 빌드 근거

  • 설치본은 웹 번들을 싣지 않고 origin 을 연다: 설치본 버전은 "어느 웹" 이 아니라 "어느 bridge capability" 를 뜻한다(§7 표). N01 이 bridge·SW·IDB 호환 matrix 를 만들 때 이 표의 capability 목록과 CACHE_VERSION 을 행으로 쓴다.
  • 환경 값(origin·scheme·app id)은 deployment-targets.json native 항목이 원천이고 xcconfig·gradle·Swift/Kotlin fallback 은 check:deployment 가 대조한다. N01 이 셸 코드를 바꿔도 이 값들은 손대지 않는다.