Conversation
okapitula
marked this pull request as ready for review
September 25, 2026 08:36
okapitula
requested review from
damianrzepka,
jakubfilinger-b,
klaudia-blazyczek-blurify,
marek-chmielowski-blurify,
mp-blurify and
zaxovaiko
as code owners
September 25, 2026 08:36
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an operator-set
customThumbnailUrlto games: a new nullablegame.custom_thumbnail_urlcolumn, settable throughPATCH /backoffice/gaming/games/{id}and returned next tothumbnailUrlon every game output (admin and public game lists and detail, category games, rule preview,GAME_CATALOG_READER'sCatalogGame, lobbyGameSummaryandFeaturedSlot). Core does not choose between the two; a consumer renderscustomThumbnailUrl ?? thumbnailUrl.Why
thumbnailUrlis the aggregator's image and a catalogue sync owns it, so an operator could not replace a game's artwork without the next sync overwriting it. A separate column keeps the operator's choice out of the sync's reach, and clearing it falls back to the aggregator image with nothing to restore.nullclears the value, and omitting the key leaves it untouched. Neither thumbnail field ever changes the other.https:URLs without embedded credentials are accepted. The stored and returned value is the normalized URL (new URL(v).href), not the raw input, so quotes, angle brackets and control characters never reach the public routes unescaped. The 512-character cap applies after normalization.PlatformConfig.gaming.allowedThumbnailHostslist, which matches hosts the same way the CMS banner allowlist does (exact host or a subdomain). The URL is loaded by anonymous players' browsers, so an unlisted host would receive their IPs. A disallowed host returns 400GameThumbnailHostNotAllowedError. TheisAllowedHostmatcher moved from cms into@openora/core/contracts, so the CMS banner check and gaming share it.gaming.game.updatedbefore/after carry the field. The change shows in the audit log underresourceType: 'game', and older events replay it asnull.game-config:update.Alternatives considered
thumbnailUrlfrom the backoffice: the next catalogue sync would revert it, and clearing it would lose the aggregator image.displayThumbnailUrl: this hides which image is the operator's, and the backoffice needs both to show "custom vs. default".Risks
gaming.allowedThumbnailHostsdefaults to an empty list, which rejects every custom thumbnail. An operator must list their thumbnail host(s) before the backoffice can set one.CatalogGamegains a requiredcustomThumbnailUrl: string | null. Code that implementsGameCatalogReaderitself, or builds aCatalogGameby hand, must now supply it. Code that only reads through the port is unaffected.thumbnailUrl, so a change can take up to 30s to appear there.thumbnailUrlinput still accepts any string, and chat keeps its own copy of the host matcher.