Campaign P&L Engine
The campaign engine behind partner rewards at a leading Southeast Asian personal-finance platform: campaigns, gifts and partner-reported applications.
Watch the explainer: Campaign P&L Engine, 75 secondsWatch the 75-second narrated explainer. English captions on.Read the transcript
TL;DR
An event-sourced P&L and cost-reconciliation engine on Rails 8, with additive-only API contracts keyed on stable UUIDs.
01
Context
Profitability lived in spreadsheets, with no shared data model, no lifecycle and no reconciliation against what was actually paid out. And because a downstream operations platform consumed this engine's APIs, every contract decision had long-range consequences.
02
What I built
- A P&L subsystem from first principles: provider-reported applications, lump-sum monetising events and expiring forecasts, with transactional CSV ingestion and row-level error reporting.
- An incentive-cost reconciliation service: an event-sourced reactor books an approximate cost the moment a gift is issued, and an async job later reconciles it against actual purchase-order costs, with a feature-flag rollback path that got used.
- Claims lifecycle automation, including fixes for the race conditions that emerge when events arrive out of order.
- External API contracts designed additive-only, documented in OpenAPI in the same branch, always keyed on stable UUIDs rather than editable names.
- A Rails 8 and Ruby 3.4 upgrade delivered through staged rollouts with disciplined production reverts, plus a scheduled end-to-end regression suite with a documented scenario matrix.
03
Engineering judgment
API surface area was treated as a liability to be minimized: the default test for any new capability is the design that adds no new endpoints, no new auth scopes and no new routes. Contracts were designed additive-only against stable identifiers, which later allowed a parallel next-generation system to adopt them as its compatibility target.
04
Outcome
Campaign profitability became a queryable system instead of a spreadsheet ritual, and the engine's external contracts now anchor a downstream fulfilment platform and a next-generation campaign system.
05
Transcript
Read the 75-second explainer as text
Is this campaign actually profitable? Nobody could answer precisely. The numbers lived in spreadsheets, never reconciled against actual payouts.
The Campaign P&L Engine powers partner rewards at a leading Southeast Asian personal-finance platform. First, a P&L model: provider-reported applications, lump-sum monetising events, and expiring forecasts, loaded by transactional CSV ingestion, with row-level errors. The moment a gift is issued, an event-sourced reactor books an approximate cost. Later, an async job reconciles it against actual purchase-order costs, with a feature-flag rollback path that got used.
External contracts are additive-only, keyed on stable UUIDs, never editable names. So a next-generation system adopted them as its compatibility target. Rails 8, PostgreSQL, Rails Event Store, Kafka and Sidekiq, owned for 3 years. Profitability became a queryable system, not a spreadsheet ritual.
Approximate now. Reconciled later.