From flutter build to Google Play Store: The invisible toll of shipping an indie app to production

Official Google Play Store Feature Graphic for pwE (Pray With Me)
Official Google Play Store listing banner for pwE: Catholic Lectio & GospelGo-Live Nov 02 · v1.0.24+200 · 177 Countries

In the previous article, I shared the personal motivation and architectural foundations behind pwE (Pray With Me) — a cross-platform digital sanctuary for daily Lectio Divina (Prayerful Reading), built inside the independent software studio JHH Solutions.

When you spend over a decade working with enterprise mission-critical systems, distributed architecture, and SRE, there is a classic mental trap when building your own 0-to-1 product: assuming that once Clean Architecture, DDD, 51 ADRs, and 931+ automated tests are in place, publishing on the Google Play Store will be a routine operational formality. Run flutter build appbundle --release, fill out the store listing, and wait a few hours.

In reality, production-ready code is not a published product.

Between submitting v1.0.0+176, officially going live in Google Play Production on November 2, 2026 (v1.0.3+179), and navigating an intense first week of live Day-2 sustainment up to v1.0.24+200, crossing that "last mile" demanded 18 brand-new ADRs dedicated to release governance, compliance, offline resilience, billing, and internationalization (ADR 0052 through ADR 0069):

Nov 02, 2026Global Go-Live after 14-day Closed Testing
51 → 69 ADRs+18 formal decisions in the production stretch
99.07% · 5.0 ★Crash-Free across 37 device models & 18 countries
~3 min · $0Zero-CI deploy & 4.11% of Firestore free tier

Operating independently — wearing the hats of architect, mobile engineer, QA, SecOps, legal counsel, and product manager in the spare hours of a father of three young kids — teaches you quickly that the final mile to the store plays by its own rules. And the toughest one has nothing to do with a compiler.


The "14-Day Valley": the real filter for independent developers

Following Google Play Console's policy overhaul for personal developer accounts (created on or after November 2023), access to the Production track is no longer immediate. Before any everyday user can discover your app on the store, you must unlock a mandatory gate: Closed Testing.

The rule sounds straightforward in official docs, yet requires surgical coordination in practice:

Stage 01

Compliance & Manifest

Data Safety, AI Policies, FGS Video

Stage 02

Signed AAB Upload

Play App Signing + Crash Symbols

Stage 03

12+ Testers Opt-in

Authorized Emails & Store Link

Stage 04

14 Consecutive Days

Unbroken Retention + Telemetry

Stage 05

~72h Human Queue

Dossier + Safe Remote Config Floor

Stage 06

Nov 02 Go-Live

HTTP 200 in 177 Countries + Web

To unlock the Apply for Production button, Google requires at least 12 real testers (originally 20) who formally accept the invitation (opt-in), install the app on physical Android devices, and remain opted-in without interruption for 14 consecutive days.

For a large studio with an internal QA device lab, gathering a dozen phones is trivial. For an indie developer, it becomes an exercise in logistics, observability, and release engineering:

  1. Opt-in friction and silent Track Shadowing (ADR 0054): In Play Console, sending a direct store link isn't enough. You must authorize the tester's email, wait for propagation, collect web opt-in consent, and ensure the Google account signed into their browser matches the active Play Store account on their phone (otherwise they hit the dreaded "Item not found" screen). Even subtler: while running internal alongside two closed tracks (alpha and a dedicated WhatsApp testing track), we discovered that updating one track at a time left early testers stranded on older binaries. We solved this by building atomic multi-track promotion via API and wiring a VersionGovernanceBanner powered by Firebase Remote Config to gently prompt testers in-app whenever a newer build went live.
  2. Recruiting with an SRE safety buffer: I approached tester recruitment like SRE capacity planning — never run at N+0. Recruiting an intentional buffer of volunteers absorbed device swaps and life surprises without resetting our two-week clock.
  3. Genuine daily engagement and catching bugs no emulator would ever surface: Google reviewers inspect whether testers actually exercised the app and whether you shipped updates addressing feedback. With pwE, the Daily Liturgy gave testers an organic reason to open the app every morning — uncovering subtle real-world edge cases:
Real closed tester screenshot highlighting PT-BR AI output inside an English UI
Field Catch · Internationalization

Cross-Locale Leak in the Wild

A tester running Android in English received AI passage suggestions in PT-BR. That single screenshot drove our 5-layer deterministic 18-language architecture with strict English fallback (ADR 0068).

Real closed tester screenshot auditing subscription restore on the Benefactor screen
Field Catch · Play Billing v5+

Receipt Isolation & Restore

Hands-on testing of the Benefactor flow exposed multi-account Google Play receipt edge cases on shared devices, hardening our RevenueCat identity sync (v1.0.23+).

"What initially felt like a bureaucratic toll turned out to be the best pre-production stress test the project could have asked for."


Where Senior Engineering pays dividends during store review

Surviving the 14-day window is half the journey; the other half is passing Google Play Console's automated, regulatory, and policy gauntlets. Here, upfront architectural discipline stopped being theoretical and translated directly into approval velocity:

1. Data Safety, AndroidManifest Hygiene & Generative AI Policy (ADR 0025 & ADR 0057)

Google Play's Data Safety disclosure demands surgical precision around collection, encryption, and retention. Many indie apps get trapped in rejection loops because third-party AAR libraries silently merge sensitive permissions into the final manifest.

By auditing our merged release manifest (:app:processProdReleaseMainManifest), we explicitly stripped transitive permissions (AD_ID, ACCESS_ADSERVICES_ATTRIBUTION, READ_PHONE_STATE, and legacy STORAGE) using tools:node="remove". Conversely, to keep background OTA downloads for our offline Gemma 4 E2B (~1.3 GB) model on Android 14+, we recorded and submitted a physical-device walkthrough video demonstrating visible user benefit for FOREGROUND_SERVICE_DATA_SYNC. Combined with Zero-Knowledge AES-256-GCM encryption in the Spiritual Notebook, strict explicit opt-in before any cloud AI call, an in-app "Flag this passage" button on every AI card, and first-party privacy, terms, and cryptographic delete-account endpoints, compliance review sailed through cleanly.

2. From flutter run to Zero-CI Local Deploys & Multi-Locale .aab (ADR 0049 & ADR 0068)

Every Flutter engineer learns the hard way that an app running flawlessly in debug can break silently in release. Beyond AOT compilation and R8/ProGuard shrinking, Android App Bundles (.aab) carry a classic gotcha: by default, Play Feature Delivery performs Language Splitting, stripping locale packs that don't match the phone's primary language at install time — breaking dynamic in-app switching across our 18 languages (962 ARB keys) until we disabled language splitting (enableSplit = false, < 150 KB impact) alongside locales_config.xml.

To ship rapid fixes without burning 25 minutes of GitHub Actions quota per build, I built pwe_local_deploy.dart: a custom CLI that builds the obfuscated .aab locally, uploads Crashlytics symbols, and authenticates via native RS256 JWT straight against the Google Play Android Publisher API v3 — promoting builds across internal, closed, and production in ~3 minutes at zero CI cost.

3. Pre-Launch Reports, WCAG Accessibility & 360° Production Telemetry (ADR 0050 & ADR 0066)

Every .aab uploaded to Google Play triggers automated Firebase Test Lab crawlers across dozens of physical devices, hunting for native crashes, ANRs, < 48×48dp touch targets, and contrast regressions. Alongside 1,430+ automated tests across 236 suites (enforcing 16 executable SPEC-* specs, a 6-viewport matrix up to TextScaler 2.0x, and 8.10:1 WCAG AA contrast), we built pwe_production_monitor.dart — a $0/month executive CLI unifying Android Vitals, GA4, Crashlytics, and Langfuse OTLP v4.

4. Open Web (PWA) & Ethical PPP Monetization Across 174 Regions (ADR 0056 & ADR 0058)

While the 14-day Android clock ticked (and iOS follows its own roadmap), serving our Flutter Web app (pwe.jhhsolutions.dev/app) gave iPhone and desktop users immediate zero-install access. On the sustainability front (Friends of the Mission), we caught Google Play's default FX conversion inflating prices across emerging markets while displaying subscription benefits in a single language. We wrote pwe_monetization_sync.dart to programmatically sync 54 localized store listings (3 plans × 18 languages) across 174 countries using Purchasing Power Parity (PPP) — modeling our non-renewing 30-day contribution as a native prepaidBasePlanType.

Here is how that convergence of contemplative UX and release engineering looks live on Google Play today:

Google Play Screen 1: Daily Sanctuary and Sacred Icon
Daily Sanctuary
Official liturgy in quiet stillness
Google Play Screen 2: Sacred Icon Contemplation and Mystagogy
Visio Divina
Full-screen Byzantine icon mystagogy
Google Play Screen 3: Lectio Divina 4-Step Flow
Lectio Divina
4 classical steps without distractions
Google Play Screen 4: Contemplatio and Hold-to-Save
Contemplatio
Zero-Knowledge encrypted Notebook

The Nov 2 Go-Live & Week 1 live in production (build #179 to #200)

We submitted our Production dossier with v1.0.0+176 on October 30 (followed by v1.0.2+178 on October 31). During Google Play's ~72-hour human review queue, we spotted a subtle Remote Config trap: bumping min_supported_build_number prematurely in Firebase Remote Config would lock out reviewers and existing testers onto a binary not yet publicly downloadable. We kept min_supported_build_number = 1 unlocked until November 2, 2026, the exact moment our public Play Store listing returned HTTP 200 globally across 177 countries — promoting v1.0.3+179, enforcing floor 178, and receiving our very first spontaneous 5.0 ★ public review that same night.

Then came the real engineering baptism across our first seven days live (Nov 2–8), spanning 24 production releases (v1.0.0 through v1.0.24+200):

Day 1 (Nov 2) · Telemetry Defense

Blocking 84 Crawler Bots at Minute Zero

Within hours of going live on Nov 2, 84 automated crawler accounts from Firebase Test Lab hit onboarding and created synthetic profiles in RevenueCat. Same day (v1.0.4), we read native Settings.System("firebase.test.lab") to isolate 100% of bots before billing or analytics boot.

Week 1 · 37 Physical Device Models

99.07% Crash-Free Across 18 Countries

In week one alone, the app welcomed 440 active users across 18 countries running on 37 distinct physical phone and tablet models (from Android 10 <= 4 GB RAM devices to Android 16/17 flagships), maintaining zero Android Vitals alerts and 17.2 min of average engaged time per user (70.0% engagement rate).

Product Discovery · ADRs 0060, 0062 & 0063

58.3% Silent Readers vs. 190 Encrypted Vaults

Aggregate telemetry revealed that 58.3% pray daily in silence (like a contemplative Missal), while 42.5% write encrypted prayers across 190 Zero-Knowledge (AES-256-GCM) vaults — driving our 0 ms True Local-First cold start and OS-level Interior Recollection Mode (Mt 6:6 DND).

FinOps & AI · ADRs 0065 & 0069

4.11% of Free Tier & 100% Orthodoxy

Even with a parallel 18-locale liturgy worker and thousands of GCS Static CDN reads, daily Firestore usage stayed at just 4.11% of the free-tier read quota ($0/month infra bill), paired with native Gemma 4 token streaming and 100% theological orthodoxy in Langfuse OTLP v4.


Open architecture where it matters, protected IP where it's sacred: inside pwe-architecture-showcase (ADR 0051)

Every engineer shipping a commercial indie product faces a classic portfolio dilemma: when your production monorepo must stay private — to safeguard pastoral prompts (Zero-Public-URL / SEC-AI-10), proprietary 7 Drops curation, ingestion workers, and cloud credentials — how do you let peers, architects, and hiring managers verify your real production engineering without asking them to take your word for it?

Our answer in ADR 0051 was evslopes/pwe-architecture-showcase, continuously synchronized from the private production monorepo via our custom tool/sync_showcase.dart CLI. On every release, it exports a strict Allowlist, runs a deterministic Redaction Engine (16 sanitization rules), and enforces a post-build Security Leak Scanner (13 forbidden patterns) that aborts the push if any internal identifier survives.

Every engineering story in this article can be audited directly in real Dart production code and unit tests today:


6 practical lessons for shipping your first indie app

If you are a software engineer preparing to publish an independent project on Google Play, here is the field playbook I wish I had on Day 0:

Critical StageCommon PitfallPractical Mitigation
1. Account & IdentityWaiting until code is "done" to open your Play Console account (assuming it's just a quick $25 fee).Register and complete identity and payment verification weeks ahead; document checks take days.
2. Testers & TracksInviting exactly 12 friends over chat and managing multiple tracks manually in the UI.Recruit 18–25 testers, share a 3-step visual opt-in guide, and promote the exact same versionCode across internal and closed to prevent Track Shadowing.
3. Manifest & AI PolicyBlindly trusting plugin permissions and generic free privacy policy generators.Strip unused transitive permissions via tools:node="remove", enforce explicit AI opt-in + content reporting, record a video for Foreground Services, and host privacy, terms, and delete-account on your own domain.
4. .aab & Multi-LocaleTesting exclusively via flutter run in debug and in a single language until launch eve.Test obfuscated release .aab builds on internal tracks from Sprint 1, set enableSplit = false for dynamic locales, and enforce deterministic English (en) fallback.
5. Production DossierWriting vague, one-line answers on Google's final production questionnaire.Document clearly how you recruited testers, which real field bugs were resolved across your 14-day releases, and how you monitor vitals in production.
6. Review Queue & Day 1Raising force-update floors in Remote Config during the ~72h human review queue and ignoring bot traffic at launch.Keep min_supported_build_number unlocked until your public listing returns HTTP 200, and detect firebase.test.lab natively on Day 1 so dozens of crawler bots don't pollute billing or analytics.

Code on your machine is study; code in the store is responsibility

Seeing the "Available on Google Play" badge go live globally on November 2, 2026 for pwE (Pray With Me) brought home a truth that years of enterprise work can sometimes numb: when you sign your name to a product end-to-end, software architecture stops being an abstraction.

Every single one of our 69 ADRs, every Zero-CI release script, and every cryptographic privacy guard existed for one purpose alone: allowing someone on the other side of the screen to open their phone and find silence, beauty, and trust — never needing to know how much engineering had to work quietly behind the scenes to protect that moment.

LIVE IN GLOBAL PRODUCTION SINCE NOV 02
Try pwE & Audit Real Production Code on GitHub

pwE is live and free on the Google Play Store (177 countries) and on the Web, backed by the public pwe-architecture-showcase repository with 69 ADRs and 20 real Clean Code Slices:

About the Author · JHH Solutions

Elvis Freitas Lopes Herllain

Senior Software Engineer, Tech Lead, and Solutions Architect with 10+ years of experience in mission-critical enterprise systems (SRE / L3 RCA) and full-cycle 0-to-1 product engineering at the independent studio JHH Solutions.