GH GambleHub

Content catalog engine

The catalog engine is the core of game showcases and promo collections at the front: it collects and normalizes metadata from providers (RGS), provides search/filters/ranking, applies accessibility rules by jurisdiction and brand, mixes personalization and promo placements, and then delivers quick responses via API with predictable SLO.

1) Goals and principles

Fast reads: p95 ≤ 100-150 ms per directory/search request.
Truth and freshness: guaranteed relevance of key attributes (availability, jackpots, provider statuses).
Flexibility: editorial collections and promo slots without releases.
Compliance: geo/age/content rules, licenses, responsible play restrictions.
Multi-tenant/region: brand isolation and data residency compliance.
Observability: Outing Quality Metrics, A/B, Game Conversion/Bet.

2) Domain model (minimum)

Entities:
  • Game is a game/product of the provider.
  • Provider - RGS/studio.
  • Variant - variants of one game (volatility, lines, limits, server).
  • Collection - editorial/automatic selection (e.g. "New Items," "Jackpots").
  • Placement - fixed position/banner/tile on the page/in the slot.
  • Capability/Feature - game attributes (free spins, buy feature, jackpot).
  • JurisdictionRule - accessibility/restriction rules.
  • Signals - behavioral/operational signals (popularity, CTR, revenue).
  • Asset - media (icons, posters, demo videos) with options for devices/densities.

Keys: 'game _ id' (stable internal, not equal to provider_game_id), 'tenant _ id', 'region', 'locale'.

3) Ingest and normalization

Conveyor:

1. Source Adapters (pullers): integrations with RGS/studios (directories, features, RTP, tags).

2. Sanitize & Map - Map external fields into a single dictionary (ACL), validate, and deduplicate.

3. Enrich: localizations, categories, semantic tags, age limit ratings.

4. Moderate: content flags (NSFW/religious symbols/sensitive topics) by market.

5. Publish: 'GameUpserted/ProviderStatusChanged' events → catalog projection.

Idempotence: all messages with 'source _ id' + 'version _ ts'; repeat is processed without side effects.
Evolution scheme: 'schema _ version' in adapters + mapper migrations.

4) Normalized scheme (simplified)

json
{
"game_id": "g_3f92",
"tenant_id": "brand_eu",
"provider": { "id": "pr_evolution", "name": "Evolution" },
"title": { "en": "Lightning Roulette", "de": "Lightning Roulette" },
"capabilities": ["live","roulette","multiplier","bonus"],
"rtp": 97. 3,
"volatility": "high",
"limits": { "min": 0. 1, "max": 1000. 0, "currency": "EUR" },
"jurisdiction": {
"allowed": ["MT","EE","DE"],
"blocked": ["NL","BE"],
"age_rating": 21
},
"assets": {
"tile": { "1x":"...", "2x":"..." },
"poster": { "web":"...", "mobile":"..." }
},
"tags": ["new","jackpot"],
"release_date": "2025-09-12",
"status": "active",
"variants": [{ "id":"v1","server":"eu-central-1","rtp":97. 3 }]
}

5) Search, filters, facets

Indexes: full text by name/synonyms, facets by 'provider', 'capabilities', 'volatility', 'rtp _ bucket', 'tags'.
Filters: jurisdiction/region/language/device/age, active/certified only.
Synonyms/stemming: a map of user terms ("books," "fruits," "balls").
Typos: tolerant search (edit distance ≤1 -2) with length restriction.

6) Ranking: signals and formula

Signals (example):
  • Freshness (time since release).
  • Population (starts/hour, unique players).
  • Quality (CTR from catalog to game, hold 1/7 day).
  • Business (marketing boosts, deals, promotional slots).
  • Compliance (soft downgrades for sensitive content, if required).
  • Player-fit (profile/preference compatibility).
Combination (concept):

score = w1freshness + w2popularity + w3ctr + w4player_fit + w5boost

Weights are controlled by configuration/experiments; all signals normalized to [0; 1].

7) Personalization

Short memory: recent launches and genres, RYW - the user immediately sees fresh action.
Long memory: Game and player profile embeddings (game genres/volatility/sessions).
Security: Personalization never violates jurisdictional/age rules.
Fallback: if there are few signals - neutral ranking + editorial collections.

8) Collections and promotional placements

Collections:
  • Auto: rule/query (e.g. 'capabilities contains' jackpot 'AND release_date> = NOW () -30d').
  • Editorial: manual list with order and timing.
  • Placements: fixed positions on pages (hero, row-1-slot-3), A/B, targeting by segment/jurisdiction.
  • Dates and priorities: 'starts _ at/ends _ at', collision priority, preview before publication.

9) Compliance and Accessibility Policy

Geo/jurisdiction: white/black lists of countries/regions, verification of licenses/certificates.
Age rating: minimum age, warnings, hiding for incompatible markets.
Subject/symbolism: flags of sensitive content by country (religion, alcohol, etc.).
Responsible play: Hide/demote for limit/timeout players.
Audit: immutable log of changes in availability with reasons.

10) Multi-tenant and multi-region

All data is marked 'tenant _ id' and 'region'.
Isolation: quorums/vaults by region; cross-regional projections - aggregates only.
Fairness: quotas for ingest/publications per tenant so that the "noisy" brand does not delay the rest.

11) Architectural outline

Write-core directory (CP): normalization + transactional outbox events.
Projections/Read Models (EC): search indices, materialized collections, popularity counters.

Cache layers:
  • Edge/CDN for cold pages/images.
  • In-memory caches for hot queries (key = filters + page + tenant + region).
  • Ficheflags: rolling ranking/collection rules without release.

12) API (REST/GraphQL, examples)

REST


GET /v1/catalog? tenant=brand_eu&region=EE&locale=ru
&filter=jackpot,true&sort=score_desc&page=1&size=24
→ 200 { items:[...], facets:{...}, as_of:"2025-10-31T12:10:02Z" }

GraphQL (fragment)

graphql query Catalog($tenant:String!,$region:String!,$q:String,$filters:Filters){
catalog(tenant:$tenant, region:$region, q:$q, filters:$filters){
items { gameId title provider { name } score badges assets { tile } }
facets { providers { key,count } capabilities { key,count } }
freshnessMs
}
}
Contracts:
  • Always return 'as _ of/freshnessMs', paging, facets.
  • For personalization - session marker (RYW) without PII.

13) Signals and data flow

Popularity: increments when launching games → minute buckets → units in projection.
CTR/conversion: Click/launch counters on placements/collections.
Operating statuses: health providers (RGS), jackpots/limits (event stream).
Marketing boosts: time factors for games/categories/suppliers.

14) Observability and SLO

Directory metrics:
  • `catalog_p95_ms`, `catalog_p99_ms`, `error_rate`.
  • 'index _ freshness _ ms' (project delay), 'ingest _ lag _ ms'.
  • 'ctr ',' click-to-launch ',' collection _ coverage '(% check out from collections).
Personalization:
  • `lift_ctr`, `lift_conversion`, «explore vs exploit» доля.
Compliance:
  • % correctly applied geo/age rules, number of blocks/hour.

Alerts: growth of'ingest _ lag _ ms', drop in CTR on key collections, degradation of the provider (tags in the issue).

15) Performance and caching

Strategy: hot queries - cache for 30-120 s with a key by filters; personal blocks - short TTL (10-30 s) or no cache.
Disability: By 'GameUpserted/AvailabilityChanged/PlacementUpdated' events.
Pagination: stable cursors so as not to "jump" cards when updating signals.

16) Working with media

Render profiles: sizes/densities for web/mobile/TV.
Optimization: WebP/AVIF, lazy-load, sprite/atlas for tiles.
Content security: scanning, watermarks, inline-PII prohibition.

17) Testing

Contract/Schema tests for adapters and APIs.
Relevancy tests: golden sets of queries → expected results/order.
Personalization: offline AUC/NDCG + online A/B with guardrail metrics (in-game time, deposits, RG signals).
Chaos: provider degradation, ingest spikes, indexing delays.

18) Playbooks (runbooks)

1. Index lag> SLO: stop secondary collections, increase the priority of ingest, temporarily simplify ranking.
2. Provider "red": lower/hide his games, raise alternative collections.
3. API error jump: check cache/backend, enable security timeouts, reduce page size.
4. Incorrect availability: roll back the last rule, include a "white list" of critical markets, audit changes.
5. Ranking release: canary rollout (5% → 25% → 50% → 100%), CTR/conversion rollback.

19) Typical errors

Mixing external provider schemas with an internal model (no ACL).
The absence of'as _ of/freshness' → disputes about the "outdated" directory.
Personalization that violates jurisdictional rules.
The only "magic" ranking formula without decomposition of signals and A/B.

Large pages without caching and cursors → p99 "shoot."

Dual-write to index and OLTP instead of events + projections.

20) Pre-sale checklist

  • Normalized field dictionary and ACL for all providers.
  • Idempotent ingest, outbox/inbox, DLQ and redrive.
  • Catalog projections and search indices with freshness SLO.
  • Weight-controlled ranking, signal decomposition and A/B.
  • Compliance rules (geo/age/topic) and audit of changes.
  • Multi-tenant/region: data isolation, fairness, residency.
  • API with'as _ of ', facets, cursors; cache and disability by event.
  • p95/p99 metrics, ingest/indexing, CTR/conversion; alerts.
  • Incident playbooks; canary releases and ficheflags.
  • Tests of relevance, contracts, chaos and personalization.

Conclusion

The catalog engine is a "search engine + rule system + showcase" over game content. Strong ACL, normalized data, projections for quick reads, transparent ranking signals, personalization with guardrail metrics and strict compliance turn the catalog into a sustainable and measurable product lever of growth - without surprises in production and without compromises with regulators.

Contact

Get in Touch

Reach out with any questions or support needs.We are always ready to help!

Telegram
@Gamble_GC
Start Integration

Email is required. Telegram or WhatsApp — optional.

Your Name optional
Email optional
Subject optional
Message optional
Telegram optional
@
If you include Telegram — we will reply there as well, in addition to Email.
WhatsApp optional
Format: +country code and number (e.g., +380XXXXXXXXX).

By clicking this button, you agree to data processing.