Closer/docs/release/internal-testing-checklist.md

7.0 KiB

Closer — Internal Testing Build Checklist

Steps to prepare, sign, and distribute an internal testing build for the private MVP. Assumes Android Gradle Plugin 8.7.3, Kotlin 2.0.21, minSdk 26, targetSdk/compileSdk 35, and app.closer applicationId.

Internal testing should verify the product goal: private, mutual-reveal relationship questions with real encryption and calmer UX.


1. Pre-build Checklist

1.1 Source readiness

  • All feature branches for the MVP merged into the internal testing branch.
  • No unintended TODO / FIXME blockers in release code (documented in docs/qa/private-mvp-checklist.md).
  • No com.couplesconnect package references remain (verified via grep -RIn across app/src).
  • No debug-only logging left in non-debug code paths (verbose/debug logs removed; error logging acceptable).
  • Version matches private MVP: versionName should be 0.1.x and versionCode incremented for each distributed build.
  • local.properties contains required secrets but is not committed to git.

1.2 Secrets and API keys

  • google-services.json is present in app/ and matches the internal testing package (app.closer).
  • RevenueCat API key defined in local.properties as RC_API_KEY.
  • Firebase App Check debug token removed or disabled for release.
  • No hardcoded API keys, tokens, or credentials in Kotlin/XML source.

1.3 Build configuration

  • build.gradle.kts has isMinifyEnabled = true and isShrinkResources = true for release.
  • ProGuard rules file (proguard-rules.pro) reviewed for Compose, Hilt, Room, Firebase, RevenueCat, and Navigation.
  • compileSdk = 35, targetSdk = 35, minSdk = 26.
  • namespace = "app.closer" and applicationId = "app.closer".
  • Kotlin jvmTarget = "17" and Java 17 compatibility set.
  • buildConfig = true and compose = true enabled.

2. Signing Config Checklist

2.1 Keystore

  • Internal testing keystore generated or available (.jks / .keystore).
  • Keystore password, key alias, and key password stored securely in CI or password manager — not in repo.
  • Keystore used for signing is backed up in a secure location (1Password, team vault, hardware token).
  • Key validity period covers expected lifetime of the app (Google Play requires validity past 22 Oct 2033 for app signing key uploads).

2.2 Gradle signing configuration

  • signingConfigs block in app/build.gradle.kts configured:
    signingConfigs {
        create("release") {
            storeFile = file(System.getenv("KEYSTORE_PATH") ?: "release.keystore")
            storePassword = System.getenv("KEYSTORE_PASSWORD")
            keyAlias = System.getenv("KEY_ALIAS")
            keyPassword = System.getenv("KEY_PASSWORD")
        }
    }
    
  • buildTypes.release references signingConfigs.getByName("release").
  • Local debug builds still use the default debug keystore.

2.3 Verify signed APK/AAB

  • Build release APK or AAB: ./gradlew :app:assembleRelease or :app:bundleRelease.
  • Confirm output is signed: apksigner verify --verbose app-release.apk.
  • Check certificate fingerprints and expiration.
  • Verify v1 (JAR) and v2/v3 APK signatures are present.

3. Firebase / Production Environment Checklist

3.1 Firebase project

  • Internal testing Firebase project created/separate from production.
  • app.closer Android app registered with correct SHA-1/SHA-256 certificates.
  • google-services.json downloaded and placed in app/.

3.2 Firebase services

  • Authentication: Email/password provider enabled (and any OAuth providers used in the app).
  • Firestore: Security rules reviewed; internal testing rules should match expected MVP rules.
  • Cloud Messaging: Server key / FCM v1 credentials available for backend/push testing.
  • Crashlytics: Crashlytics plugin applied and mapping file upload enabled.
  • Analytics: No PII logged; events reviewed.
  • Remote Config: Default values in-app handle absent remote values.
  • App Check: Play Integrity provider configured for release builds; debug provider only for debug/internal.

3.3 Firebase secrets

  • No Firebase API keys or FCM tokens committed.
  • CI injects google-services.json or uses environment-based substitution.

4. Test Account Setup

4.1 Device / emulator accounts

  • At least two test user accounts available (User A and User B) for couple pairing flows.
  • Test accounts use + or tagged email addresses for isolation (e.g., qa+a@closer.app, qa+b@closer.app).
  • Passwords stored in team vault; accounts enabled in Firebase Auth allowlist if applicable.

4.2 Data seeding

  • Seed questions and categories in Firestore/remote config for internal testing.
  • Seed at least one premium category and one free category.
  • Prepare test RevenueCat products with sandbox pricing.
  • Ensure test accounts have predictable subscription states (free, premium, expired).

4.3 Test scenarios matrix

Scenario User A User B
Unpaired new install fresh account fresh account
Paired couple paired with B paired with A
Premium unlock subscribed not subscribed
Different answer states answered daily not answered
Invite expiry create invite accept after expiry

5. Distribution Checklist

5.1 Firebase App Distribution

  • Firebase App Distribution Gradle plugin applied (optional but recommended).
  • App Distribution configured with tester groups (e.g., mvp-internal, qa-team).
  • Build variant selected: release (signed).
  • Distribution command run: ./gradlew :app:assembleRelease :app:appDistributionUploadRelease.
  • Testers receive email/notification with download link.
  • APK install succeeds and app launches.

5.2 Alternative distribution

  • If not using App Distribution, use internal Google Play track with closed testing.
  • Signed AAB uploaded to Play Console internal testing track.
  • Testers added to internal testing list.
  • Play Console review status tracked (internal tests may be immediately available).

5.3 Verification after install

  • App installs and opens on target device.
  • Onboarding flow reachable.
  • Auth and pairing flows tested end-to-end on distributed build.
  • Push notification received and quiet-hours suppression works.
  • Paywall loads products in sandbox (where RevenueCat configured).
  • Crashlytics reports non-fatal test event and appears in console.

6. Build Commands Reference

# Debug compile (fast smoke test)
./gradlew :app:compileDebugKotlin

# Debug install
./gradlew :app:installDebug

# Release APK (signed)
./gradlew :app:assembleRelease

# Release AAB (signed)
./gradlew :app:bundleRelease

# Firebase App Distribution upload
./gradlew :app:assembleRelease :app:appDistributionUploadRelease

7. Sign-off

Role Name Date Notes
Build engineer
QA lead
Product owner