Перейти до основного вмісту

Frequency capping + quiet hours

Translator note: machine-translated baseline. Needs human review by a native UK speaker. EN source is canonical.

Два policy gates, через які кожен send (campaign / journey / manual) проходить перед тим, як hit provider.

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 counts existing message_sends rows per (player, channel, rolling_window) — only counts rows у (queued, sending, sent, delivered, opened, clicked, bounced) статусі. Suppressed rows (SKIPPED_*) не count toward cap (otherwise cumulative misses would lock you out).

When campaign batch fan-outs, cap check runs as SQL filter directly у segment query — capped гравці never enter batch + не отримують message_sends row at all.

Для journey send_message + manual sends (single-player), checkMessagingPolicies() returns first breached 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 (якщо set) → quiet_hours.default_timezoneUTC. Wrap-around supported (start=22:00 end=09:00 = quiet from 22:00 to 09:00 next day).

Implementation uses Intl.DateTimeFormat з timeZone option для DST-aware local-clock conversion.

When campaign sends to гравцеві у його quiet window, casinocrm.io doesn't drop message — inserts row з status=failed + error_code=SKIPPED_QUIET_HOURS, so campaign stats panel shows suppression. Operator може re-target on next campaign run.

Test sends bypass

checkMessagingPolicies({ bypass: true }) skips both checks. Admin "Send test" button uses bypass так operators can test their template without fighting their own policies.

Audit trail

Кожна suppression writes reason у 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) shows them so operators can debug.