Home About Skills Experience Projects Certifications GitHub ↗ Hire me
← Back to Portfolio
Tuwaiq Pay icon
Featured Project · Fintech · iOS & Android · Saudi Market · Sep 2025 – Sep 2026

Tuwaiq Pay

Overview

Tuwaiq Pay is a production fintech app used by real merchants across Saudi Arabia to manage invoicing, accept in-person and card payments, and track transactions. I owned the mobile stack end to end — from the Clean Architecture foundation to the pipeline that ships builds to the App Store and Google Play.

The app integrates three payment providers (NearPay NFC tap-to-pay, HyperPay, and Geidea) behind a single interface, so merchants can accept payments however their customers pay, without the app ever feeling like three different apps stitched together.

3Payment providers unified behind one interface
LiveShipping on both App Store & Google Play
AR / ENFull bilingual merchant experience
Core Capabilities

What the app does

💳
Multi-provider payments

NearPay NFC tap-to-pay, HyperPay card payments, and Geidea, each wrapped behind a shared Strategy interface so the UI never branches on provider.

🔐
Biometric & secure auth

Face ID / fingerprint login layered on top of token-based session handling, with a dedicated auth gate in the router.

🧾
Sub-accounts

Merchants can create and manage sub-accounts with their own OTP verification, permissions, and status controls.

🚩
Remote feature flags

Firebase Remote Config drives kill-switches and gradual rollouts (e.g. disabling NearPay instantly if a provider has an outage).

🌍
Arabic / English

Every screen, error message, and NFC failure reason is localized with easy_localization.

🚀
CI/CD to both stores

GitHub Actions + Fastlane build, sign, and ship Dev/UAT/Prod flavors to Firebase App Distribution and TestFlight automatically.

Architecture

How it's built

The app is split into clear data / domain / presentation layers, with Riverpod (codegen + freezed state) managing everything above the repository boundary. Three build flavors — Dev, UAT, and Prod — each point at their own Firebase project, so a bug in staging can never leak into a merchant's production data. Routing uses go_router with typed routes and a splash/auth gate that decides where a cold-started user lands before any screen renders.

Presentation (Riverpod)→Domain (Use Cases)→Repository Interface→Data (Dio + DTOs)→NearPay / HyperPay / Geidea SDKs
Walkthrough

See it in action

Tuwaiq Pay Screenshots Banner
Select Payment Methods
Select Payment Methods
Payment Links & Invoices
Payment Links & Invoices
Manage Sub-Accounts
Manage Sub-Accounts
Manage Bank Accounts
Manage Bank Accounts
Refunds
Refunds
Transactions
Transactions
Business Registration
Business Registration
Problems Solved

Real engineering challenges

Strategy Pattern
Adding a third payment provider without a third UI

When Geidea joined NearPay and HyperPay as a bill payment option, I refactored the provider-specific logic into GeideaBillStrategy, HyperPayBillStrategy, and NearPayBillStrategy classes behind one interface — new providers plug in without touching a single screen.

Remote Config
Stale cache & a race condition on cold start

Firebase Remote Config was occasionally serving stale flags right after app launch. Fixed the fetch/activate sequencing so the app never reads a flag before the first successful config fetch resolves.

App Store Review
Rejection over tracking disclosure

The app was rejected over missing NSUserTrackingUsageDescription / ATT handling for IDFA. Added the proper permission prompt and usage string, and the resubmission passed review.

Android 16KB pages
Play Store's new memory page-size requirement

Newer Android devices require 16KB memory page size compliance. Resolved it via useLegacyPackaging configuration in the Android build rather than waiting on every native dependency to update.

R8 / ProGuard
A feature flag that vanished only in release builds

A production feature was invisible only in release APKs — R8 was tree-shaking code the release build thought was unused. Traced it to over-aggressive shrinking and shipped a --no-shrink workaround while a proper keep-rule was rolled out.

Technologies Employed

Built with

FlutterRiverpodClean ArchitectureNearPay SDKHyperPayGeideaFreezedGoRouterFirebase Remote ConfigDioGitHub ActionsFastlane
Screenshot preview