Gamification Platform – Phase 1 HLD

1. Summary

The gamification platform is an event-driven runtime for reward-bearing customer journeys that must not sit on the payments critical path. It consumes events, evaluates eligibility, progresses users through linear milestone journeys, and orchestrates NeuCoin/voucher rewards asynchronously. PostgreSQL is the authoritative store; Redis holds projection caches; Confluent Cloud Kafka is the streaming platform.

Phase 1 delivers a JSON-configured, count-based milestone game using a single archetype NUMERIC_COUNTER. UPI and FS events both drive the same numeric counter via config-defined triggers. The design keeps the hot path short and deterministic, while the config and event models are extensible to future gamification archetypes (amount, category, checklist, streak, daily grid).


2. Scope and Non-Goals

2.1 In Scope (Phase 1)

2.2 Explicit Non-Goals (Phase 1)


3. Architecture Overview

[Diagram]

3.1 System Architecture

The system consists of four main layers:

External Systems:

Event Streaming:

Gamification Runtime:

Data Layer:

Client:

Key decisions:


4. Config Model (JSON-Driven)

Note: DB schemas are WIP and will be derived from these JSON models; JSON is the primary configuration contract.

4.1 Game Config Schema – Phase 1

Top-level fields:

4.1.1 Example: UPI + FS Milestone Game

{
  "schema_version": "1.0",
  "game_id": "upi_fs_milestone_may_2026",
  "game_archetype": "NUMERIC_COUNTER",

  "cohort_id": "viduur_segment_upi_fs_early_lifecycle",

  "game_window": {
    "start": "2026-05-01T00:00:00Z",
    "end": "2026-05-31T23:59:59Z",
    "type": "monthly"
  },

  // this would vary per game archetype in future
  // mapped to each game strategy (numeric counter for now)
  "progress_state_model": {
    "type": "numeric_counter",
    "unit": "count",
    "display_unit": "transactions",
    "max_value": 12
  },

  "milestone_steps": [
    { "step": 3,  "step_type": "REWARD",
      "reward": {
        "reward_type": "NC",
        "value": 10,
        "visibility": "visible",
        "display_type": "flat"
      }
    },
    { "step": 6,  "step_type": "REWARD",
      "reward": {
        "reward_type": "NC",
        "value": 30,
        "visibility": "hidden",
        "display_type": "upto"
      }
    },
    { "step": 12, "step_type": "REWARD",
      "reward": {
        "reward_type": "NC",
        "value": 100,
        "visibility": "visible",
        "display_type": "flat"
      }
    }
  ],

  "triggers": [
    {
      "trigger_id": "upi_plus_one",
      "event_type": "payment_success",
      "rule": {
        "operator": "and",
        "conditions": [
          { "field": "attributes.payment_status", "op": "eq", "value": "SUCCESS" },
          { "field": "attributes.transaction_type", "op": "eq", "value": "UPI" },
          { "field": "attributes.transaction_amount", "op": "gte", "value": 1200 }
        ]
      },
      "progression_config": {
        "mode": "increment_by_constant",
        "value": 1
      }
    },
    {
      "trigger_id": "fs_plus_three",
      "event_type": "fs_action_complete",
      "rule": {
        "operator": "and",
        "conditions": [
          { "field": "attributes.action_type", "op": "eq", "value": "CREDIT_CARD_APPLY" }
        ]
      },
      "progression_config": {
        // this config will vary for future games to increment by attribute fields such as .attributes.txn_amount
        "mode": "increment_by_constant",
        "value": 3
      }
    }
  ]
}

FS cross-sell is just another trigger (higher value) on FS events, not a separate skip/config block. This scales naturally to more FS actions or other event types.

4.2 Config Validation and Versioning


5. Event Model and Normalisation

5.1 Normalisation Layer

The Normalisation Layer:

5.2 Normalised Events (Phase 1)

5.2.1 UPI Payment

{
  "event_id": "evt_pay_001",
  "event_type": "payment_success",
  "event_version": "1.0",
  "occurred_at": "2026-06-10T11:05:00+05:30",
  "producer": "payments",
  "user_id": "U123",
  "correlation": {
    "payment_id": "pay_123",
    "txn_id": "txn_123", // FS correlation?
    "canonical_transaction_id": "txn_123",
    "original_event_id": null // FS correlation?
  },
  "attributes": {
    "transaction_type": "UPI",
    "payment_status": "SUCCESS",
    "transaction_amount": 25000,
    "currency": "INR",
    "merchant_id": "m_001",
    "merchant_category": "UTILITY",
    "action_type": null
  }
}

Future games leverage the same attributes.* space (e.g., merchant_category, billpay_category) in their triggers, giving us config-only extensibility.


6. Runtime Flows

6.1 Forward Write Path

[Diagram]

Sequence:

  1. Producer (PAY/FS) publishes event to Kafka
  2. Event Consumer receives event from Kafka
  3. Consumer calls LaunchDarkly for event-time eligibility check using cohort_id
  4. If ineligible: drop event (no state mutation)
  5. If eligible:
    • Consumer invokes Normalisation Layer
    • Normalisation Layer returns canonical event
    • Consumer passes canonical event to Game Engine
  6. Game Engine begins PostgreSQL transaction:
    • Load user_game_counter for game_id
    • If no enrollment: rollback and return SKIP_NO_ENROLLMENT
    • If enrolled:
      • Insert into processed_events(event_id,...)
      • If duplicate event_id: rollback (unique violation)
      • If new event:
        • Evaluate triggers[] for this event
        • Apply NumericCounterStrategy (increment by sum of deltas)
        • Evaluate milestone_steps and create reward_entitlement rows
        • Commit transaction
  7. Engine invalidates projection cache in Redis for user/game
  8. Engine notifies Reward Orchestrator of pending entitlements (async)

Evaluation scope: Phase 1 uses INBOUNDEVENT evaluation only; no logical-transaction correlation is applied. Trigger stacking (multiple triggers on the same event) is supported via mode: ADDITIVE but is not required for UPI+FS Phase 1.


7. Data and State Model

7.1 State Ownership

7.2 Storage Strategy

7.3 Archival Strategy

7.4 Canonical Event Structure

{
  "event_id": "evt_001",
  "event_type": "payment_success",
  "event_version": "1.0",
  "occurred_at": "2026-06-10T11:05:00+05:30",
  "producer": "payments",
  "user_id": "U123",
  "correlation": {
    "payment_id": "pay_123",
    "txn_id": "txn_123",
    "original_event_id": null
  },
  "attributes": {
    "transaction_type": "UPI",
    "payment_status": "SUCCESS",
    "transaction_amount": 25000,
    "currency": "INR",
    "merchant_id": "m_001",
    "merchant_category": "GROCERY",
    "billpay_category": null,
    "action_type": null,
    "frm_flag": null
  }
}

8. Read Path & UX

8.1 BFF Read Path

Homepage widgetGET /api/games/active

Game JourneyGET /api/games/{game_id}

History/supportGET /api/games/{game_id}/history

BFF pattern:

  1. App calls BFF endpoint (GET /api/games/active)
  2. BFF checks Redis for projection:dashboard:{user_id}
  3. If cache hit: return projection
  4. If cache miss:
    • BFF queries PostgreSQL (user_game_counter, reward_entitlement)
    • BFF assembles DTO
    • BFF sets projection in Redis with TTL
    • Return response to App

8.2 Frontend Responsibilities

8.3 Post-Transaction Screen Behaviour (WIP – UX Dependent)

The write path is fully event-driven, so the engine does not expose a synchronous mutation API for post-transaction screens. UX will choose one of two patterns, to be finalised based on approved Figma flows:

1. Optimistic post-transaction UI (preferred where safe)

2. Authoritative but delayed UI (fallback)

this is work in progress and will be finalised once UX figmas are signed off; architecture supports both patterns without additional backend components.

[Diagram]

9. Extensibility

Although Phase 1 is limited to UPI + FS and a linear milestone game, the architecture generalises cleanly:

New progress drivers – commerce orders, app opens, and other events can be onboarded by:

New archetypes – checklist, streak, and calendar grid games can be implemented as additional strategies behind the same engine contract, with corresponding config extensions (e.g., per-category targets, streak windows).

New progression modes – amount-based, weighted, uniqueness-based are already part of the NUMERIC_COUNTER design and only require additional progression_config enums and strategy logic, not new infrastructure. In case of newer archetypes such as streaks, calendar based games, etc are introduced, we introduce new Game Strategy plugin to handle such games.

Admin UI – A future admin/config portal can sit on top of the JSON validation and activation APIs without changing the runtime responsibilities.


10. Risks and Open Items

1. UPI + FS double-dipping (same logical transaction)

2. FRM integration undefined

3. Clawback/reversal strategy undefined

4. Normalisation layer deployment shape

5. DB schema details are WIP


TLDR

[Diagram]