/dashboard/vip-intelligence screens — KPIs, client list, opportunities and
comparisons. Who counts as a VIP is defined per brand on
/dashboard/settings/vip-tiers, and every query in the module respects the
active definition.
The weighted-by-modality definition
Atlas uses a single definition model: weighted by modality (weighted_by_vertical). Casino and Sports are evaluated independently — a
player who qualifies in either modality is a VIP (OR semantics), and the
combined tier is the highest tier reached across both.
Anchored window
Metrics are computed over a per-player rolling window (30, 60, 90 or 180 days) anchored on the player’s last valid activity (any bet or approved deposit). A player whose anchor is older than 180 days leaves the VIP base entirely (staleness gate) — inactive players never linger in VIP lists.Weighted score per tier
Each modality defines tiers (e.g. Legend, Elite, Exclusive, Black) with a minimum band per metric, and a weight per metric (weights sum to 100%; weight 0 disables the metric):
For a tier
T, the score is Σ weight_i × (metric_i / band_i(T)) — no cap,
so an extreme metric can qualify on its own. The player lands on the highest
tier whose score reaches the qualifying cut. Sub-tiers reuse the same
weighted score against the sub-tier bands.
W/D adjustment (Sports second filter)
The W/D factor (wins ÷ window deposits; wins include returned stakes) rebalances Sports tiers after the base score: operators define contiguous W/D ranges, each contributing a score — a bad W/D demotes the tier, a good one sustains it. Players with no deposit in the window fall in the worst range. With W/D weight 0 the factor is inert (ranges stay editable in the UI).Definition history & audit
Every effective change to a brand’s VIP definition is recorded as an immutable version — visible in the Histórico e auditoria section of the VIP tiers screen, with the full before/after report and one-click restore.- Versions are numbered per brand (v1, v2, …); v1 is the definition in effect when auditing was enabled.
- A save that does not change the definition does not create a version.
- The recorded author is the operator’s session e-mail.
- Restore is append-only: restoring v2 creates a new version with v2’s
content, flagged
restored_from_version: 2— the trail is never rewritten.
GET /v1/vips/config/versions
Returns the organization-wide history (all brands), newest first, capped at
the 100 most recent entries.
is_current marks the version in effect for that brand. prev_definition is
absent on the initial seed version.
POST /v1/brands/{brand_id}/vips/config/versions/{version}/restore
Restores the brand’s definition to that version’s content, as a new
version, and returns the updated config (same shape as
PATCH /v1/brands/{brand_id}/vips/config).
Both endpoints require a dashboard session (API tokens are not accepted —
audit entries always carry a human author).
Simulation
Preview how a candidate (unsaved) definition would partition the real player base — powers the Simulação collapse in each modality of the VIP tiers screen. It runs against live windowed data without persisting anything.POST /v1/brands/{brand_id}/vips/simulate
Body: a full VIPDefinition (same shape as POST .../vips/count), typically the
values currently on the screen. Only weighted_by_vertical is supported
(400 vip_simulate_unsupported_mode otherwise); the definition is validated
before running (400 invalid_config).
Returns the base partitioned per tier, per modality:
base. vip_total is the union (a player VIP in both
modalities is counted once) — it is not casino.base + sport.base. No cache:
the result reflects the exact definition posted.
Where the data comes from
- Windowed metrics:
atlas.vw_vip_player_window(ClickHouse Gold, refreshed daily) — one row per player and anchor, with columns per window preset. - Lifetime universe and screens:
atlas.vw_vip_player_current. - Definition and version history: PostgreSQL (
vip_score_configs,vip_definition_versions) — the backend is the single write path.