Přeskočit na hlavní obsah

A/B testing + conversion goals

Per-campaign N variant s deterministickým per-player přiřazením + conversion attribution proti libovolné kanonické události.

Variants

Každá campaign má 1..N řádků v campaign_variants:

{
"name": "Variant A",
"label": "A", // krátký badge label
"template_id": "...", // operátor klonuje template, tweakuje copy
"weight": 50, // relativní váha 0..10000
"sort_order": 0
}

Weights nemusí součtem dát 100 — assignment normalizuje podle total. Dvě varianty s weight=1 každá = 50/50 split. Jedna 70, druhá 30 = 70/30.

Deterministické přiřazení

bucket = FNV1a32(`${campaign_id}|${player_id}`) mod sum_weights
variant = první variant kde cumulative_weight > bucket

Stejný hráč na stejné campaign vždy spadne do stejné varianty — i napříč re-sends. Brání variant-drift attribution mud.

Stejný hráč na různých campaigních může spadnout do různých variant (campaign_id mění hash input).

Conversion goals

// Na campaign:
{
"goal_event": "deposit_confirmed", // kanonická event name
"goal_attribution_days": 7, // 1..90
"goal_value_property": "amount_base" // jsonpath pro revenue attribution
}

GET /v1/campaigns/:id/conversion-stats joinuje message_sends (PG) s raw_events (CH):

  • Pro každého hráče, který dostal zprávu v (sent | delivered | opened | clicked) statusu,
  • Najde nejranější goal_event v [sent_at, sent_at + attribution_days * 24h)
  • Grupuje podle variant_id → count + value sum

Nejranější protože hráč může goal udělat víckrát — kreditujeme JEDNU konverzi per hráč per campaign.

Stats response

{
"campaign_id": "...",
"goal_event": "deposit_confirmed",
"goal_attribution_days": 7,
"total_recipients": 3085,
"total_conversions": 151,
"variants": [
{
"variant_id": "...",
"variant_name": "Variant A",
"variant_label": "A",
"recipients": 1547,
"conversions": 87,
"conversion_rate": 0.0563,
"conversion_value": 870000 // sum v base měně tenanta v centech
},
{
"variant_id": "...",
"variant_name": "Variant B",
"variant_label": "B",
"recipients": 1538,
"conversions": 64,
"conversion_rate": 0.0416,
"conversion_value": 640000
}
],
"winner_variant_id": "...A's id"
}

Winner picker

Variant je deklarován vítězem, když:

  1. nejvyšší conversion rate mezi všemi variantami
  2. Jeho recipients count je ≥ 30 (zabrání deklaraci vítězů na šumu)
  3. Tie-break: nejvyšší recipient count (víc důvěry) → první podle sort_order

Pod 30 sample size je winner_variant_id null, dokud se nenahromadí víc sends.

Mid-campaign weight changes

Operátoři mohou editovat weights mid-campaign — jen nové sends respektují nový split. Už-zařazené message_sends drží svůj přiřazený variant_id, takže conversion attribution zůstane čisté.