Your friendly map to the codebase — what the app is, how it’s built, how to get it running, and how the core flows work. Read it at your own pace.
Welcome aboard — and take a breath.
stc pay is a big app, and nobody expects you to hold all of it in your head this week. Think of this guide as your map, not a test: skim what you need now, and come back to the rest when a real ticket pulls you there. By the end of §04 you’ll have the whole app in one mental picture — everything after that just fills it in.
| When | Read |
|---|---|
| Day 1 | §01–04 — what the app is and the one mental model. ~10 minutes. |
| Your first week | §08–11 to get it building, then §12–16 plus one walkthrough (§19) to see how a real screen works. |
| Keep handy | §05–07 (the map), §17–20 (flows), §23 (glossary), §24 (cheat-sheet). |
Along the way: monospace means a real file, class or command; coloured callouts flag things worth noticing; and a “To complete” callout marks a spot only the team can fill in.
First stop: a 60-second picture of what you’re actually building.
The whole map on one page — jump in wherever you need.
stc pay is a digital wallet — a “super-app” that puts a lot of money services behind one login. This repo is the customer-facing Android app for Bahrain, now stretching to Kuwait too (the Gradle project is even named stcPayBH-KW).
In plain terms, a user can hold a balance, top it up, send / request / split money, pay bills and merchants, order a card, remit money abroad, and earn cashback — all in one place. Two themes follow from handling real money, and you’ll feel them throughout the code: regulation (identity checks, OTPs, limits, account statuses) and security (encryption, tamper/root detection, secrets kept out of source).
One app, two app stores: it ships as GMS (Google Play) and HMS (Huawei AppGallery) builds, so it runs with or without Google services.
| Repository | stcpaybh/stcpay-customer-android |
| Application ID | com.vivacash.sadad |
| Current version | 8.7.8 (build 422) |
| Branches | main (released) · develop (where you work) |
com.vivacash.* and the app ID com.vivacash.sadad are legacy brand names — read them as “stc pay internal”. Second, the Bahrain and Kuwait apps share a codebase, and code gets copied both ways (BH→KW and KW→BH), so you’ll find packages like com.stcpay.customer.kuwait in the Bahrain build and a few that simply don’t match their module. It’s history and cross-copying, not a mistake — don’t read meaning into the country in a package name.
So that’s the what. Here’s the how, in one picture.
If you remember one sentence from this guide, make it this one:
Hold that, and every feature reads the same way. Here is what actually happens when a user taps something — load a balance, confirm a payment, anything:
hiltViewModel() and shows whatever state the VM exposes.NavigationBaseVM).NetworkResponse — loading, success, or error — and the screen’s dialogs react to it automatically.That last step is the one surprise worth flagging early:
NavController. They write a navigation request into a channel and one Composable carries it out — which keeps VMs simple and lets a deep link or a push notification navigate the very same way.
That’s the entire app. The rest of this guide just zooms into each part — starting with where all that code actually lives.
~40 modules sounds like a lot, but they fall into four easy buckets — and day to day you mostly live in the one feature you’re working on. Module names matter when you’re navigating the code, so here is every one, with its package root.
| Module | What it does | Package root |
|---|---|---|
:app | Single-Activity shell: StcApplication, MainActivity, the NavHost, deep-link wiring. Depends on every feature. | com.stcpay.customer.kuwait |
:util | Low-level helpers: crypto, biometrics, permissions, phone & locale utilities. | com.vivacash.util |
:dto | Request / response data classes. | com.vivacash.dto |
:network | Retrofit client, base URLs, the NetworkResponse result types. | com.vivacash.network |
:eventLogging | Analytics fan-out (Firebase, Adjust, OneSignal, Remote Config). | com.vivacash.eventlogging |
:notification | Push notifications (Firebase / Huawei). | com.vivacash.notification |
:payment | Shared payment & review-transaction logic. | com.vivacash.payment |
| Module | What it does | Package root |
|---|---|---|
:common | Umbrella that re-exports the three below — features depend on this. | com.vivacash.common |
:common:navigator | Navigation core: AppNavigator, NavigationBaseVM, routes, deep links, session. | com.vivacash.navigator |
:common:repository | The repository layer over :network. | com.vivacash.repository |
:common:commonui | Shared Compose UI, base ViewModels, the eKYC SDKs. | com.vivacash.commonui |
:common:keys | Build-config secrets (from the native module in production). | com.vivacash.keys |
| Module | What it does | Package root |
|---|---|---|
:ekyc:base | Shared eKYC building blocks + the Bahrain IGA eKey web flow. | com.vivacash.base |
:ekyc:verification | The identity-verification screens & flow. | com.vivacash.ekyc.verification |
:ekyc:location | GCC location check during onboarding (maps). | com.vivacash.location |
| Module | What it does | Package root |
|---|---|---|
:features:onboarding | First-run splash & session bootstrap (the NavHost start). | com.vivacash.onboarding |
:features:login | Login / authentication (MPIN, biometric). | com.vivacash.login |
:features:registration | Sign-up + OTP, leading into eKYC. | com.vivacash.registration |
:features:home | The dashboard: balance, cards, services, recent activity. | com.stcpay.customer.kuwait.home |
:features:history | Transaction history & receipts. | com.vivacash.history |
:features:sendmoney | Peer-to-peer transfer (to mobile or IBAN), QR scan. | com.stcpay.customer.kuwait.sendmoney |
:features:requestandsplitmoney | Request money from, and split bills with, contacts. | com.vivacash.requestandsplitmoney |
:features:contactsView | Shared phonebook picker (Room-cached contacts). | com.vivacash.inviteafriendcontactsview |
:features:addMoney | Wallet top-up / cash-in (card, BenefitPay, branch maps). | com.stcpay.customer.kuwait.addmoney |
:features:cards | Physical & virtual card management, 3DS, tokenization. | com.vivacash.cards |
:features:remittance | Cross-border money transfer. | com.stcpay.customer.kuwait.remittance |
:features:marketplace | In-app services & bill payments (Fawateer, prepaid/postpaid, EWA…). | com.stcpay.customer.kuwait.marketplace |
:features:cashback | Cashback pocket / rewards (also usable as a payment source). | com.vivacash.cashback |
:features:stcPayCheckout | Merchant in-app (app-to-app) checkout. | com.vivacash.stc_pay_checkout |
:features:webCheckout | Merchant web (3DS) checkout. | com.vivacash.webcheckout |
:features:payPal | PayPal link, top-up & withdraw. | com.vivacash.paypal |
:features:fawryEgypt | Fawry Egypt bill payments. | com.vivacash.fawryegypt |
:features:samsungpay | Samsung Pay card tokenization. | com.vivacash.samsungpay |
:features:gulfair | Gulf Air MilesPlus loyalty link & redeem. | com.vivacash.gulfair |
:features:inviteafriend | Referral / invite a friend. | com.vivacash.inviteafriend |
:features:appWidgets | Home-screen Glance widgets (balance, cashback, miles). | com.vivacash.appwidgets |
:features:appstoreupdate | In-app update & review prompts. | com.vivacash.appstoreupdate |
| Module | What it does | Package root |
|---|---|---|
:securityNDK | Native C++ (CMake) holding production secrets; only in prod builds. | com.vivacash.sadad.securityndk |
:biometric_view | Biometric-auth UI gate. | com.vivacash.biometricview |
:otpview | OTP-entry UI + SMS auto-retrieval. | com.vivacash.otpview |
:benefit_pay_sdk | Vendored BenefitPay in-app SDK (an .aar). | (AAR — no namespace) |
com.vivacash.* and com.stcpay.customer.kuwait.* above. That’s expected — see §03: the Bahrain and Kuwait apps share a codebase, so a module’s package doesn’t always match its name or country. Don’t read meaning into it.
Dependencies run top-down and never loop: features sit on top of :common, which sits on the foundation. The foundation never reaches up into a feature.
:app ─► features:* + :notification + :biometric_view
│
▼
:common ( commonui + navigator + repository )
│
▼
:network ─► :dto ─► :util ─► :common:keys ─► :securityNDKThe upshot: features never depend on each other’s internals — anything shared lives in :common or :payment. Now, what those modules are built from.
You don’t need to memorise versions — they all live in one file, gradle/libs.versions.toml. Just know the headline numbers and roughly why each library is here.
| Component | Version |
|---|---|
| Java / JDK | 17 |
| Kotlin | 2.2.0 |
| Android Gradle Plugin | 8.13.2 |
| compileSdk / targetSdk | 36 |
| minSdk | 23 (Android 6.0) |
| Compose BOM | 2025.12.01 |
| Hilt · Room · Nav | 2.56.2 · 2.7.1 · 2.9.0 |
(minSdk 23 reaches back to Android 6, but core-library desugaring is on, so modern Java APIs still work.)
| Area | Library | Why it’s here |
|---|---|---|
| UI | Jetpack Compose, Material 3, the in-house stcpay-ui-kit | The whole UI is Compose. |
| DI | Hilt | Wires the app together; scopes ViewModels. |
| Network | Retrofit, OkHttp, Gson | Talks to the backend. |
| Data | Room, SharedPreferences, Coroutines, WorkManager | Local storage and background work. |
| Platform | Firebase (GMS) / AGConnect (HMS) | Push, crash reporting, config — per app store. |
| Identity | Jumio + iProov | ID scan & liveness for eKYC. |
| Engagement | OneSignal, Adjust, Intercom | Push, attribution, support chat. |
| Security | BouncyCastle, AndroidX Security & Biometric | Crypto for a banking app. |
stcpay-ui-kit — linked as a required composite build. The app won’t even sync without it, and it’s why you won’t find StcPayTheme or the common components here. Set it up — and browse the full component catalogue — in the dedicated UI Kit guide (stcpay-bh-android-ui-kit-knowledge-transfer.html); walk through it with your lead the first time.
One more piece of the map, then we build: the patterns that repeat across every module.
A handful of patterns repeat across the whole codebase. Learn these five and the code stops surprising you.
com.stcpay.customer.kuwait is the app and some newer features; com.vivacash.* is everything else (an old brand name). Same project — just history.
A feature’s build.gradle.kts is only a few lines because all the real Gradle config lives once in build-logic/convention/ as reusable stcpay.* plugins. A module just applies one or two:
plugins { alias(libs.plugins.stcpay.android.library.compose) // Android + Compose alias(libs.plugins.stcpay.hilt) // + dependency injection } dependencies { implementation(projects.common) }
| You see… | It’s… |
|---|---|
XxxScreen + XxxScreenVM | A Composable screen and its ViewModel. |
XxxRepository / Impl | A data source: the interface and its implementation. |
XxxApiService | A Retrofit endpoint group. |
onXxxNavigation() | A feature’s screens, registered into the one NavHost. |
xxxRSH | A RemoteServiceHandler — one per API call in a ViewModel. |
:common (or :payment) — never feature-to-feature.AppNavigator — never give a ViewModel a NavController.That’s the whole map — what the app is, where the code lives, and how it’s shaped. Let’s get it running on your machine.
Two things to line up: the tools on your machine (quick), and the access only the team can grant (ask early, it can take a day or two).
stcpaybh GitHub org.[ ... ].
| Repo access | [ how to get added to the GitHub repo ] |
| VPN / network | [ is VPN needed to reach UAT? ] |
| Secrets & keystore | debug.properties, release.properties & debug.keystore — needed at the repo root and in util/. [ where to get them ] |
| UI Kit repo | [ clone URL for stcpay-bh-android-ui-kit ] — required for the build (§09). |
| Test accounts | [ UAT test numbers / OTP for login & eKYC ] |
| Consoles & chat | [ Firebase / OneSignal / Adjust access + team channels ] |
Got those? Let’s build it.
The happy path is short:
stcpay-bh-android-ui-kit). Open the app root in Android Studio.debug.properties, release.properties, debug.keystore — at both the repo root and inside util/.stcPayUiKitProjectPath, below) — this is required../gradlew :app:assembleGmsUat.debug.properties, release.properties, debug.keystore) are deliberately not in git and are needed at the repo root and in util/. (2) The UI Kit composite build must be linked (below). Miss either and the project won’t sync. [ to complete: where the secrets files live ]
local.properties)The app depends on the in-house stcpay-ui-kit, supplied from source as a composite build — without it the project won’t sync. Point local.properties at your local clone of the UI Kit repo:
stcPayUiKitProjectPath | Required. Absolute path to your stcpay-bh-android-ui-kit clone. |
stcPayNDKPath | Optional — NDK location for the native security module. |
stcpay-bh-android-ui-kit-knowledge-transfer.html). It’s short; read it before your first sync.
Before you hit Run, one quick word on which build you’re making.
A build variant is just a flavor × a build type — e.g. gmsUat. Both are defined once in build-logic/ and shared everywhere.
Flavor is the app store: gms (Google) or hms (Huawei), each pulling in its own services and a src/gms / src/hms source set. Build type is the environment — and note they’re named after environments, not debug/release:
| Build type | Backend | Notes |
|---|---|---|
uat | api.uat.stcpay.com.bh | Your day-to-day dev build. Debuggable. |
preProd | api.pre-prod.stcpay.com.bh | Pre-release testing. |
prod | api.stcpay.com.bh | Release: minified, ProGuard, prod signing. |
# this is the one you'll use most $ ./gradlew :app:assembleGmsUat $ ./gradlew :app:assembleHmsUat # Huawei build $ ./gradlew :app:bundleGmsProd # release AAB
In Android Studio’s Build Variants panel, pick gmsUat. (Production signing is gated by an IS_PRODUCTION flag — [ to complete: how it’s set in CI ].)
gmsUat and a device or emulator (Android 6+).:app — you’ll land on the splash, then Welcome / Login.uat won’t get blocked.
If the build fights you, it’s almost always one of these:
| Symptom | Fix |
|---|---|
| Fails on missing signing / properties | Add debug.properties, release.properties & debug.keystore at the repo root and in util/ (§09). |
Can’t resolve com.stcpay:stcpay-ui-kit | The UI Kit isn’t linked — set stcPayUiKitProjectPath (see the UI Kit guide). |
| “Class already exists” / duplicate on sync | Composite-build name clash — match the UI Kit’s project name with the app’s includeBuild name, sync, then revert (UI Kit guide §06). |
| NDK / CMake not found | Install the NDK or set stcPayNDKPath. |
| HMS variant won’t build | Missing agconnect-services.json — use a gms variant unless you need HMS. |
| Wrong backend / Gradle JDK errors | Pick a *Uat variant; set the Gradle JDK to 17. |
It’s running. Now let’s peek under the hood — what happens from launch to that first screen.
Getting to the first screen is three quick handoffs: the Application, the one Activity, then Compose.
StcApplication wakes up the SDKsThe Hilt application root (@HiltAndroidApp). Its onCreate starts what the whole app leans on — Timber logging (non-prod), the security SDK (prod only), Firebase (skipped on Huawei), the preferences store and device ID, then Adjust, Intercom, OneSignal and the locale engine. Secret keys come from KeysProviderImpl (the native NDK in production).
MainActivity — the only ActivityIt draws edge-to-edge, clamps the font scale (so huge system fonts can’t break layouts), sets up the deep-link gate, fetches remote config, then hands everything to Compose with setContent { AppRoot() }.
AppRoot → AppContent — Compose takes overAppRoot picks light/dark and wraps the app in StcPayTheme. AppContent wires up the navigator and declares the single NavHost where every feature plugs in its screens:
NavHost(navController, startDestination = StcRoute.OnBoarding) { onBoardingNavigation(navController) onLoginNavigation(navController, prevRepo, onSuccessfulLogin = { session.setLoggedIn(true) }) onHomeNavigation(navController, prevRepo) // … ~20 feature graphs, one line each … }
That NavHost is the spine of the app — so let’s see how navigation actually works.
One rule sums it up: ViewModels don’t navigate — they post a request, and one place carries it out.
AppNavigator holds a channel of navigation requests (go back, go to a route, session-expired, logout…). A ViewModel writes to it; a single Composable, NavigationEffects, reads from it and drives the real NavController. In practice your VM extends NavigationBaseVM, gets AppNavigator injected, and calls a helper like moveBack() / moveToHome() — or appNavigator.navigateTyped(SomeScreen) for anything custom.
StcRoute names the top-level graphs (OnBoarding, Home, Login…); StcScreens names individual screens. Each feature exposes an onXxxNavigation() that the one NavHost calls — and that’s exactly where you register a new screen:
fun NavGraphBuilder.onHomeNavigation(navController, prevRepo) { navigation(startDestination = StcScreens.HomeScreen.name, route = StcRoute.Home.name) { composable(StcScreens.HomeScreen.name) { HomeScreen2() } composable<StcScreens.ProfileScreen> { ProfileScreen() } } }
A tapped notification or an external URL flows through input → parse → gate → dispatch. The interesting part is the gate: it’s a login check. If a link needs you logged in and you aren’t, it parks the link, sends you to Login, and replays it the instant you’re in — which is how a payment push can drop you straight onto the right screen after login.
Every screen those routes lead to is an MVVM ViewModel. That pattern is the real backbone — next.
If there’s one section to actually learn, it’s this one — every screen follows the same loop, so once it clicks you can read any feature in the app.
The loop: a Composable gets its ViewModel with hiltViewModel(), shows the VM’s state, and calls VM functions on taps. The VM extends NavigationBaseVM, runs each API call through a RemoteServiceHandler, and navigates via AppNavigator.
It’s deliberately thin: a ViewModel with the navigator injected and a few navigation helpers. (Loading and error state aren’t here — they live per API call, below.)
@HiltViewModel open class NavigationBaseVM @Inject constructor(app, val appNavigator: AppNavigator) : AndroidViewModel(app) { fun moveBack() = appNavigator.tryNavigateBack() fun moveToHome() = appNavigator.tryNavigateBack(StcScreens.HomeScreen.name) }
You declare one handler per endpoint, with an apiCall lambda and callbacks. setRequest(req) fires it; the handler flips loading/error flags as the result comes back, and a matching RemoteServiceListener in the screen renders the loading and error dialogs straight off those flags — so you never wire that UI by hand.
val fetchUserRSH = RemoteServiceHandler( vm = this, remoteServiceCallbacks = object : RemoteServiceCallbacks<BaseRequest, UserResponseBody>() { override fun onSuccess(code, body, title, msg) { user.value = body } }, apiCall = { dashboardRepository.userAccount(it) }, )
StcScreens.kt.@HiltViewModel VM that extends NavigationBaseVM, exposes state, and declares its API calls as handlers.hiltViewModel(), show the state, drop in a RemoteServiceListener.onXxxNavigation() (§13).See step 2, where the VM calls a repository? That’s how the app talks to the backend — let’s open that up.
Good news: every backend call has the same shape — VM → repository → Retrofit → a NetworkResponse — so once you’ve seen one, you’ve seen them all.
Hilt provides one shared OkHttp + Retrofit client (the base URL is set per environment). Service methods hand back LiveData<NetworkResponse<T>>, and request logging is on only in non-prod builds.
Authorization header. Auth travels as a session-id inside the request body (via BaseRequest, which also fills in device, version, locale and platform automatically). If you’re hunting for a bearer token, that’s why you won’t find one.
NetworkResponse is a sealed result type — Loading, Success, the various errors, SessionExpired, NoInternet. A repository wraps a single Retrofit call in a NetworkBoundResource (which unwraps the BaseResponse envelope) and exposes it as LiveData. The shape is always:
override fun getCardServiceDetails(body) = object : NetworkBoundResource<Service, …>(Service::class) { override fun createCall() = cardApiService.getCardServiceDetails(body) }.asLiveData()
SharedPreferences is the main local store (sensitive values like the session id and PIN are hand-encrypted with CryptoHelper). Room appears in exactly one place — the contacts cache. Models are Gson DTOs, each wrapped in a BaseResponse envelope (response-code / -message / data).
A few shared services hum behind all of this. That’s the last piece of “how it works”.
Five pieces of shared machinery you’ll lean on without thinking about them much.
Hilt, all app-wide (the SingletonComponent). StcApplication is @HiltAndroidApp, MainActivity is @AndroidEntryPoint, and providers live in modules like AppModule, HttpModule and RepositoryModule.
SimpleSessionProvider is the single source of truth (isLoggedInFlow). A 10-minute idle timer logs the user out — but every API call resets it, so active users stay in. On expiry the app shows the session-expired dialog.
Production secrets live in the native :securityNDK. Hardening (root / emulator / tamper checks via SecureUtility) runs only in production and behind a remote-config flag; any hit routes to a SecurityInfoDialog.
LocaleManager + LocaleWrapper handle language and right-to-left layout; strings are per-module (res/values/ + res/values-ar/). Country (Bahrain vs Kuwait) is a runtime setting (CountrySetup), not a build flavor.
StcEvents.logEvent() is the one place events fan out to Firebase, Adjust and OneSignal. Push is owned by OneSignal; the native Firebase/Huawei services just forward the token.
That’s the engine. Now let’s watch it run — three real flows, start to finish.
The way in chains three features — onboarding → login → registration — all inside the one NavHost (which starts at OnBoarding).
SplashScreen plays a Lottie animation while SplashScreenVM checks or creates a session (a Firebase flag can act as a kill-switch). When both finish, it routes on to Login.
WelcomeScreen shows a returning user (from the saved number) or a sign-up path. PinScreen takes the MPIN — or a biometric prompt — and fires loginUser() with the encrypted PIN. On success, getRouteBasedOnStatus(...) reads the account status and sends the user wherever they need to be (Home, or back into an eKYC step). The session itself flips in the NavHost wiring: onSuccessfulLogin = { setLoggedIn(true) }.
Sign-up is a short funnel:
getRouteBasedOnStatus(...) drives both login and sign-up, so a user always lands wherever their account currently needs them — no matter how they got there.
That last step hands off to identity verification — the part unique to a regulated wallet.
A wallet is a regulated product, so the user’s identity must be verified (KYC) before an account or card is issued. The ekyc:* modules do this digitally — ekyc:base (shared logic + the Bahrain eKey flow), ekyc:verification (the screens), and ekyc:location (a GCC location check).
IgaEkeyWebViewScreen); the branch is KycOnBoardType.JUMIO vs E_KEY.
Once verified, the user’s in. Here’s what they do most — move money.
This is the flagship money flow — trace it once and you understand every money feature, because they all share this skeleton.
On entry, HomeScreen2 fans out several loads at once — balance, cards, the services grid, a two-row recent-activity preview. The balance is cached so other screens can read it instantly, and the services grid is server-driven (the backend decides which tiles appear).
pay() fires the payment handler → repository → the pay endpoint.Two supporting modules round it out: requestandsplitmoney, and contactsView — in fact the send-money VM extends the contacts list VM to reuse the picker. Send money is just one rail, though. The app plugs into many.
stc pay connects to a lot of payment networks — but they all share the same plumbing (repository → handler → a shared review flow), so this is really just a tour of what each one is.
| Rail | What it is |
|---|---|
| BenefitPay | Bahrain’s national payment scheme — both an in-app SDK and an app-to-app launch. (Removed in the Kuwait build.) |
| Samsung Pay | Provisions an STC card into Samsung Wallet. |
| PayPal | Link a PayPal wallet; top-up / withdraw via a web redirect (USD↔BHD). |
| Fawry Egypt | Egyptian bill payments with a dynamic, biller-specific form. |
| stc pay Checkout | Merchant app-to-app payment; validates, pays, returns a result. |
| Web Checkout | Merchant 3DS flow — confirm a tentative transaction. |
| Cards | Order / freeze / renew cards; 3DS purchase challenges arrive as a notification. |
| Add Money | Top-up via card, BenefitPay or Fawri (card payments go through a 3DS WebView). |
| Remittance | International transfer; reuses the send-money transfer endpoint. |
| Marketplace | Bills & services — Fawateer, prepaid/postpaid, EWA, charity, gift cards. |
And a few smaller pieces: cashback (rewards, also usable to pay), Gulf Air MilesPlus, invite-a-friend, home-screen widgets, and the unified transaction history.
That’s the app, end to end. Last stop — how we work on it together.
How code travels from your branch to the app stores.
| Branch | Purpose |
|---|---|
main | Released, production code. |
develop | Integration — you branch from, and merge back to, this. |
feature/* | Your work, merged into develop. |
hotfix/* | Urgent production fixes. |
release/* | Release stabilisation (e.g. release/8.7.8). |
You’ll see a big feature/kuwait* cluster too — that’s the Kuwait rollout (adding KW rails, removing some Bahrain-only ones).
Semantic MAJOR.MINOR.PATCH, git-tagged each release (currently 8.7.8). It’s defined in exactly one place:
projectVersionName = "8.7.8" projectVersionCode = "422"
| Cutting a release | [ who cuts release/x.y.z, and when ] |
| CI / signing | [ how prod artifacts are built & signed ] |
| Store submission | [ Play + AppGallery upload process ] |
| Sign-off | [ QA / pre-prod gates before release ] |
The human side. The defaults below are a sensible starting point — confirm and complete them with your lead.
Branch from develop, open a focused PR back into develop, and link the ticket. [ to complete: required approvals, code owners, the CI checks that must pass ]
| Android lead(s) | [ name & contact ] |
| Feature owners | [ who owns cards / sendmoney / ekyc … ] |
| Backend / API contact | [ who to ask about endpoints & response codes ] |
| Team chat | [ Slack / Teams channels ] |
| Boards & docs | [ Jira board + wiki ] |
| UI Kit guide | Setup & reference for the required design-system composite build (stcpay-bh-android-ui-kit-knowledge-transfer.html). |
| SDK guide | The SDK internal setup guide (stcpay-bh-sdk-internal-setup-guide.html). |
The words and acronyms you’ll bump into most — keep this open in a tab for your first week.
| Term | In one line |
|---|---|
| super-app | One app bundling many money services under a single login — this whole codebase. |
| KYC | Know-Your-Customer: verifying who a user is before giving them financial features. |
| eKYC | Doing that KYC digitally, in-app (the ekyc/ modules). |
| IGA eKey | Bahrain’s government national digital identity (a WebView verification). Bahrain-only. |
| Jumio | The vendor that does ID-document scan + liveness during eKYC. |
| iProov | The face-liveness check, run inside Jumio. |
| OTP | One-Time Password — a short code confirming a sensitive action. |
| MPIN | The user’s numeric app login / transaction PIN. |
| 3DS | 3-D Secure: the bank’s challenge step for online card payments. |
| MDES | Mastercard’s service for tokenizing a card into a wallet. |
| BenefitPay | Bahrain’s national payment scheme (removed in the Kuwait build). |
| Fawateer | Bahrain bill-payment aggregator. |
| Fawry | Egyptian bill-payment network. |
| ENET | A Kuwait payment / bill aggregator. |
| remittance | Sending money across borders. |
| top-up | Loading wallet balance or airtime. |
| GMS / HMS | The Google vs Huawei build flavors. |
| OneSignal | The push-notification service (owns most push here). |
| Adjust | Marketing-attribution SDK. |
| Intercom | In-app customer-support chat. |
| DTO | Data Transfer Object — a plain class for API payloads (the :dto module). |
| VM | ViewModel — the screen’s state/logic; most extend NavigationBaseVM. |
| RSH | RemoteServiceHandler — wraps one API call and its loading/error state. |
| UAT | User Acceptance Testing — the dev/test environment & build type. |
| File | Is the… |
|---|---|
app/.../StcApplication.kt | Startup & SDK setup. |
app/.../MainActivity.kt | Single Activity & the NavHost. |
common/navigator/.../NavigationBaseVM.kt | Base ViewModel. |
common/navigator/.../StcScreens.kt | Routes & screens. |
.../screenStates/RemoteServiceHandler.kt | API call → UI state. |
network/.../NetworkResponse.kt | Network result type. |
gradle/libs.versions.toml | Every version. |
build-logic/convention/** | Build config & plugins. |
$ ./gradlew :app:assembleGmsUat # build the dev variant $ ./gradlew :app:installGmsUat # build + install on a device $ ./gradlew projects # list every module
gmsUat, and log in on UAT.onXxxNavigation().