Přeskočit na hlavní obsah

Frequency capping + quiet hours

Dvě policy gates, kterými každý send (campaign / journey / manuální) projde, než narazí na providera.

Frequency capping

Per-tenant config:

{
"messaging": {
"frequency_caps": {
"email": { "per_day": 1, "per_week": 5 },
"sms": { "per_day": 1, "per_week": 3 },
"push": { "per_day": 3, "per_week": 14 }
}
}
}

Cap query počítá existující message_sends řádky per (player, channel, rolling_window) — počítá jen řádky ve statusu (queued, sending, sent, delivered, opened, clicked, bounced). Suppressed řádky (SKIPPED_*) nepočítají do capu (jinak by kumulativní misses uzamkly).

Když campaign batch fan-outne, cap check běží jako SQL filter přímo v segment query — capped hráči nikdy nevstoupí do batche + nedostanou message_sends řádek vůbec.

Pro journey send_message + manuální sends (single-player) checkMessagingPolicies() vrátí první porušený cap.

Quiet hours

Per-tenant config + per-player players.timezone:

{
"messaging": {
"quiet_hours": {
"start": "22:00",
"end": "09:00",
"default_timezone": "Europe/Prague"
}
}
}

Effective timezone resolution: players.timezone (pokud nastaveno) → quiet_hours.default_timezoneUTC. Wrap-around podporován (start=22:00 end=09:00 = quiet od 22:00 do 09:00 dalšího dne).

Implementace používá Intl.DateTimeFormat s timeZone opcí pro DST-aware local-clock konverzi.

Když campaign pošle hráči v jeho quiet okně, casinocrm.io zprávu nedropne — vloží řádek se status=failed + error_code=SKIPPED_QUIET_HOURS, takže campaign stats panel zobrazí suppression. Operátor může re-targetnout v dalším campaign runu.

Test sends bypass

checkMessagingPolicies({ bypass: true }) přeskočí oba checky. Admin "Send test" tlačítko používá bypass, takže operátoři mohou testovat svůj template bez boje s vlastními politikami.

Audit trail

Každá suppression zapíše důvod do message_sends.error_message:

"player in quiet-hours window (Europe/Prague)"
"player has no email for channel email"
"frequency cap email per_day=1 reached"

Recipients list (GET /v1/campaigns/:id/recipients?status=failed) je zobrazí, takže operátoři mohou debugovat.