# D3RO Voice 모바일 제품화 핸드오프 > 작성 시각: 2026-08-21 KST > 마지막 사실 동기화: 2026-08-29 KST > 제품 런타임: `apps/mobile-rn` > 구현·검증 정본: [`MOBILE_APP_COMPLETION_SSOT.md`](./MOBILE_APP_COMPLETION_SSOT.md) > 2026-08-21 Git 기준선: `main` @ `a9c9a1ca6efdfc83ae7a12a0c1f2a05f15ef9138` (역사 증거, 현재 release SHA 아님) > release identity: version `1.1.0`, Android versionCode / iOS build `1010001` > 판정: **내부 기능·local upload/evidence key·AdMob identity는 준비됐지만 production AAB·Firebase·CI secret 주입·closed test가 없어 Play 출시는 RED** ## 0. 2026-08-29 release readiness 스냅샷 | 영역 | 현재 사실 | 다음 게이트 | |---|---|---| | Play 앱 | `D3RO Voice`, `com.d3ro.voice`, app ID `4976102237698469110`; Console 상태 `임시` | 첫 AAB 업로드 후 설정 0/11 채우기 | | 버전 | product `1.1.0`, Android versionCode / iOS build `1010001` | AAB·desktop artifact·release record가 같은 identity를 가리키는지 CI에서 증명 | | Play App Signing | SHA-256 `01:00:19:21:DB:4F:33:40:85:CE:21:E4:B8:DE:CC:BD:71:DA:87:67:C5:6E:3B:59:83:2A:A1:C8:29:EA:0D:AB` 실확인 | local upload key는 있다. 첫 AAB 후 Console 표시가 local cert와 일치하는지 증명 | | App Links | source `assetlinks.json` 3개는 Play SHA-256으로 갱신 | live는 아직 구 certificate라 배포·public 재검증 필요 | | Play 트랙 | 첫 AAB 0건, closed tester 0명 | 12명을 연속 14일 유지하고 production access 신청·승인 | | production access | disabled | 승인 전에 production/open testing 가능으로 간주 금지 | | local release keys | upload PKCS12 private-key readback GREEN; Ed25519 evidence keypair roundtrip GREEN | CI secret 업로드·오프라인 복구 백업·실제 AAB 서명 대기 | | production 입력 | AAB·Firebase config·AdMob/upload/evidence CI secret 주입 증거 없음 | protected secret store와 승인 경계에 주입한 후 fail-closed build | 일반적인 “배포해” 지시는 Data safety, App content, production access 답변과 같은 외부 법적·정책 선언의 대리 승인이 아니다. 실제 Console 문구를 사용자가 읽고 action-time 승인하기 전에는 저장·제출하지 않는다. ## 0.1 2026-08-24 AdMob 재개 결과 - 정본 계정 `yunchan8804@gmail.com`에서 AdMob 계정과 D3RO Voice Android 앱이 생성된 상태를 재확인했다. - App ID: `ca-app-pub-1039714767792854~6427959892` - banner: `ca-app-pub-1039714767792854/9840591290` - rewarded: `ca-app-pub-1039714767792854/2255790918` - rewarded contract: `50 cloud_ai_tokens` - SSV URL: `https://llnocwyqvhgwpdjcqqyw.supabase.co/functions/v1/admob-ssv`; AdMob의 URL 확인 성공 후 저장하고 새로고침 뒤 영속 상태를 재확인했다. - Supabase production migration `20260821000028`과 `admob-ssv` Edge v13을 배포했다. unknown key는 HTTP 503, 영구 거부는 HTTP 200으로 응답한다. - 보상 transaction은 `ad_reward_receipts.transaction_id UNIQUE`에서 먼저 소비한다. cooldown/cap/ineligible/unknown-user도 영구 terminal 처리하며 계정 삭제 시 사용자 UUID는 NULL로 분리한다. - live 상태는 `검토 필요`, `광고 게재 제한`, Play store 미연결, 결제 프로필 미완료다. production signed AAB와 test-device/Play 설치본의 실제 Google-signed SSV 지급 E2E도 남았다. ## 1. 가장 먼저 읽을 것 1. Google/Firebase/Play/AdMob의 정본 계정은 **`yunchan8804@gmail.com`**이다. 2. Play 개발자 계정은 **`YUN CHAN`**, 개발자 ID는 **`7374613349497835192`**다. 3. **TWENTYOZ 계정으로 프로젝트·앱·광고 계정을 만들거나 제출하면 안 된다.** 잘못된 계정에서는 실제 제출한 항목이 0건이다. 4. 과거 Git 커밋의 author email `yunchan@twentyoz.kr`은 저장소 메타데이터일 뿐이며 Google Console 계정 선택 근거가 아니다. 5. 현재 worktree에는 여러 작업자의 대규모 수정·신규 파일이 함께 있다. `git reset --hard`, `git checkout --`, `git clean`, 광범위한 포맷·삭제를 하면 안 된다. 6. 보존된 APK 증거는 **Google TEST AdMob + debug signer의 TEST-DEMO**다. Play production 또는 공식 signed APK로 게시하면 안 된다. 7. 이 문서와 모바일 SSOT는 현재 untracked다. 정식 릴리스 전 관련 소스·migration·Edge Function·문서를 검토 가능한 커밋으로 보존해야 한다. ## 2. 현재 한눈에 보기 | 영역 | 현재 상태 | 출시까지 남은 것 | |---|---|---| | 모바일 기능 | 인증, 온보딩, 테마, 녹음/전사, Talk, History, 회의, 팀, Push 계약, portability, template/memo, billing, ads, admin 구현 | 외부 provider의 production journey | | 모바일 정적 검증 | typecheck·ESLint GREEN | 없음 | | 모바일 Jest | **57 suites / 353 tests GREEN** | 없음 | | Android E2E | API 34 exact `.11` TEST-DEMO auth/signup/invite 및 cold launch GREEN | production-signed artifact로 재실행 | | Supabase DB/Edge | production migration `00001`~`00028`, AdMob SSV v13 ACTIVE·rewarded secret 설정 | FCM drain cron, 실제 provider-signed E2E | | 법적 페이지 | production HTTPS 200 | Play Console 등록정보에 URL 입력 | | Firebase | Console `u/0`, `u/1` 모두 D3RO project 없음; production Android config·CI secret 없음 | 사용자 승인 후 정본 프로젝트/Android 앱·Play fingerprint·FCM 연결 | | Play Console | 앱 `4976102237698469110` 생성, App Signing SHA-256 확인; 상태 `임시`, 설정 0/11, AAB 0건 | AAB·스토어 설정·상품·internal/closed track·12명 14일·production access | | AdMob | App/Banner/Rewarded ID·SSV URL 설정 완료 | `검토 필요`·`광고 게재 제한`·지급 프로필·store 미연결·UMP/test-device E2E | | production APK/AAB | 없음 | secret 주입 후 signed APK+AAB build/verifier/CI | | Fold6 | `.11` TEST-DEMO Taildrop 전송 완료 | 설치·실행·공유·OAuth·구매 실증 | ## 3. 계정과 브라우저 상태 ### Firebase - Firebase Console `u/0`과 `u/1`을 2026-08-29에 모두 재확인했고 D3RO 프로젝트는 0개였다. - production `google-services.json`, Android 앱 등록, Play app-signing fingerprint, FCM/CI secret은 없다. - 새 Cloud/Firebase 프로젝트와 Android 앱 등록은 영구 외부 상태를 만든다. 사용자에게 계정·프로젝트 ID·Analytics 선택·생성 범위를 보여준 뒤 action-time 승인을 받는다. ### Google Play Console - 계정: `yunchan8804@gmail.com` - 개발자 계정: `YUN CHAN` - 개발자 ID: `7374613349497835192` - 앱: `D3RO Voice`, package `com.d3ro.voice`, app ID `4976102237698469110` - 상태: `임시`; 설정 0/11, 첫 AAB 0건 - Play app-signing SHA-256: `01:00:19:21:DB:4F:33:40:85:CE:21:E4:B8:DE:CC:BD:71:DA:87:67:C5:6E:3B:59:83:2A:A1:C8:29:EA:0D:AB` - Console upload certificate 표시: 첫 AAB 업로드 후. local upload key 존재 여부와는 다른 상태다. - closed test: 0명 / 요건 12명, 연속 14일 - production access: disabled 앱 생성 당시 정책·수출법 선언은 사용자 승인 후 완료됐다. 이후 Data safety, App content, production access 답변도 동일하게 사용자의 법적·정책 진술이므로 action-time 승인 전에 제출하지 않는다. ### AdMob - 계정 표시: `yunchan8804@gmail.com` (`authuser=1`) - D3RO Voice Android 앱과 production App/Banner/Rewarded ID: 생성 완료 - rewarded `50 cloud_ai_tokens`: 저장 완료 - production SSV URL: Google 확인 및 저장 완료 - 지급 프로필: 미완료. 이 상태에서는 앱 검토가 보류된다. - live 상태: `검토 필요`, `광고 게재 제한` - store 등록정보: 미연결. 앱 검토와 Privacy & messaging/UMP production 검증: 대기 `authuser=0`은 정본 계정 경로가 아니다. 이후에도 `authuser=1`과 화면의 `yunchan8804@gmail.com` 표시를 같이 확인한다. ### 사용자에게 필요한 다음 확인 Firebase 프로젝트/Android 앱 생성, 지급·세금 프로필, Data safety/App content 답변, production access 신청은 각각 외부 상태를 영구적으로 바꾼다. 실제 Console 문구와 입력할 사실을 보여준 뒤 해당 액션별로 명시 승인을 받는다. ## 4. 완료된 핵심 구현과 증거 상세 요구사항별 상태는 모바일 SSOT 4절과 7절이 정본이다. 핵심 실행 증거만 요약한다. - 모바일 lint: warning/error 0 - 모바일 typecheck: GREEN - 모바일 Jest: 57 suites / 353 tests GREEN - API 34 TEST-DEMO exact APK: - package `com.d3ro.voice` - version `0.0.0-e2e.20260821.11` - versionCode `202608221` - non-debuggable - arm64-v8a + x86_64 - embedded Hermes bundle + Whisper model verified - cold launch 0.872초, top-resumed - fresh auth 30초, signup 40초, invite warm+cold 14초 PASS - fatal/ANR/React fatal 0 - Android instrumentation: CSPRNG 1 + incoming-share 3, 총 4/4 GREEN - 모바일 Admin 역할 E2E: ordinary/manager/admin/super_admin/stale-manager 55 assertions PASS, fixture 0 - Free tier Google TEST banner/rewarded 실제 렌더 및 SSV 미구성 시 credit 0 fail-closed 확인 - 녹음 FGS, HOME, 통화 audio focus, process kill 복구, 알림 discard, 실제 WAV 복구 확인 - Talk: WAV→STT→Claude SSE→Android TTS/stop 확인 - 외부 ContentProvider `ACTION_SEND`→Record→durable queue→cancel cleanup 확인 - production Supabase: - linked ref `llnocwyqvhgwpdjcqqyw` - migration `00001`~`00028` local/remote 일치 - Edge Functions 25개 ACTIVE - `admob-ssv` v13, rewarded unit secret 존재, AdMob URL verification GREEN - 익명 user/admin 함수 fail-closed 401 및 admin `no-store` - 배포 전후 production aggregate 불변 ## 5. 현재 산출물 ### TEST-DEMO APK - 빌드 경로: `apps/mobile-rn/android/app/build/outputs/apk/e2e/app-e2e.apk` - 전달 복사본: `scratch/D3RO-Voice-0.0.0-e2e.20260821.11-TEST-DEMO-74035b69db0a.apk` - 크기: `146,739,935` bytes - SHA-256: `74035B69DB0A564846DF5ED4B85CA5D0E2289D5BB7D73DEE02C35DFD57380C2B` - Fold6 Taildrop 파일명: `D3RO-Voice-0.0.0-e2e.20260821.11-TEST-DEMO-74035b69db0a.apk` 이 APK는 debug certificate와 Google TEST AdMob ID를 사용한다. 공식 배포, Play internal testing, production 광고 검증에 사용하지 않는다. ### 준비된 Android upload key - PKCS12: `C:\Users\encep\.d3ro\release\d3ro-upload-key-20260821.p12` - alias: `d3ro-upload-20260821` - password vault target: `D3ROVoice-Android-Upload-20260821` - certificate SHA-256: `4F:AC:69:24:82:1C:50:DA:AB:ED:76:49:32:A5:3C:48:6F:8C:6C:5F:34:B9:F1:8D:B9:20:AA:40:99:15:2B:54` - file/parent directory user-only ACL과 private-key readback: GREEN - 별도 오프라인 복구 백업: 아직 필요 - protected CI secret 등록: 아직 필요 - Play Console upload certificate 표시·local cert 대조: 첫 AAB 업로드 후 가능. Console에 아직 표시되지 않는다고 key가 없는 것은 아니다. 암호·PKCS12를 출력, 채팅, Git, 일반 로그, browser upload 임시 경로에 남기지 않는다. ### release-evidence Ed25519 keypair - private: `C:\Users\encep\.d3ro\release\d3ro-mobile-evidence-ed25519-private.pem`, 저장소 밖 user-only ACL - public: `release/mobile-release-evidence-public.pem` - keyId: `2797d3e63affd2348941bc2871b57e520c958f7f5da1a4bbe8aa46904a890b7f` - private/public 일치·sign/verify roundtrip: GREEN - protected CI private-key secret 등록·오프라인 복구 백업: 아직 필요 ### 폐기된 key - `apps/mobile-rn/android/app/d3ro-release-key.COMPROMISED-20260821.keystore` - 재사용 금지 - 현재 live `https://d3ro.chanpaca.net/.well-known/assetlinks.json`에는 이 과거 계열 certificate fingerprint `06:EE:C7:57:...:E4:81`가 남아 있다. - source 3개는 Play app-signing SHA-256 `01:00:19:21:...:EA:0D:AB`로 교체했다. 배포 후 public HTTPS 응답이 정확히 이 한 개 fingerprint만 반환하는지 검증한다. upload certificate와 혼동하지 않는다. ### production schema 백업 - `scratch/prod-public-schema-before-mobile-20260821.sql` - SHA-256: `35CDD059669D097C58B98D0ADF157B49A1AAA2FF03D9AC6497E84F550511A5AC` - `supabase db dump --dry-run`은 임시 DB credential을 stdout에 출력하므로 재사용하지 않는다. ## 6. 공개 법적 리소스 - 개인정보처리방침: `https://d3ro.chanpaca.net/privacy/` - 이용약관: `https://d3ro.chanpaca.net/terms/` - 앱 외부 계정 삭제: `https://d3ro.chanpaca.net/delete-account/` 세 URL 모두 production HTTPS 200이며 운영자는 `YUN CHAN`, Cloudflare email-protection 복호화 연락처는 `yunchan8804@gmail.com`, TWENTYOZ 문자열은 0건이다. 주의: 법적 파일은 NAS host와 현재 컨테이너 양쪽에 좁게 배포했으나, 현재 compose의 `/app/wwwroot` 영속 mount가 확실하지 않다. 컨테이너 재생성 전에 mount 계약을 고치거나 재검증한다. dirty한 `site/dist` 전체를 NAS에 덮어쓰지 않는다. ## 7. 재개 순서 ### 7.1 Firebase 생성과 Android 등록 1. `u/0`, `u/1` 모두 D3RO 프로젝트가 없다는 2026-08-29 기준선에서 시작한다. 2. 사용자에게 Google 계정·프로젝트 ID·Analytics 선택을 보여주고 명시 승인을 받은 후에만 새 프로젝트를 생성한다. 3. Android 앱 `com.d3ro.voice`를 등록한다. 4. `google-services.json`을 내려받아 로컬에서는 `apps/mobile-rn/android/app/google-services.json`에 둔다. 5. 파일을 Git에 커밋하지 않는다. CI에는 base64로 `ANDROID_GOOGLE_SERVICES_JSON_B64` secret을 주입한다. 6. FCM service account를 최소 권한으로 준비하고 Supabase secret에 `FCM_SERVICE_ACCOUNT_JSON`, `FCM_PROJECT_ID`를 설정한다. 7. Play Console의 app-signing SHA-1/SHA-256을 Firebase Android 앱에 추가한다. upload key fingerprint만으로 production OAuth/App Links를 완료 처리하지 않는다. ### 7.2 AdMob 완료: 1. `authuser=1` / `yunchan8804@gmail.com`의 Android app `ca-app-pub-1039714767792854~6427959892`, banner `ca-app-pub-1039714767792854/9840591290`, rewarded `ca-app-pub-1039714767792854/2255790918`을 만들었고 `release/android-release-identity.json`과 대조했다. 2. rewarded 값을 `50 cloud_ai_tokens`로 저장했다. 3. Supabase secret `ADMOB_REWARDED_AD_UNIT_ANDROID`를 production rewarded unit과 맞췄다. 4. production `admob-ssv` Edge v13과 durable receipt migration을 배포했다. 5. AdMob에서 SSV URL을 확인·저장하고 새로고침 뒤 영속 상태를 확인했다. 남음: 1. 사용자가 결제·세금 프로필을 직접 작성한다. 2. Play store 등록정보와 AdMob 앱을 연결하고 `검토 필요`·`광고 게재 제한` 상태를 해소한다. 3. Privacy & messaging의 production UMP 메시지를 게시하고 EEA/regulated-US/non-EEA를 검증한다. 4. build/CI secret: - `ADMOB_APP_ID` - `ADMOB_BANNER_UNIT_ID` - `ADMOB_REWARDED_UNIT_ID` 5. Play internal 설치본과 등록된 test device로 실제 reward 완료→Google-signed SSV→receipt/claim exactly-once→credit +50을 확인한다. 6. 본인·팀의 production 광고 클릭으로 테스트하지 않는다. Google test ads 또는 공식 test device만 사용한다. ### 7.3 Play 앱, App Signing, 상품 1. `YUN CHAN` / developer ID `7374613349497835192` / app ID `4976102237698469110`를 확인한다. 2. version `1.1.0`, versionCode `1010001`의 production AAB를 보호된 CI에서 생성·검증한다. 3. 첫 AAB를 internal track에 제한 업로드한 뒤 upload certificate를 확인하고 Play app-signing certificate와 다름을 증명한다. 4. 확인된 app-signing SHA-256으로 갱신한 다음 source 3개를 배포한다. - `site/public/.well-known/assetlinks.json` - Firebase Android certificate fingerprints - Google OAuth Android client가 필요하면 package/certificate 조합 5. subscription product를 정확한 ID로 만든다. - `d3ro_voice_pro_monthly` - `d3ro_voice_pro_plus_monthly` 6. 두 상품 모두 활성 월간 base plan과 구매 가능한 offer를 가져야 한다. offer tag `default`를 권장하며, 없으면 앱은 첫 offer를 사용한다. 7. license tester, internal testing tester, 실제 SKU/offer를 설정한다. 8. Google Play Developer API service account를 앱에 연결하고 Supabase secret을 설정한다. - `GOOGLE_PLAY_SERVICE_ACCOUNT_JSON` - `GOOGLE_PLAY_PACKAGE_NAME=com.d3ro.voice` - RTDN 사용 시 `GOOGLE_PLAY_PUBSUB_AUDIENCE` - RTDN 사용 시 `GOOGLE_PLAY_PUBSUB_SERVICE_ACCOUNT` 9. RTDN Pub/Sub topic/subscription과 `google-play-rtdn` 인증 경계를 실제 메시지로 검증한다. ### 7.4 Push drain과 초대 이메일 - production invite canonical origin은 `https://d3ro.chanpaca.net`이다. - 필요한 Supabase secrets: - `SITE_URL` - `RESEND_FROM` - `RESEND_API_KEY` - `FCM_SERVICE_ACCOUNT_JSON` - `FCM_PROJECT_ID` - durable push outbox drain: - `POST /functions/v1/send-push?mode=drain&limit=100` - header `apikey: ` - body `{}` - pg_cron + pg_net + Vault를 사용하고 service secret을 SQL, migration, 로그에 평문으로 넣지 않는다. - 실제 2-device 부분 실패, retry, stale token, logout token 제거, notification open allowlist를 production FCM으로 재검증한다. ### 7.5 production provider secrets 현재 production DB/Edge 코드는 배포됐지만 다음 provider 경로는 실제 자격 증명과 콘솔 설정이 필요하다. - Google Play/RTDN - AdMob 실제 Google-signed reward 지급 E2E(콘솔/secret/SSV URL은 완료) - Firebase Cloud Messaging - Resend - STT: `GROQ_API_KEY`, `OPENAI_API_KEY`, `DEEPGRAM_API_KEY` 또는 내부 `D3RO_API_URL` + `D3RO_API_TOKEN` - LLM: `ANTHROPIC_API_KEY` - Stripe: secret, Pro/Pro+ price, webhook secret - Payple: production merchant/return/webhook configuration secret 누락 상태는 의도적으로 fail-closed다. 가짜 값이나 성공 mock으로 통과시키지 않는다. ## 8. production build와 CI ### 필수 protected CI secrets - `ANDROID_RELEASE_KEYSTORE_B64` - `ANDROID_GOOGLE_SERVICES_JSON_B64` - `ANDROID_UPLOAD_CERT_SHA256` - `ANDROID_PLAY_APP_SIGNING_CERT_SHA256` - `ANDROID_RELEASE_STORE_PASSWORD` - `ANDROID_RELEASE_KEY_ALIAS` - `ANDROID_RELEASE_KEY_PASSWORD` - `ADMOB_APP_ID` - `ADMOB_BANNER_UNIT_ID` - `ADMOB_REWARDED_UNIT_ID` - `ANDROID_RELEASE_EVIDENCE_PRIVATE_KEY_B64` - `ANDROID_RELEASE_EVIDENCE_PUBLIC_KEY_B64` 2026-08-29 기준 upload/evidence private key는 local external path에, AdMob ID는 release identity에 준비됐지만 production Firebase/AdMob/signing/evidence secret을 실행 가능한 CI에 주입하지 않았다. 복구 백업도 대기다. `mobile-production-release` protected environment 승인과 trusted main/tag 경계를 유지한다. ### 릴리스 빌드 계약 - JDK 17 - package `com.d3ro.voice` - release version: `1.1.0`; Android versionCode / iOS build: `1010001`. CI run number로 다시 계산하지 않고 release SSOT의 고정된 단조 증가 값을 사용 - arm64-v8a production APK/AAB - `google-services.json` 필수 - production AdMob App/Banner/Rewarded ID 필수 - 준비한 `d3ro-upload-20260821` key를 CI에 보호 주입하고 실제 AAB signer를 검증한다. upload 인증서와 Play app-signing 인증서는 서로 달라야 하며, App Links/Firebase 공급자 등록에는 Play app-signing fingerprint를 사용한다. - TEST AdMob ID, debug signer, x86-only, missing Firebase config면 gate가 실패해야 정상 정본 게이트는 실제 remote에 연결된 `.gitlab-ci.yml`과 동등 계약의 `.github/workflows/release.yml`이다. 현재 remote/runner/secrets가 실제로 연결된 파이프라인을 사용하고, 로컬 ad-hoc publish로 대체하지 않는다. 주요 검증: ```powershell npm --prefix apps/mobile-rn run lint npm --prefix apps/mobile-rn run typecheck npm --prefix apps/mobile-rn run test:ci npm run security:secrets:test npm run security:secrets npm run release:mobile:boundary:test node scripts/ci/verify-mobile-build-config.mjs ``` CI는 signed APK+AAB를 만든 뒤 다음을 검증한다. - BuildConfig version/build type/Firebase/production ad IDs - package/version/versionCode - upload signer certificate - arm64 native library 완전성 - embedded Hermes/Whisper model hash - APK/AAB metadata·signer·AdMob 동등성 - Ed25519 signed release evidence - App Links certificate - publication artifact hash/create-only 경계 ## 9. Play internal testing 완료 조건 아래가 모두 실제 Play 설치본에서 GREEN이어야 production 완료로 볼 수 있다. 1. Internal track AAB upload 성공 2. Play 설치본의 `installedFromPlayStore=true` 3. 신규 설치/기존 로그인/온보딩/theme/permission 4. Google OAuth consent→Supabase callback→앱 session 5. Google Play Pro 구매 6. Pro→Pro+ upgrade 및 replacement mode 7. restore, pending, cancel, billing issue, subscription management deep link 8. server purchase verification, acknowledge, entitlement snapshot 일치 9. Free production banner 및 rewarded 표시 10. SSV 완료 전 credit 0, SSV 이후 exactly-once credit 11. Pro/Pro+에서 광고 요청·표시 0 12. FCM 실제 수신, open allowlist, logout 후 token/device cleanup 13. `ACTION_SEND` audio/video, 파일 import, 전사, History, 공유 14. 계정 로그아웃·삭제·session loss 후 모든 로컬 민감 데이터 purge 15. Fold6 cold launch, background recorder, share, OAuth, purchase 16. fatal/ANR/React fatal/민감 로그 0 ## 10. 절대 하지 말 것 - TWENTYOZ Google/AdMob/Firebase/Play 계정 사용 - 사용자 확인 없이 Play 수출법/정책 또는 AdSense 약관 제출 - TEST-DEMO APK를 official/release/signed 이름으로 공개 - 폐기된 `d3ro-release-key.COMPROMISED-20260821.keystore` 재사용 - upload certificate를 Play app-signing certificate처럼 사용 - `google-services.json`, service-account JSON, keystore password, OAuth secret을 Git/로그/채팅에 노출 - `supabase db dump --dry-run` 출력 공유 - dirty worktree를 reset/clean/checkout하거나 광범위하게 덮어쓰기 - NAS 전체 `wwwroot` 또는 dirty `site/dist`를 통째로 배포 - provider 장애·secret 누락·store sideload를 성공으로 간주 - production 광고를 직접 클릭해 테스트 ## 11. 재개자가 먼저 실행할 15분 체크 ```powershell git status --short --branch Get-FileHash apps/mobile-rn/android/app/build/outputs/apk/e2e/app-e2e.apk -Algorithm SHA256 Test-Path apps/mobile-rn/android/app/google-services.json npm --prefix apps/mobile-rn run typecheck npm --prefix apps/mobile-rn run lint npm --prefix apps/mobile-rn run test:ci npm run security:secrets ``` 기대값: - branch, HEAD, remote tracking 상태를 현재 출력대로 새 release record에 기록. 2026-08-21의 `2 commit ahead`는 역사 기준선일 뿐 현재 기대값이 아님 - E2E APK SHA-256 `74035B69...380C2B` - `google-services.json`은 Firebase 등록 전까지 없음 - typecheck/lint/Jest/security scan GREEN 그 다음 브라우저에서 계정을 다시 확인하고, 사용자 확인을 받은 뒤 7절 순서대로 진행한다. ## 12. 아직 완료라고 말하면 안 되는 이유 - Firebase `u/0`, `u/1` 모두 D3RO 프로젝트가 없고 production Android config도 없음 - production AdMob ID/SSV는 확정했지만 `검토 필요`·`광고 게재 제한`·결제 프로필·store 연결·실제 지급 E2E가 아직 없음 - Play 앱은 생성됐고 App Signing SHA-256도 확인했지만 첫 AAB·Console upload-certificate 대조·상품·internal track·설정 11개가 아직 없음 - upload/evidence keypair는 local에 준비됐지만 CI secret 등록·복구 백업·실제 AAB signature/evidence가 없음 - production signed APK/AAB와 CI 실행 증거가 아직 없음 - live App Links가 폐기된 과거 certificate를 가리킴 - closed tester가 0/12명이고 14일 기간을 시작하지 않았으며 production access가 disabled임 - 실제 Google OAuth callback, Play purchase/restore/cancel, production ads/SSV, FCM이 아직 외부 E2E되지 않음 - Fold6는 APK 전달만 됐고 설치·실행 확인이 없음 - 대규모 dirty/untracked 변경이 아직 릴리스 가능한 버전관리 상태로 정리되지 않음 이 항목들이 모두 증거로 닫히기 전에는 “모바일 제품화 완료” 또는 “공식 출시 완료”라고 판정하지 않는다.