AquaX Mobile Build And Release

Owner: Mobile, DevOps
Reviewers: QA, Backend, Security, Product, Release Owner
Status: Draft - Current-Code Baseline
Version: 0.1
Last Updated: 2026-09-17
Review Cycle: Per mobile release, signing, store or Expo SDK change

1. Purpose And Scope

This document describes the current AquaX mobile build and release process as implemented in mobile/.

It covers:

This document is based on current repository files, not on a planned EAS Build workflow. AquaX mobile currently has an Expo project ID in app.json, but no eas.json; release scripts use local expo prebuild, Gradle, Xcode and Fastlane/altool flows.

2. Source Files Reviewed

File Purpose
mobile/package.json Expo scripts, dependencies and validation scripts.
mobile/app.json App identity, package IDs, version, plugins and update settings.
mobile/.env.example Public runtime environment variables.
mobile/secrets/build_config.env.example Build credential variable template.
mobile/scripts/build_android_aab.sh Android AAB build script.
mobile/scripts/deploy_android_playstore.sh Android AAB build and Google Play upload script.
mobile/scripts/build_ios_appstore.sh iOS IPA build and App Store Connect upload script.
mobile/scripts/README_BUILD_IOS_APPSTORE.md Existing iOS build guide.
mobile/scripts/README_DEPLOY_ANDROID_PLAYSTORE.md Existing Android Play Store guide.
docs/Mobile_Architecture.md Mobile architecture baseline.
docs/09_Deployment Plan.md Deployment baseline and mobile release status.
.gitignore, mobile/.gitignore Secret/native-output ignore rules.

3. Current Mobile App Profile

Item Current value
Framework Expo React Native
Expo SDK ~56.0.8
React Native 0.85.3
React 19.2.3
TypeScript ~6.0.3
App name AquaX
Expo slug aquax-mobile
App version 1.0.0
Scheme aquax
Orientation portrait
UI style light
Expo updates disabled
Android package com.aquax.app
iOS bundle id in app.json com.aquax.app
iOS bundle id in iOS build script vn.aquax.app
EAS project id present in app.json
EAS build config not present

Important gap:

4. Runtime Environment

The mobile app reads public Expo environment variables:

Variable Purpose Example / Default
EXPO_PUBLIC_API_URL Backend API base URL http://192.168.2.62:3001/api in .env.example
EXPO_PUBLIC_APP_ENV Environment label development

Release rule:

5. Local Validation Before Build

Run validation from mobile/ before creating a store artifact:

cd mobile
npm install
npm run lint
npm run typecheck

Optional local smoke checks:

npm start
npm run android
npm run ios

Current package scripts:

Script Purpose
npm start Start Expo development server.
npm run android Run Android target through Expo.
npm run ios Run iOS target through Expo.
npm run web Start Expo web target.
npm run lint Run Expo ESLint.
npm run typecheck Run TypeScript without emitting files.
npm run format Format with Prettier.
npm run format:check Check formatting with Prettier.

6. Build Number And Versioning

Current app version is read from mobile/app.json:

{
  "expo": {
    "version": "1.0.0"
  }
}

Build scripts use BUILD_NUMBER when provided; otherwise they generate a timestamp-like number.

Platform Store field Script behavior
Android android.versionCode Generated from BUILD_NUMBER or trimmed timestamp, then written into app.json and Gradle.
iOS ios.buildNumber / CFBundleVersion Generated from BUILD_NUMBER or full timestamp, then written into app.json and Info.plist.

Release rules:

Known side effect:

7. Secrets And Signing Material

Credential template:

mobile/secrets/build_config.env.example

Real credential location:

mobile/secrets/

This folder is gitignored, except:

Do not add credential values to documentation, tickets, PR comments or logs.

7.1 Android Signing Variables

Variable Purpose Required
ANDROID_KEYSTORE_PATH Path to .jks or .keystore; auto-detected from mobile/secrets/ when omitted. Required for Play Store upload
ANDROID_KEYSTORE_PASSWORD Keystore password. Required
ANDROID_KEY_ALIAS Key alias, defaults to upload. Optional
ANDROID_KEY_PASSWORD Key password, defaults to keystore password. Optional
GOOGLE_PLAY_JSON_KEY Google Play service account JSON key. Required for upload
BUILD_NUMBER Store build number override. Optional

7.2 iOS Signing Variables

Variable Purpose Required
CERT_P12_PATH Apple Distribution .p12; auto-detected from mobile/secrets/ when possible. Required
CERT_P12_PASSWORD .p12 password; can be empty if certificate has no password. Optional
MOBILEPROVISION_PATH App Store .mobileprovision; auto-detected from mobile/secrets/ when possible. Required
ASC_KEY_ID App Store Connect API key ID; auto-detected from AuthKey_*.p8 filename when possible. Required
ASC_ISSUER_ID App Store Connect issuer ID. Required
ASC_KEY_PATH App Store Connect .p8 path; defaults to AuthKey_${ASC_KEY_ID}.p8. Required
ASC_PROVIDER_PUBLIC_ID Provider ID for accounts with multiple teams. Optional
BUILD_NUMBER Store build number override. Optional

8. Android AAB Build

Script:

mobile/scripts/build_android_aab.sh

Purpose:

Run from repository root:

chmod +x mobile/scripts/build_android_aab.sh
mobile/scripts/build_android_aab.sh

Main steps:

  1. Load mobile/secrets/build_config.env when present.
  2. Auto-detect Android keystore from mobile/secrets/.
  3. Generate BUILD_NUMBER when not provided.
  4. Run npm install --no-audit --no-fund.
  5. Run npx expo prebuild --platform android --clean.
  6. Write android.versionCode into mobile/app.json.
  7. Patch Gradle versionCode when generated native Gradle file exists.
  8. Run ./gradlew bundleRelease.
  9. Print the generated .aab path.

Expected artifact:

mobile/android/app/build/outputs/bundle/release/*.aab

9. Android Google Play Release

Script:

mobile/scripts/deploy_android_playstore.sh

Purpose:

Supported tracks:

Track Purpose
internal Internal testing; default and safest first upload target.
alpha Closed testing.
beta Open testing.
production Production release.

Run from repository root:

chmod +x mobile/scripts/deploy_android_playstore.sh
mobile/scripts/deploy_android_playstore.sh internal

Production upload:

mobile/scripts/deploy_android_playstore.sh production

Main steps:

  1. Validate the requested track.
  2. Load mobile/secrets/build_config.env.
  3. Auto-detect keystore and Google Play JSON key where possible.
  4. Install or verify Fastlane.
  5. Run npx expo prebuild --platform android --clean.
  6. Set Android versionCode.
  7. Build release AAB with Gradle.
  8. Upload AAB with fastlane supply.

Release recommendation:

10. iOS App Store Connect Release

Script:

mobile/scripts/build_ios_appstore.sh

Purpose:

Required build machine:

Run from repository root:

chmod +x mobile/scripts/build_ios_appstore.sh
mobile/scripts/build_ios_appstore.sh

Main steps:

  1. Load build variables from mobile/secrets/build_config.env and selected values from mobile/.env.
  2. Auto-detect .p12, .mobileprovision and AuthKey_*.p8 where possible.
  3. Create a temporary keychain.
  4. Import Apple Distribution certificate.
  5. Install provisioning profile.
  6. Run npx expo prebuild --platform ios --clean.
  7. Generate ExportOptions.plist.
  8. Patch Xcode project for manual signing.
  9. Run pod install --repo-update.
  10. Set iOS build number.
  11. Build archive and export IPA through xcodebuild.
  12. Upload IPA through xcrun altool.
  13. Delete temporary keychain on exit.

Expected artifact:

mobile/build/ios/ipa/*.ipa

iOS release blocker:

11. Release Flow

Recommended release flow:

feature/fix branches
  -> mobile validation
  -> release branch or approved release commit
  -> Android internal / iOS TestFlight candidate
  -> QA smoke + regression
  -> store production rollout
  -> post-release verification

Minimum release checklist:

12. QA Smoke Test

Smoke test each store candidate against the intended API:

Area Check
App launch Splash screen, icon and first screen render correctly.
Environment App points to intended API base URL.
Auth Login, token refresh and logout work.
Role navigation ADMIN, OWNER, MANAGER and TECHNICIAN routes load according to available accounts.
Owner flows Farm, pond, activity, feeding and ticket/problem surfaces load.
Technician flows Incident list, detail and accept/processing flows load.
Notifications Push registration does not crash and notification list loads.
Secure storage Session restoration works after app restart.
Error handling API/network error states are usable and do not expose secrets.

13. Rollback And Recovery

Android:

iOS:

Application data:

14. Current Automation Status

Area Current status
Mobile CI in GitHub Actions Not present in the main CI workflow.
Local validation scripts Present: lint, typecheck, format.
Android build script Present.
Android Play Store upload Present through Fastlane.
iOS App Store upload Present through local macOS/Xcode script.
EAS Build Not configured.
Expo OTA updates Disabled.
Store release manifest Not yet standardized.

15. Known Gaps

Gap Impact Recommended Follow-up
iOS bundle ID mismatch between app.json and build_ios_appstore.sh iOS release/signing can fail or target the wrong app record Align bundle ID across app config, script, provisioning profile and App Store Connect.
No eas.json despite EAS project ID Release process relies on local machines and custom scripts Decide whether to keep script-based releases or migrate to EAS Build/Submit.
Mobile CI is not in .github/workflows/ci.yml Mobile regressions may not block PRs Add mobile install, lint and typecheck jobs.
Scripts mutate app.json during build Build-number changes can be accidentally committed or lost Define whether build numbers are committed, generated only, or controlled by release tooling.
iOS script uses altool Apple tooling may require future migration Evaluate notarytool, Transporter or EAS Submit when updating release tooling.
Release manifest is not standardized Store release traceability may vary Add a mobile release record template covering commit, version, build, store track, API target and QA evidence.
Production API URL policy is not formalized for mobile Store build may point to the wrong API Add environment-specific build config and verification step.

16. Quick Commands

Validate mobile:

cd mobile
npm install
npm run lint
npm run typecheck

Build Android AAB:

mobile/scripts/build_android_aab.sh

Upload Android internal test:

mobile/scripts/deploy_android_playstore.sh internal

Upload Android production:

mobile/scripts/deploy_android_playstore.sh production

Build and upload iOS:

mobile/scripts/build_ios_appstore.sh

Set a manual build number:

BUILD_NUMBER=2026091701 mobile/scripts/build_android_aab.sh
BUILD_NUMBER=2026091701 mobile/scripts/build_ios_appstore.sh