07EXPERIMENTALEXPLORATION2024

Offline Payment Relay

Product lab

An experiment in resilient device-to-device payment workflows for unreliable connectivity.

The problem

A merchant with unreliable connectivity still needs to keep selling — but most payment flows assume the network is there at the exact moment of the sale.

The interesting question isn’t “can two phones talk offline” (they can); it’s whether transaction information can be exchanged between nearby devices with enough integrity that both sides hold a trustworthy record to reconcile later — without ever pretending that money actually moved.

The approach

MerchantOS is a Flutter prototype that lets a merchant device and a customer device exchange a cryptographically signed promise-to-pay over Bluetooth Low Energy, with QR codes as a full-fidelity fallback. Each side signs with a device-held Ed25519 key; both sides store immutable, matched receipts in their own local SQLite ledger.

The boundary is explicit in code and UI alike: exchanging transaction data offline is not completing an authorized payment offline. Settlement in this build is a local simulator, the wallet is labeled simulated on screen, and a licensed payment partner exists only as an interface awaiting a real integration.

My role — Product thinking, mobile architecture and offline workflow exploration. No official UPI or financial-network integration is claimed.

FlutterRiverpodClean ArchitectureDrift / SQLiteBLEQR

How it works, step by step

Offline exchange — signed data, not money

The implemented device-to-device flow. Amounts and identities are dummy values.

MerchantMerchantOSmerchant deviceBLE / QR exchangesame payload, twotransportsMerchantOScustomer deviceMerchant ledgerSQLite · append-onlyCustomer ledgerSQLite · append-onlyLicensed payment partnerfuture integration pointPLANNED

01Merchant creates the transaction

The merchant enters an amount. The transaction is recorded locally first — if nothing else happens, there’s still a truthful record that it was offered.

Select any node in the diagram to inspect it.

Person
This project
Internal layer
Connected system
Data at rest
Planned (not built yet)
Success
Info
Pending

Example output

Transaction certainty — the state ladder

Recorded
exists on this device
Exchanged
signed by both devices, receipts match
Authorized offline
settlement pending — no money moved
Simulated settlement
local simulator only, labeled in the UI
Real settlement
planned — requires a licensed partner

The product’s own vocabulary, shown with dummy states. Each rung is a different level of certainty, and the UI never blurs them.

Architecture

Architecture

Offline-first taken literally: in this build, nothing has a network to talk to.

Flutter UIpresentationApplication layerRiverpod providersDomainentities · Result<T>Data layerrepositoriesDrift / SQLite21 tablesBLE GATT · QRtransportSecure storageEd25519 seed · PINEncrypted backupAES-256-GCM containerSync queueinterfaces onlyPLANNED
Connected system
Internal layer
This project
Data at rest
Planned (not built yet)
Connected system
Internal layer
This project
Data at rest
Planned (not built yet)

Strict clean-architecture layering per feature (presentation → application → domain → data), enforced by project convention and ADRs. NFC exists only as a token-codec stub with no radio; it hands off to BLE discovery.

Key engineering decisions

  • Offline-first state
  • BLE exchange
  • QR fallback
  • Reconciliation model
  • Device-to-device workflow

Switch to the technical view for the engineering trade-offs behind these.

Challenges & limitations

  • No real UPI, NPCI, bank or PSP integration — settlement is a local simulator, labeled as such in the UI, and a licensed partner is an empty interface awaiting a real integration.
  • This build has no network client at all: “reconcile once online” is a designed seam (interfaces + a local sync-event trail), not working sync.
  • BLE is implemented and its message framing is unit-tested, but it has not been through physical-device acceptance — the project’s own release review says “not ready for pilot,” and this page agrees with it.
  • A device-reset / recovery flow does not exist; local encrypted backup and restore do.

What I learned

Offline UX is honesty engineering. Recorded, exchanged, authorized and settled are four different certainties, and the product only stays trustworthy if every screen — and every diagram — refuses to round one up to the next.

Project status

Prototype — experimental build

259 passing tests, clean static analysis and CI-built debug artifacts, with the project’s own production-acceptance review honestly concluding “not ready for pilot”: no signed release binaries and no physical-device BLE acceptance yet.