CI Workflows
build.yml — parameterized build
Manually-triggered, build-only pipeline (no push, no deploy). Produces downloadable artifacts.
How to run
- GitHub → Actions tab → Build (left sidebar) → Run workflow.
- Pick:
- environment —
stagingorprod - target —
all,customer,mitra,backend, orcontrol_center - platform —
android,ios, orboth(only affects the customer/mitra apps; ignored for backend/control_center)
- environment —
- Run workflow. Open the run; artifacts appear at the bottom of the summary page when it finishes.
(You can also trigger it from the CLI: gh workflow run build.yml -f environment=staging -f target=all -f platform=android.)
Runner split (Linux vs macOS)
iOS can only be built on macOS, so the workflow routes jobs accordingly:
| Job | Runner |
|---|---|
customer-ios, mitra-ios |
macos-latest |
customer-android, mitra-android, backend, control_center |
ubuntu-latest |
⚠️ macOS runner minutes bill at ~10× Linux. That's why
platformdefaults toandroid. Chooseios/bothdeliberately.
What each target produces
| Target | Platform | Tool | Artifact | Notes |
|---|---|---|---|---|
customer |
android | Flutter | customer-<env>-android-apk → app-<env>-release.apk |
Debug-signed (no keystore in repo). Fine for internal/Firebase App Distribution. |
customer |
ios | Flutter | customer-<env>-ios-app (Runner.app) |
Unsigned (--no-codesign). See iOS prerequisites below. |
mitra |
android | Flutter | mitra-<env>-android-apk |
Same as customer-android. |
mitra |
ios | Flutter | mitra-<env>-ios-app |
Same caveats as customer-ios. |
control_center |
— | Vite | control-center-<env>-dist (the dist/ folder) |
VITE_API_BASE_URL baked in at build time — see below. |
backend |
— | Docker | backend-<env>-image (*.tar.gz) |
Env-agnostic image (config is runtime env vars). Load with docker load. |
all runs every selected job in parallel; each is independent, so one failing doesn't block the others.
⚠️ iOS prerequisites (not satisfied yet)
The iOS jobs are wired but will fail until two things are done:
- Per-flavor Xcode schemes (
staging,prod) must exist inios/Runner.xcodeproj. Today there's only the defaultRunnerscheme, soflutter build ios --flavor stagingerrors with "The Xcode project does not define custom schemes". This mirrors the Android flavor setup but on the iOS side (schemes + build configurations + per-config bundle IDs). - Code signing for a distributable
.ipa: Apple Developer certificate + provisioning profiles stored as GitHub secrets. The current jobs use--no-codesign, which only validates that the app compiles and produces an unsignedRunner.app(not installable on devices).
Until then, platform=ios/both is useful only once the schemes land. platform=android works today.
Environment specifics
- Apps (customer/mitra):
environmentselects the Flutter flavor + entrypoint +env/<env>.json(--flavor,-t lib/main_<env>.dart,--dart-define-from-file). Reminder:env/staging.jsonstill has a placeholder API URL until the staging backend is deployed. - control_center:
VITE_API_BASE_URLis compiled in. Defaults: prod →https://internal.halobestie.com, staging →https://staging-internal.halobestie.com. Override without editing the workflow by setting repo Variables (Settings → Secrets and variables → Actions → Variables):CC_API_BASE_URL_PROD,CC_API_BASE_URL_STAGING. - backend: the image is identical across environments; env/secrets are supplied at
docker runtime (see backend/DEPLOY.md). The<env>in the artifact name is just a label.
Deploying a build artifact (manual, since we don't push yet)
- Backend: download
backend-<env>-image, copy to the host, then:gunzip -c halobestie-backend-<env>.tar.gz | docker load # then run per backend/DEPLOY.md - control_center: download
control-center-<env>-dist, serve thedist/behind Nginx (internal-only). - Apps: download the APK and install / upload to Firebase App Distribution.
Pinned versions
Flutter 3.41.9, JDK 17, Node 20 (see env: block in build.yml). Bump them there when the team upgrades.
Not included yet (by design)
Pushing images to a registry and deploying are intentionally out of scope for this first iteration. When you're ready, the natural next step is a release.yml that pushes to GHCR and (optionally, via a self-hosted runner or SSH) deploys to the VPS.