Release Workflow
Step-by-step guide for shipping a new kiosk APK to the fleet.
Last updated: April 27, 2026
Prerequisites
- Access to the
familypocket-kioskGit repo - GitHub Actions secrets configured (see Secrets section below)
- Access to the technician dashboard (or auth service API)
Pre-Release Checklist
Before tagging a release, verify:
- All tests pass on CI (
./gradlew test) - APK builds successfully with the production keystore
- Manual smoke test on at least one staging device
- Database migration (if any) tested on staging
- Release notes drafted
versionCodeis strictly greater than previous release
Step 1: Bump Version
Edit app/build.gradle.kts:
app/build.gradle.kts
kotlin
defaultConfig {
versionCode = 2 // increment by 1 (monotonically, NEVER decrease)
versionName = "2.1.0"
}Rules:
versionCodemust be strictly greater than the previous releaseversionNamefollows semver: MAJOR.MINOR.PATCH- Tag must match versionName: tag
v2.1.0for versionName"2.1.0"
Step 2: Commit and Tag
Terminal
bash
git add app/build.gradle.kts
git commit -m "chore(kiosk): bump version to 2.1.0"
git tag v2.1.0
git push origin main --tagsStep 3: CI Takes Over (Automatic)
The tag push triggers .github/workflows/release.yml:
- Builds signed release APK (using secrets keystore)
- Computes SHA-256 hex checksum
- Renames APK to
familypocket-kiosk.apk - Creates GitHub Release with the APK attached
- POSTs
{ version, checksum }to auth service webhook - Auth service stores checksum in
kiosk_rollout_config.checksums
i
You don't need to do anything here. Wait for the GitHub Actions workflow to complete (check the Actions tab).
Step 4: Configure Rollout
After CI completes, update the rollout config via the technician dashboard OTA screen or the API:
Via API (curl):
curl
bash
curl -X PUT https://auth.familypocket.co.ke/api/auth/kiosk/rollout-config \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"targetVersion": "2.1.0",
"previousStableVersion": "2.0.0",
"rolloutPercentage": 5,
"active": true
}'Via Technician Dashboard:
- Open the OTA Rollout screen
- Set target version to
2.1.0 - Set previous stable to
2.0.0 - Set rollout percentage to 5%
- Toggle active ON
- Save
Step 5: Phased Rollout (7 days)
| Day | Percentage | Action |
|---|---|---|
| 0 | 5% | Release to ~500 devices. Monitor telemetry for crashes. |
| 2 | 25% | If no issues, expand. |
| 4 | 60% | Continue expanding. |
| 7 | 100% | Full fleet rollout. |
!
If you see crash spikes, drop rollout to 0% immediately.
curl -X PUT .../rollout-config \
-H "Authorization: Bearer <token>" \
-d '{ "rolloutPercentage": 0 }'How Devices Receive Updates
Update Flow
text
Device boots -> KioskEngineService runs update check every 4 hours
-> GET cdn.familypocket.io/update/latest
Headers: X-Device-Id, X-Current-Version
<- { targetVersion: "2.1.0", apkUrl: "/update/v2.1.0/apk", checksum: {...} }
-> GET cdn.familypocket.io/update/v2.1.0/apk
<- 302 redirect -> GitHub Releases download URL
-> Downloads familypocket-kiosk.apk, verifies SHA-256
-> Waits for safe window (22:00-03:00, charging, no active trip)
-> Silent install via PackageInstaller (Device Owner privilege)
-> POST cdn.familypocket.io/update/confirmForce updates (forceUpdate=true) bypass the safe window entirely.
Versioning Rules
- Filename is always
familypocket-kiosk.apk, version lives in the Git tag path - URL pattern:
github.com/.../releases/download/v{VERSION}/familypocket-kiosk.apk - Never reuse a tag. If v2.1.0 has a bug, ship v2.1.1
- Never re-sign with a different keystore
- Android refuses to install a lower versionCode, so always fix forward
Rollback
!
Android cannot downgrade APKs. You cannot roll back to a previous version.
If a release is bad:
- Drop
rolloutPercentageto 0 (stops new devices from getting it) - Fix the bug
- Release v2.1.1 with the fix
- Resume rollout with the fixed version
Post-Rollout Cleanup
After a full 100% rollout with no issues:
- Update
previous_stable_versionto the new version (e.g.,2.1.0), preparing for the next release cycle - Confirm
update.completedevents from at least 95% of recently-seen devices - Archive release notes in engineering wiki
i
Forgetting to update
previous_stable_version means the next phased rollout will serve an outdated fallback to devices outside the rollout percentage.GitHub Actions Secrets Required
| Secret | Description |
|---|---|
| KIOSK_KEYSTORE_BASE64 | Base64-encoded release keystore file |
| KIOSK_KEYSTORE_PASSWORD | Keystore password |
| KIOSK_KEY_ALIAS | Signing key alias (e.g., kiosk) |
| KIOSK_KEY_PASSWORD | Signing key password |
| BACKEND_DEPLOY_HOOK_URL | https://auth.familypocket.co.ke/api/auth/kiosk/release-webhook |
| SERVICE_TOKEN | Service-to-service auth token (must match auth service env) |