Games (Casino)
Integracao do cassino no template. Lista jogos, categorias, providers, busca, start-game, votos e estatisticas via @cactus-agents/games, com cache server-side via GamesCacheService.
Arquitetura
Loader (SSR) Client
| |
v v
GamesCacheService useGamesStore (Zustand)
| |
v v
ServerCache (memory + CF Cache) API Routes → SDK
|
v
@cactus-agents/games (SDK)
Dados publicos (home, categorias, providers) sao cacheados no servidor com stale-while-revalidate. Acoes autenticadas (start-game, votos) vao direto na API.
Arquivos principais
| Arquivo | Tipo | Descricao |
|---|---|---|
store/games.ts | Store (Zustand) | Estado completo do cassino |
services/games.client.ts | Service (client) | Client-side games service |
services/games.server.ts | Service (server) | Server-side com SDK direto |
services/games.cache.server.ts | Service (server) | Cache layer com stale-while-revalidate |
config/home-rows.legacy.ts | Config | Ordenação das rows da home (modo CASSINO_MODE=legacy; em api_new as rows vêm do BFF) |
config/casino-rows.legacy.ts | Config | Rows do hub /games (modo legacy) |
config/casino-live-rows.legacy.ts | Config | Rows do hub /games/live (modo legacy) |
config/categories.personalize.config.ts | Config | Overlay opcional (orderBy + displayPriority) sobre categorias vindas do BFF — ativo em legacy e api_new |
config/game-details.server.ts | Config (server) | SEO e descriptions de jogos (fork-overridable) |
utils/game-details.server.ts | Util (server) | Resolve templates e retorna details por jogo |
Store — useGamesStore
Estado principal:
homeRows— rows da home page (banners, categorias, widgets)categories/providers— metadados do catalogotopWins/lastWins— maiores ganhos e ultimos ganhossearchTerm/searchResults— buscaactiveGame— jogo ativo (detalhe)gameIframe— estado do iframe de jogovoteState— likes/dislikes do usuario
Rotas
Os paths abaixo sao os defaults — configuraveis via Route Registry (~/config/routes.paths). Use routeHref() e gameHref() para gerar links.
| Chave | Path padrao | Descricao |
|---|---|---|
casino | /games | Lobby do cassino (home rows) |
casino.play | /games/:provider/:game | Detalhe de jogo (SEO, stats, votos, iframe) |
casino.category | /games/category/:slug | Categoria de jogos |
casino.providers | /games/providers | Grid de providers |
casino.provider | /games/providers/:slug | Jogos de um provider |
API Routes
| Rota | Descricao |
|---|---|
api/games/search | Busca de jogos (usa cache de todos os jogos + filtro in-memory) |
api/games/start | Start game (autenticado) |
api/games/vote | Criar/remover voto |
api/cache/games/purge | Purge do cache de jogos |
Cache server-side
O GamesCacheService encapsula todas as chamadas do SDK com cache de 2 niveis:
- In-memory (isolate do Worker) — hit instantaneo
- CF Cache API — shared entre isolates
Estrategia stale-while-revalidate
fresh→ retorna imediatamentestale→ retorna imediatamente + revalida em background viawaitUntil()miss→ fetch da API, cacheia, retorna
Metodos cacheados
| Metodo | Cache key | Descricao |
|---|---|---|
getHome() | {domain}/home | Layout da homepage |
getBase() | {domain}/base | Categorias + providers |
getAllGames() | {domain}/all-games | Todos os jogos (paginado 500/pg) |
getByCategory(slug) | {domain}/category/{slug} | Jogos por categoria |
getByProvider(slug) | {domain}/provider/{slug} | Jogos por provider |
getDetail(slug) | {domain}/game/{slug} | Detalhe de um jogo |
getTopWins() | {domain}/top-wins | Top wins |
getLastWins() | {domain}/last-wins | Ultimos wins |
search(params) | (usa all-games cache) | Filtro in-memory |
Componentes
Home
GameSection— secao generica (titulo + grid/carrossel)LazyGameSections— lazy load das secoesGameCarousel— carrossel horizontal de jogos
Listagem
GameCard— card de jogo (thumbnail + nome + provider)GameGrid— grid responsivo de cardsGamesFilterBar— filtros por categoria/providerProvidersGrid— grid de providers
Detalhe
GameIframe— iframe do jogo (full-screen ou embed)GameDetailsBar— barra de detalhes (tags, RTP, margem, description com HTML)GameStats— estatisticas por periodoRelatedGames— jogos relacionados
Busca
SearchOverlay— overlay de busca com resultados em tempo real
Game Details Config
O arquivo config/game-details.server.ts centraliza SEO e descriptions de jogos. E server-only (nunca entra no bundle client).
Estrutura
export const gameDetails: GameDetailsConfig = {
defaults: {
meta_title: "{game_name} - Jogar Online | {brand_name}",
meta_description: "{game_name} é um jogo de cassino online disponível no {brand_name}...",
front_description: "<strong>{game_name}</strong> é um jogo de cassino online...",
},
games: {
"pgsoft/fortune-tiger": {
meta_description: "Fortune Tiger é um dos slots mais populares...",
front_description: "<strong>Fortune Tiger</strong> é um dos slots...",
// meta_title omitido → herda do defaults
},
},
};
Campos
| Campo | Uso | Formato |
|---|---|---|
meta_title | <title> e og:title | texto puro |
meta_description | <meta description> e JSON-LD | texto puro |
front_description | Exibido na pagina do jogo | HTML (<strong>, <em>, etc.) |
Template tags
Tags substituidas em runtime com dados reais do jogo:
| Tag | Valor |
|---|---|
{game_name} | Nome do jogo |
{game_provider} | Nome do provedor |
{game_rtp} | RTP (fallback: 97 se nao disponivel) |
{brand_name} | Nome da marca (brand.settings.name) |
Resolucao
- Se o jogo tem entry em
games, cada campo presente sobrescreve o default - Campos omitidos no entry herdam do
defaults - Apos o merge, template tags sao resolvidas com dados reais
Override por brand
O arquivo e overridable via Vite alias. Cada brand pode ter seus proprios defaults (idioma, tom de voz) e entries por jogo. Veja overrides/README.md.
Configuração — *-rows.legacy.ts
O template suporta 2 modos de cassino (CASSINO_MODE=legacy|api_new). Em legacy cada page (home, /games, /games/live) é montada a partir de um arquivo *-rows.legacy.ts (brand-overridable). Em api_new as rows vêm do BFF (GET /casino-games/page/{home,cassino,cassino_live}) e os arquivos .legacy.ts ficam dormentes.
// home-rows.legacy.ts — quando CASSINO_MODE=legacy
export const legacyHomeRows = [
{ slug: "home-banners", type: "widget" },
{ slug: "search-field", type: "widget" },
{ title: "Slots", slug: "slots", type: "games-api", maxItems: 15 },
// ...
];
Tipos de row aceitos em config: widget, games-api, providers-api, games-fixed. Todas as brands que usam modo legacy declaram as rows aqui — brands em api_new não precisam destes arquivos.
Pra curar ordenação/stat exibida em categorias BFF (tanto em legacy quanto api_new), use o overlay categories.personalize.config.ts — ver seção dedicada.