Skip to content

feat(analytics): catalogue boosts, payment requests and Sent Cash context - #1890

Merged
bmc08gt merged 3 commits into
code/cashfrom
feat/analytics-money-flow
Oct 30, 2026
Merged

bmc08gt merged 3 commits into
code/cashfrom
feat/analytics-money-flow

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Three money movements send nothing useful to Mixpanel today, on either app (section 2 of the 2026-10-29 analytics audit):

  • Boosts (paid reactions) move money and have no event, the only transfer without one.
  • Group payment requests have no create or close event. On iOS, paying a share sends Sent Cash with nothing marking it as a request payment. Android sends nothing when a share is paid.
  • Group sends reach Mixpanel as Sent Cash with the total only, so a send to 5 members looks like a send to 1.

This PR adds the catalogue entries and wires Android to send them ("As wired"). It stays draft until iOS is wired.

Entries

Event Fires when Records
Sent Cash (existing) Cash is sent or a request share is paid New optional Context (Direct, Group Send, Payment Request, new list SendContext) and optional Recipient Count (count, Group Send only)
Sent Boost (Transfer) A boost is confirmed, on success or failure Chat Type (existing ChatType list), State, amount (whole boost, before the split), Error
Payment Request: Created (new domain) A request is created, on success or failure Payer Count (people asked, creator excluded), State, amount (per person), Error
Payment Request: Closed The creator closes a request early, on success or failure State, Error
  • Sent Cash had no equivalent of Context or Recipient Count.
  • Sent Boost sits in Transfer next to Sent Tip and Sent Cash and uses the outcome group like them. Amount is the same amount group.
  • Paying a request is Sent Cash with Context = Payment Request, not a new event.
  • A request that ends at its deadline fires nothing, since the user did nothing.

Adding properties to Sent Cash changes the generated TransferEvents.sentCash signature (the builders have no defaults); every Android call site now passes Context and Recipient Count. iOS gets the new signature only after the next Publish SharedCore release.

As wired

All under apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/, sent through FlipcashAnalytics.track.

Event Android function Moment
Sent Cash, Context = Direct currencysend/CurrencySendViewModel.kt (send result); ChatViewModel.kt sent (non-cash-link branch); payment/StartChattingPayer.kt sent (TipAction.SEND) After the payment result, as before. Success inside holdPaymentSuccess's release where it was already there
Sent Cash, Context = Group Send, Recipient Count = groupSend.selected.size ChatViewModel.sendToMembers Success in release after the success hold, failure immediately
Sent Cash, Context = Payment Request request/RequestPayFlow.kt: confirm (success) and afterFailedPayment (failure). Covers RequestPayViewModel and RequestDetailsViewModel Success in release, after the success hold. Failure before the refetch, so a failed pay is counted even when the refetch finds the share paid or the request closed. Nothing on the balance and send-limit blocks before payments.pay. Amount is the share
Sent Boost screens/boost/ReactionBoostViewModel.boost On the result of payer.boost, success before the 600 ms hold. A failure that is StartChattingPayer.PaymentBlocked (below minimum, balance, send limit, no account, self boost) sends nothing. Amount is centsToUsd(selectedCents), the whole boost
Payment Request: Created request/RequestMoneyViewModel.send and failed Success right after requests.create returns, before sendPaymentRequest, so a message that fails to send still counts. Failure in failed(), which also covers the seal and draft errors that precede create. A retry that reuses createdRequestId sends nothing. Payer Count = draft.requestedCount, amount draft.perPerson
Payment Request: Closed request/RequestDetailsViewModel.close On the requests.close result, wrapped inside close() so markPaid is unaffected. Not on askClose

Differences from the plan above: Chat Type on Sent Boost is metadata?.type?.analytics, falling back to Unknown, because metadata is nullable and ChatType.analytics is not. RequestPayFlow, RequestMoneyViewModel, RequestDetailsViewModel, RequestPayViewModel and ReactionBoostViewModel each take an injected FlipcashAnalytics. The events.toml entries needed no change.

Judgment calls

  • Created and Closed carry State and Error, like Group: Created, so failed creates and closes are countable. Say if you want success-only.
  • Sent Cash.Context is optional, so the existing sends keep working until they are wired. Once all sites send it, it could become required.
  • Sent Boost follows Sent Tip in Transfer and has no Context. A boost is its own event because the user's action differs from sending cash.

Sent Cash now carries Context at every call site (Direct, Group Send with
Recipient Count, Payment Request), and paying a request share sends it for
the first time on Android. Sent Boost, Payment Request: Created and
Payment Request: Closed are sent on the result of the call they describe.
… is absent

Optional builder params now default to null, so the call sites and tests no longer pass null for Recipient Count. Also disambiguate the ResourceHelper.getString mocks in RequestMoneyAnalyticsTest.
@bmc08gt
bmc08gt force-pushed the feat/analytics-money-flow branch from f85bc3d to 01f0105 Compare October 30, 2026 04:49
@bmc08gt
bmc08gt marked this pull request as ready for review October 30, 2026 05:13
@bmc08gt
bmc08gt merged commit 6fdad9a into code/cash Oct 30, 2026
6 checks passed
@bmc08gt
bmc08gt deleted the feat/analytics-money-flow branch October 30, 2026 05:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant