# =========================================================================== # LEIA ISTO ANTES DE ACRESCENTAR UM ROBO AQUI EMBAIXO. # # As regras deste arquivo moram dentro do macro `regras()` e sao REPETIDAS em # cada grupo de User-agent. A repeticao nao e desleixo, e obrigacao do formato. # # No robots.txt um robo obedece a UM grupo so: o mais especifico que casa com o # nome dele - e ignora o grupo `*` por inteiro. Entao um grupo assim: # # User-agent: ClaudeBot # Crawl-delay: 2 # # nao "acrescenta um atraso ao ClaudeBot". Ele faz o ClaudeBot parar de enxergar # TODOS os `Disallow` de baixo - as paginas atras de login, a paginacao, o # `/admin/`, o `/stripe/`, tudo. A tentativa de segurar o robo mais pesado do # site o soltaria justamente em cima do que custa mais caro, e em silencio: o # arquivo continuaria bonito e nada acusaria erro. # # Por isso todo grupo termina chamando o macro `regras()`. E a chamada NAO pode # ser citada com as chaves duplas aqui nesta prosa: o Jinja expande `{`+`{ ... }`+`}` # dentro de comentario tambem, e o bloco inteiro de regras vazaria para ca. # `tests/test_robots.py` falha se algum grupo ficar sem a chamada. # # Grupos de `User-agent:` consecutivos, sem linha em branco entre eles, contam # como UM grupo. E por isso que catorze robos cabem em duas listas em vez de # catorze copias das regras. # =========================================================================== # NOTE: /*/events/ (the events list/search page) is intentionally NOT blocked here. # It already ships its own `` in # templates/events/events.html, which lets Googlebot crawl it (and follow the links # to individual event pages) while keeping the thin, AJAX-filtered listing itself out # of the index - a robots.txt Disallow would instead stop crawling entirely and could # prevent discovery of/linking to the indexable per-event pages under /events/. # Individual event pages carry their own conditional noindex once the event has ended; # see templates/events/event.html. # --------------------------------------------------------------------------- # GRUPO 1 - todo mundo. Sem `Crawl-delay` de proposito: o Googlebot ignora # `Crawl-delay` por politica declarada, e ele e justamente quem manda gente # para ca. Ele custa 874 s de origem em tres horas, contra 20.616 s da Meta. User-agent: * # Allow everything by default, then block private/account areas, checkout/payment # endpoints, technical (non-content) endpoints and known duplicate/low-value URLs. Allow: / Disallow: /*/decks/*/play Disallow: /*/decks/*/registration Disallow: /*/decks/*/exportproxy Disallow: /*/decks/*/exporttxt Disallow: /*/decks/*/export Disallow: /*/decks/*/exportimage Disallow: /*/profile/* Disallow: /*/videos/* Disallow: /*/leagues/* Disallow: /*/teams/* Disallow: /*/admin/* Disallow: /*/stripe/* Disallow: /*/login/* Disallow: /*/edit$ Disallow: /*/new$ # As tres abaixo sao irmas do `/*/edit$` e entraram pelo mesmo motivo, medido em # 2026-08-14 no log da origem: 14% de TUDO que chegava nos servidores era resposta # 307, e 93% desses 307 eram pagina atras de login sendo varrida por robo. Numa # janela de 12 minutos, num droplet so: `suggestion` 1.697 pedidos, `edit` 919, # `history` 153, `pimpmydeck` 130. O `suggestion`, campeao isolado, nao estava aqui. # # Doi mais do que parece porque um 307 e INCACHEAVEL neste app: o `add_header` do # `__init__.py` so marca como `public` o que e 2xx ou (301, 308), entao todo 307 sai # `private, no-cache` e vai na origem toda vez. Conferido de fora: MISS, MISS, MISS. # # Nao se perde nada indexavel: as dez rotas que casam com estas linhas tem TODAS # `@login_required`, ou seja, para um robo elas nunca foram outra coisa senao um # redirecionamento para o login. # # `send` ficou de fora de proposito. Ele nao existe sem query string (`/card/send? # image=...&name=...`: 102 pedidos, 102 com query, zero sem), entao um `/*/send$` # jamais dispararia - seria a "regra que vira enfeite" contra a qual o # `tests/test_robots.py` existe. Quem ja pega esse caso e o `Disallow: /*/card/*?*` # la embaixo. Disallow: /*/suggestion$ Disallow: /*/history$ Disallow: /*/pimpmydeck$ Disallow: /*/meta-decks/top-players Disallow: /*/meta-decks/tournaments Disallow: /*/app/ Disallow: /*/cardsearch Disallow: /*/decks/fromdecktxtotojson Disallow: /*/decks/getmetadeck # Same story across every section below: the bare page (and its own search/filter page) is # real, indexable content; the problem is individual-item pages picking up a query string # (deck_txt, card_path, keyword, page, etc.), which turns every combination into its own # crawlable, CDN-cached URL that's essentially never requested twice. "Disallow: /X/*?*" # blocks that without touching the bare page. # # Each search/listing page's own filters (e.g. "?card_path=..." on combo-infinite, "?page=2" # on articles/search) still need to stay crawlable, since that's how these get discovered/ # indexed in the first place - a plain "Allow: /X/?*" for that can't reliably win, though: per # Google's robots.txt spec, when an Allow and a Disallow both match a URL the LONGER rule (by # character count) wins, and "/X/?*" is always exactly one "*" shorter than "/X/*?*" - i.e. the # Disallow above would always win the tie. The "=*" suffix is not decorative - it pads the # Allow past that length (real query strings always contain "key=value", so this doesn't # narrow what actually gets matched). # PAGINACAO FORA DO ALCANCE DOS ROBOS, so a primeira pagina de cada listagem. # # Decisao do dono em 2026-08-12, durante o incidente de lentidao. O que ela # resolve, medido no dia: `/articles/search/` era 6,6% de tudo que chegava nos # servidores, com a taxa de acerto da CDN em 4,4%. A pagina CACHEIA # corretamente (conferido: tres pedidos, tres HIT) - o problema e que cada # `?keyword=X&page=N` e uma URL diferente que quase ninguem pede duas vezes: # 862 pedidos para 429 URLs distintas, e como a bunny tem dezenas de pontos de # presenca, duas visitas no mundo costumam ser dois PoPs, logo dois misses. # Quem caminhava: GPTBot 56%, mais Amazonbot e ClaudeBot. # # A PRIMEIRA PAGINA CONTINUA LIVRE porque ela nao tem `page=` na URL: o # template canonicaliza `?keyword=&game=1&page=1` para o endereco limpo (ver o # comentario no topo de `templates/articles.html`). Estas regras so pegam quem # tem `page=` de verdade. # # O `?*page=*` de cada linha e MAIS LONGO que o `Allow` que ele disputa, de # proposito - vence o padrao mais longo, como explicado acima. Encurtar um # destes faz o Allow voltar a ganhar e a regra vira enfeite. O do `/card/` # passa por dentro do `card_name=` por essa razao, e nao por capricho. # `tests/test_robots.py` falha se isso for desfeito. # # O QUE SE PERDE, escrito aqui para nao virar surpresa depois: a paginacao # profunda era `noindex, follow` - o robo entrava, nao indexava, mas SEGUIA os # links para os artigos. Com `Disallow` ele nao entra, e esse caminho de # descoberta acaba. O substituto natural seria o sitemap, e o dono informou em # 2026-08-12 que o sitemap NAO FUNCIONA. Enquanto nao funcionar, artigo antigo # depende de link interno para ser reencontrado. Disallow: /*/decks/deckbuilder?* Disallow: /*/tools/*?* Disallow: /*/tools/getlands Disallow: /*/articles/*?* Allow: /*/articles/search/?*=* Disallow: /*/articles/search/?*page=* Disallow: /*/decks/*?* # Os DOIS formatos, com e sem barra antes do "?", de proposito. # # A linha `Disallow: /*/decks/*?*` acima pega qualquer URL de deck com query, e # estas duas sao a excecao que libera a busca. Em 2026-08-16 os links do site # passaram a usar `/decks/search/?...` (com barra), que e para onde o servidor # ja redirecionava - e a excecao, escrita so na forma SEM barra, deixaria de # casar: a busca de decks inteira cairia no Disallow de cima e sairia do indice. # A forma sem barra continua aqui porque e a que esta indexada hoje e a que # chega de link externo; ela responde 308 para a com barra. # As linhas de `articles` logo acima ja usavam a forma com barra. Allow: /*/decks/search?*=* Disallow: /*/decks/search?*page=* Allow: /*/decks/search/?*=* Disallow: /*/decks/search/?*page=* Disallow: /*/tournament/*?* Disallow: /*/combo-infinite/*?* Allow: /*/combo-infinite/?*=* Disallow: /*/combo-infinite/?*page=* Disallow: /*/meta-decks/*?* Disallow: /*/meta-decks/*/*?* Disallow: /*/sets/*?* Allow: /*/sets/?*=* Disallow: /*/sets/?*page=* Disallow: /*/references/*?* Allow: /*/references/?*=* Disallow: /*/references/?*page=* Disallow: /*/card/*?* Allow: /*/card/?card_name=* Disallow: /*/card/?card_name=*page=* # /videos/ is already fully blocked below (Disallow: /*/videos/*), not just its query-string # variants - left alone here rather than assumed into this pattern. Disallow: /*/api/* Disallow: /*/finance/* Disallow: /*/seller/* Disallow: /*/push/* # # LOCALES QUE NAO SAO PAGINA NOVA, SAO A MESMA PAGINA OUTRA VEZ. # # O `before_request` aceita qualquer um dos 228 `language_locale_code` da tabela, # e manda 307 para um deles conforme o `Accept-Language` do navegador. Mas o # site so RECONHECE 61: e o que o `get_all_languages_locales` devolve, o que # alimenta o seletor de idioma e os `hreflang`. Os 167 restantes respondem 200 e # renderizam `lang="en-us"` - conferido em 01/09/2026 em `/et-ee/`, `/th-th/`, # `/vi-vn/` e `/hi-in/`: byte por byte a pagina inglesa, noutro endereco. # # CADA UM DELES E UMA CHAVE DE CACHE SEPARADA na CDN. Medido no mesmo dia: 27% # de acerto (site de conteudo fica entre 80% e 95%), 29,2 milhoes de requisicoes # em 24h e 937 GB puxados da origem so na zona de Magic. A origem respondia em # ~5s pela medida da bunny contra 0,23s de processamento real no nginx - a # diferenca era fila, com os droplets em 60-100% de CPU o dia inteiro. # # A lista sai do banco (`mysql_share.get_locales_fora_da_lista`), nao esta # escrita a mao: ligar um locale no admin o tira daqui sozinho. # # ISTO NAO RESOLVE SOZINHO, e a limitacao importa: robots.txt fala com robo, e o # 307 por `Accept-Language` continua mandando GENTE para ca. Enquanto o # redirecionamento existir, a fragmentacao de cache continua para o trafego # humano - o conserto completo e o site parar de rotear para locale que ele nao # reconhece. Disallow: /af/ Disallow: /af-za/ Disallow: /ar/ Disallow: /ar-ae/ Disallow: /ar-bh/ Disallow: /ar-dz/ Disallow: /ar-iq/ Disallow: /ar-jo/ Disallow: /ar-kw/ Disallow: /ar-lb/ Disallow: /ar-ly/ Disallow: /ar-om/ Disallow: /ar-qa/ Disallow: /ar-sy/ Disallow: /ar-tn/ Disallow: /ar-ye/ Disallow: /az/ Disallow: /az-az/ Disallow: /be/ Disallow: /be-by/ Disallow: /bg/ Disallow: /bg-bg/ Disallow: /bs-ba/ Disallow: /ca/ Disallow: /cs/ Disallow: /cs-cz/ Disallow: /cy/ Disallow: /cy-gb/ Disallow: /da/ Disallow: /da-dk/ Disallow: /de/ Disallow: /dv/ Disallow: /dv-mv/ Disallow: /el/ Disallow: /el-gr/ Disallow: /en/ Disallow: /en-cb/ Disallow: /eo/ Disallow: /es/ Disallow: /et/ Disallow: /et-ee/ Disallow: /eu/ Disallow: /eu-es/ Disallow: /fa/ Disallow: /fa-ir/ Disallow: /fi/ Disallow: /fi-fi/ Disallow: /fo/ Disallow: /fo-fo/ Disallow: /fr/ Disallow: /gl/ Disallow: /gl-es/ Disallow: /gu/ Disallow: /gu-in/ Disallow: /he/ Disallow: /he-il/ Disallow: /hi/ Disallow: /hi-in/ Disallow: /hr/ Disallow: /hr-ba/ Disallow: /hr-hr/ Disallow: /hu/ Disallow: /hu-hu/ Disallow: /hy/ Disallow: /hy-am/ Disallow: /id/ Disallow: /id-id/ Disallow: /is/ Disallow: /is-is/ Disallow: /it/ Disallow: /ja/ Disallow: /ka/ Disallow: /ka-ge/ Disallow: /kk/ Disallow: /kk-kz/ Disallow: /kn/ Disallow: /kn-in/ Disallow: /ko/ Disallow: /kok/ Disallow: /kok-in/ Disallow: /ky/ Disallow: /ky-kg/ Disallow: /lt/ Disallow: /lt-lt/ Disallow: /lv/ Disallow: /lv-lv/ Disallow: /mi/ Disallow: /mi-nz/ Disallow: /mk/ Disallow: /mk-mk/ Disallow: /mn/ Disallow: /mn-mn/ Disallow: /mr/ Disallow: /mr-in/ Disallow: /ms/ Disallow: /ms-bn/ Disallow: /ms-my/ Disallow: /mt/ Disallow: /mt-mt/ Disallow: /nb/ Disallow: /nb-no/ Disallow: /nl/ Disallow: /nl-be/ Disallow: /nn-no/ Disallow: /ns/ Disallow: /ns-za/ Disallow: /pa/ Disallow: /pa-in/ Disallow: /pl/ Disallow: /pl-pl/ Disallow: /ps/ Disallow: /ps-ar/ Disallow: /pt/ Disallow: /qu/ Disallow: /qu-bo/ Disallow: /qu-ec/ Disallow: /qu-pe/ Disallow: /ro/ Disallow: /ro-ro/ Disallow: /ru/ Disallow: /sa/ Disallow: /sa-in/ Disallow: /se/ Disallow: /se-fi/ Disallow: /se-no/ Disallow: /se-se/ Disallow: /sk/ Disallow: /sk-sk/ Disallow: /sl/ Disallow: /sl-si/ Disallow: /sq/ Disallow: /sq-al/ Disallow: /sr-ba/ Disallow: /sr-sp/ Disallow: /sv/ Disallow: /sw/ Disallow: /sw-ke/ Disallow: /syr/ Disallow: /syr-sy/ Disallow: /ta/ Disallow: /ta-in/ Disallow: /te/ Disallow: /te-in/ Disallow: /th/ Disallow: /th-th/ Disallow: /tl/ Disallow: /tl-ph/ Disallow: /tn/ Disallow: /tn-za/ Disallow: /tr/ Disallow: /tr-tr/ Disallow: /ts/ Disallow: /tt/ Disallow: /tt-ru/ Disallow: /uk/ Disallow: /uk-ua/ Disallow: /ur/ Disallow: /ur-pk/ Disallow: /uz/ Disallow: /uz-uz/ Disallow: /vi/ Disallow: /vi-vn/ Disallow: /xh/ Disallow: /xh-za/ Disallow: /zh/ Disallow: /zu/ Disallow: /zu-za/ # --------------------------------------------------------------------------- # GRUPO 2 - os robos que EXTRAEM conteudo em vez de mandar visita. # # Medido em 30/08/2026, no `access.log` da origem, janela de 3 horas num # droplet (28/08, 14h-17h UTC), somando `upstream_response_time` por robo: # 51% de TODO o tempo de processamento da origem era robo declarado. # # Meta (meta-externalagent + meta-webindexer) 20.616 s 167 mil pedidos # ClaudeBot 10.578 s 72 mil # Amazonbot 4.975 s 28 mil # Bytespider 4.129 s 18 mil # GPTBot + OAI-SearchBot 2.018 s 11 mil # PetalBot 918 s 4 mil # PerplexityBot 332 s 1 mil # --- # Googlebot (o que traz busca) 874 s 5 mil # # `Crawl-delay: 2` = meio pedido por segundo por robo, ou 43 mil paginas por # dia. Continua sendo orcamento de rastreio de sobra para um site de conteudo, # e derruba o ClaudeBot de ~10 pedidos/s para 0,5 - vinte vezes menos. # # NEM TODOS OBEDECEM, e isto esta escrito aqui para nao virar surpresa: # Amazonbot, Bytespider, PetalBot e os robos de SEO do grupo 3 documentam # obediencia a `Crawl-delay`. A OpenAI nao documenta suporte, e a Meta tambem # nao - para esses dois a linha e aposta, nao garantia. Se numa medicao futura # o volume deles nao cair, o passo seguinte e bloqueio, nao atraso. User-agent: ClaudeBot User-agent: meta-externalagent User-agent: meta-webindexer User-agent: Amazonbot User-agent: Bytespider User-agent: GPTBot User-agent: OAI-SearchBot User-agent: PerplexityBot User-agent: PetalBot Crawl-delay: 2 # Allow everything by default, then block private/account areas, checkout/payment # endpoints, technical (non-content) endpoints and known duplicate/low-value URLs. Allow: / Disallow: /*/decks/*/play Disallow: /*/decks/*/registration Disallow: /*/decks/*/exportproxy Disallow: /*/decks/*/exporttxt Disallow: /*/decks/*/export Disallow: /*/decks/*/exportimage Disallow: /*/profile/* Disallow: /*/videos/* Disallow: /*/leagues/* Disallow: /*/teams/* Disallow: /*/admin/* Disallow: /*/stripe/* Disallow: /*/login/* Disallow: /*/edit$ Disallow: /*/new$ # As tres abaixo sao irmas do `/*/edit$` e entraram pelo mesmo motivo, medido em # 2026-08-14 no log da origem: 14% de TUDO que chegava nos servidores era resposta # 307, e 93% desses 307 eram pagina atras de login sendo varrida por robo. Numa # janela de 12 minutos, num droplet so: `suggestion` 1.697 pedidos, `edit` 919, # `history` 153, `pimpmydeck` 130. O `suggestion`, campeao isolado, nao estava aqui. # # Doi mais do que parece porque um 307 e INCACHEAVEL neste app: o `add_header` do # `__init__.py` so marca como `public` o que e 2xx ou (301, 308), entao todo 307 sai # `private, no-cache` e vai na origem toda vez. Conferido de fora: MISS, MISS, MISS. # # Nao se perde nada indexavel: as dez rotas que casam com estas linhas tem TODAS # `@login_required`, ou seja, para um robo elas nunca foram outra coisa senao um # redirecionamento para o login. # # `send` ficou de fora de proposito. Ele nao existe sem query string (`/card/send? # image=...&name=...`: 102 pedidos, 102 com query, zero sem), entao um `/*/send$` # jamais dispararia - seria a "regra que vira enfeite" contra a qual o # `tests/test_robots.py` existe. Quem ja pega esse caso e o `Disallow: /*/card/*?*` # la embaixo. Disallow: /*/suggestion$ Disallow: /*/history$ Disallow: /*/pimpmydeck$ Disallow: /*/meta-decks/top-players Disallow: /*/meta-decks/tournaments Disallow: /*/app/ Disallow: /*/cardsearch Disallow: /*/decks/fromdecktxtotojson Disallow: /*/decks/getmetadeck # Same story across every section below: the bare page (and its own search/filter page) is # real, indexable content; the problem is individual-item pages picking up a query string # (deck_txt, card_path, keyword, page, etc.), which turns every combination into its own # crawlable, CDN-cached URL that's essentially never requested twice. "Disallow: /X/*?*" # blocks that without touching the bare page. # # Each search/listing page's own filters (e.g. "?card_path=..." on combo-infinite, "?page=2" # on articles/search) still need to stay crawlable, since that's how these get discovered/ # indexed in the first place - a plain "Allow: /X/?*" for that can't reliably win, though: per # Google's robots.txt spec, when an Allow and a Disallow both match a URL the LONGER rule (by # character count) wins, and "/X/?*" is always exactly one "*" shorter than "/X/*?*" - i.e. the # Disallow above would always win the tie. The "=*" suffix is not decorative - it pads the # Allow past that length (real query strings always contain "key=value", so this doesn't # narrow what actually gets matched). # PAGINACAO FORA DO ALCANCE DOS ROBOS, so a primeira pagina de cada listagem. # # Decisao do dono em 2026-08-12, durante o incidente de lentidao. O que ela # resolve, medido no dia: `/articles/search/` era 6,6% de tudo que chegava nos # servidores, com a taxa de acerto da CDN em 4,4%. A pagina CACHEIA # corretamente (conferido: tres pedidos, tres HIT) - o problema e que cada # `?keyword=X&page=N` e uma URL diferente que quase ninguem pede duas vezes: # 862 pedidos para 429 URLs distintas, e como a bunny tem dezenas de pontos de # presenca, duas visitas no mundo costumam ser dois PoPs, logo dois misses. # Quem caminhava: GPTBot 56%, mais Amazonbot e ClaudeBot. # # A PRIMEIRA PAGINA CONTINUA LIVRE porque ela nao tem `page=` na URL: o # template canonicaliza `?keyword=&game=1&page=1` para o endereco limpo (ver o # comentario no topo de `templates/articles.html`). Estas regras so pegam quem # tem `page=` de verdade. # # O `?*page=*` de cada linha e MAIS LONGO que o `Allow` que ele disputa, de # proposito - vence o padrao mais longo, como explicado acima. Encurtar um # destes faz o Allow voltar a ganhar e a regra vira enfeite. O do `/card/` # passa por dentro do `card_name=` por essa razao, e nao por capricho. # `tests/test_robots.py` falha se isso for desfeito. # # O QUE SE PERDE, escrito aqui para nao virar surpresa depois: a paginacao # profunda era `noindex, follow` - o robo entrava, nao indexava, mas SEGUIA os # links para os artigos. Com `Disallow` ele nao entra, e esse caminho de # descoberta acaba. O substituto natural seria o sitemap, e o dono informou em # 2026-08-12 que o sitemap NAO FUNCIONA. Enquanto nao funcionar, artigo antigo # depende de link interno para ser reencontrado. Disallow: /*/decks/deckbuilder?* Disallow: /*/tools/*?* Disallow: /*/tools/getlands Disallow: /*/articles/*?* Allow: /*/articles/search/?*=* Disallow: /*/articles/search/?*page=* Disallow: /*/decks/*?* # Os DOIS formatos, com e sem barra antes do "?", de proposito. # # A linha `Disallow: /*/decks/*?*` acima pega qualquer URL de deck com query, e # estas duas sao a excecao que libera a busca. Em 2026-08-16 os links do site # passaram a usar `/decks/search/?...` (com barra), que e para onde o servidor # ja redirecionava - e a excecao, escrita so na forma SEM barra, deixaria de # casar: a busca de decks inteira cairia no Disallow de cima e sairia do indice. # A forma sem barra continua aqui porque e a que esta indexada hoje e a que # chega de link externo; ela responde 308 para a com barra. # As linhas de `articles` logo acima ja usavam a forma com barra. Allow: /*/decks/search?*=* Disallow: /*/decks/search?*page=* Allow: /*/decks/search/?*=* Disallow: /*/decks/search/?*page=* Disallow: /*/tournament/*?* Disallow: /*/combo-infinite/*?* Allow: /*/combo-infinite/?*=* Disallow: /*/combo-infinite/?*page=* Disallow: /*/meta-decks/*?* Disallow: /*/meta-decks/*/*?* Disallow: /*/sets/*?* Allow: /*/sets/?*=* Disallow: /*/sets/?*page=* Disallow: /*/references/*?* Allow: /*/references/?*=* Disallow: /*/references/?*page=* Disallow: /*/card/*?* Allow: /*/card/?card_name=* Disallow: /*/card/?card_name=*page=* # /videos/ is already fully blocked below (Disallow: /*/videos/*), not just its query-string # variants - left alone here rather than assumed into this pattern. Disallow: /*/api/* Disallow: /*/finance/* Disallow: /*/seller/* Disallow: /*/push/* # # LOCALES QUE NAO SAO PAGINA NOVA, SAO A MESMA PAGINA OUTRA VEZ. # # O `before_request` aceita qualquer um dos 228 `language_locale_code` da tabela, # e manda 307 para um deles conforme o `Accept-Language` do navegador. Mas o # site so RECONHECE 61: e o que o `get_all_languages_locales` devolve, o que # alimenta o seletor de idioma e os `hreflang`. Os 167 restantes respondem 200 e # renderizam `lang="en-us"` - conferido em 01/09/2026 em `/et-ee/`, `/th-th/`, # `/vi-vn/` e `/hi-in/`: byte por byte a pagina inglesa, noutro endereco. # # CADA UM DELES E UMA CHAVE DE CACHE SEPARADA na CDN. Medido no mesmo dia: 27% # de acerto (site de conteudo fica entre 80% e 95%), 29,2 milhoes de requisicoes # em 24h e 937 GB puxados da origem so na zona de Magic. A origem respondia em # ~5s pela medida da bunny contra 0,23s de processamento real no nginx - a # diferenca era fila, com os droplets em 60-100% de CPU o dia inteiro. # # A lista sai do banco (`mysql_share.get_locales_fora_da_lista`), nao esta # escrita a mao: ligar um locale no admin o tira daqui sozinho. # # ISTO NAO RESOLVE SOZINHO, e a limitacao importa: robots.txt fala com robo, e o # 307 por `Accept-Language` continua mandando GENTE para ca. Enquanto o # redirecionamento existir, a fragmentacao de cache continua para o trafego # humano - o conserto completo e o site parar de rotear para locale que ele nao # reconhece. Disallow: /af/ Disallow: /af-za/ Disallow: /ar/ Disallow: /ar-ae/ Disallow: /ar-bh/ Disallow: /ar-dz/ Disallow: /ar-iq/ Disallow: /ar-jo/ Disallow: /ar-kw/ Disallow: /ar-lb/ Disallow: /ar-ly/ Disallow: /ar-om/ Disallow: /ar-qa/ Disallow: /ar-sy/ Disallow: /ar-tn/ Disallow: /ar-ye/ Disallow: /az/ Disallow: /az-az/ Disallow: /be/ Disallow: /be-by/ Disallow: /bg/ Disallow: /bg-bg/ Disallow: /bs-ba/ Disallow: /ca/ Disallow: /cs/ Disallow: /cs-cz/ Disallow: /cy/ Disallow: /cy-gb/ Disallow: /da/ Disallow: /da-dk/ Disallow: /de/ Disallow: /dv/ Disallow: /dv-mv/ Disallow: /el/ Disallow: /el-gr/ Disallow: /en/ Disallow: /en-cb/ Disallow: /eo/ Disallow: /es/ Disallow: /et/ Disallow: /et-ee/ Disallow: /eu/ Disallow: /eu-es/ Disallow: /fa/ Disallow: /fa-ir/ Disallow: /fi/ Disallow: /fi-fi/ Disallow: /fo/ Disallow: /fo-fo/ Disallow: /fr/ Disallow: /gl/ Disallow: /gl-es/ Disallow: /gu/ Disallow: /gu-in/ Disallow: /he/ Disallow: /he-il/ Disallow: /hi/ Disallow: /hi-in/ Disallow: /hr/ Disallow: /hr-ba/ Disallow: /hr-hr/ Disallow: /hu/ Disallow: /hu-hu/ Disallow: /hy/ Disallow: /hy-am/ Disallow: /id/ Disallow: /id-id/ Disallow: /is/ Disallow: /is-is/ Disallow: /it/ Disallow: /ja/ Disallow: /ka/ Disallow: /ka-ge/ Disallow: /kk/ Disallow: /kk-kz/ Disallow: /kn/ Disallow: /kn-in/ Disallow: /ko/ Disallow: /kok/ Disallow: /kok-in/ Disallow: /ky/ Disallow: /ky-kg/ Disallow: /lt/ Disallow: /lt-lt/ Disallow: /lv/ Disallow: /lv-lv/ Disallow: /mi/ Disallow: /mi-nz/ Disallow: /mk/ Disallow: /mk-mk/ Disallow: /mn/ Disallow: /mn-mn/ Disallow: /mr/ Disallow: /mr-in/ Disallow: /ms/ Disallow: /ms-bn/ Disallow: /ms-my/ Disallow: /mt/ Disallow: /mt-mt/ Disallow: /nb/ Disallow: /nb-no/ Disallow: /nl/ Disallow: /nl-be/ Disallow: /nn-no/ Disallow: /ns/ Disallow: /ns-za/ Disallow: /pa/ Disallow: /pa-in/ Disallow: /pl/ Disallow: /pl-pl/ Disallow: /ps/ Disallow: /ps-ar/ Disallow: /pt/ Disallow: /qu/ Disallow: /qu-bo/ Disallow: /qu-ec/ Disallow: /qu-pe/ Disallow: /ro/ Disallow: /ro-ro/ Disallow: /ru/ Disallow: /sa/ Disallow: /sa-in/ Disallow: /se/ Disallow: /se-fi/ Disallow: /se-no/ Disallow: /se-se/ Disallow: /sk/ Disallow: /sk-sk/ Disallow: /sl/ Disallow: /sl-si/ Disallow: /sq/ Disallow: /sq-al/ Disallow: /sr-ba/ Disallow: /sr-sp/ Disallow: /sv/ Disallow: /sw/ Disallow: /sw-ke/ Disallow: /syr/ Disallow: /syr-sy/ Disallow: /ta/ Disallow: /ta-in/ Disallow: /te/ Disallow: /te-in/ Disallow: /th/ Disallow: /th-th/ Disallow: /tl/ Disallow: /tl-ph/ Disallow: /tn/ Disallow: /tn-za/ Disallow: /tr/ Disallow: /tr-tr/ Disallow: /ts/ Disallow: /tt/ Disallow: /tt-ru/ Disallow: /uk/ Disallow: /uk-ua/ Disallow: /ur/ Disallow: /ur-pk/ Disallow: /uz/ Disallow: /uz-uz/ Disallow: /vi/ Disallow: /vi-vn/ Disallow: /xh/ Disallow: /xh-za/ Disallow: /zh/ Disallow: /zu/ Disallow: /zu-za/ # --------------------------------------------------------------------------- # GRUPO 3 - ferramentas de SEO. Rastreiam o site inteiro para vender relatorio # de backlink a terceiros e nao mandam UMA visita de volta; juntas custavam # 3.373 s na mesma janela de tres horas. Dez segundos de intervalo (8.640 # paginas por dia) e generoso para o que elas devolvem. User-agent: AhrefsBot User-agent: SemrushBot User-agent: SERankingBacklinksBot User-agent: DataForSeoBot User-agent: MJ12bot Crawl-delay: 10 # Allow everything by default, then block private/account areas, checkout/payment # endpoints, technical (non-content) endpoints and known duplicate/low-value URLs. Allow: / Disallow: /*/decks/*/play Disallow: /*/decks/*/registration Disallow: /*/decks/*/exportproxy Disallow: /*/decks/*/exporttxt Disallow: /*/decks/*/export Disallow: /*/decks/*/exportimage Disallow: /*/profile/* Disallow: /*/videos/* Disallow: /*/leagues/* Disallow: /*/teams/* Disallow: /*/admin/* Disallow: /*/stripe/* Disallow: /*/login/* Disallow: /*/edit$ Disallow: /*/new$ # As tres abaixo sao irmas do `/*/edit$` e entraram pelo mesmo motivo, medido em # 2026-08-14 no log da origem: 14% de TUDO que chegava nos servidores era resposta # 307, e 93% desses 307 eram pagina atras de login sendo varrida por robo. Numa # janela de 12 minutos, num droplet so: `suggestion` 1.697 pedidos, `edit` 919, # `history` 153, `pimpmydeck` 130. O `suggestion`, campeao isolado, nao estava aqui. # # Doi mais do que parece porque um 307 e INCACHEAVEL neste app: o `add_header` do # `__init__.py` so marca como `public` o que e 2xx ou (301, 308), entao todo 307 sai # `private, no-cache` e vai na origem toda vez. Conferido de fora: MISS, MISS, MISS. # # Nao se perde nada indexavel: as dez rotas que casam com estas linhas tem TODAS # `@login_required`, ou seja, para um robo elas nunca foram outra coisa senao um # redirecionamento para o login. # # `send` ficou de fora de proposito. Ele nao existe sem query string (`/card/send? # image=...&name=...`: 102 pedidos, 102 com query, zero sem), entao um `/*/send$` # jamais dispararia - seria a "regra que vira enfeite" contra a qual o # `tests/test_robots.py` existe. Quem ja pega esse caso e o `Disallow: /*/card/*?*` # la embaixo. Disallow: /*/suggestion$ Disallow: /*/history$ Disallow: /*/pimpmydeck$ Disallow: /*/meta-decks/top-players Disallow: /*/meta-decks/tournaments Disallow: /*/app/ Disallow: /*/cardsearch Disallow: /*/decks/fromdecktxtotojson Disallow: /*/decks/getmetadeck # Same story across every section below: the bare page (and its own search/filter page) is # real, indexable content; the problem is individual-item pages picking up a query string # (deck_txt, card_path, keyword, page, etc.), which turns every combination into its own # crawlable, CDN-cached URL that's essentially never requested twice. "Disallow: /X/*?*" # blocks that without touching the bare page. # # Each search/listing page's own filters (e.g. "?card_path=..." on combo-infinite, "?page=2" # on articles/search) still need to stay crawlable, since that's how these get discovered/ # indexed in the first place - a plain "Allow: /X/?*" for that can't reliably win, though: per # Google's robots.txt spec, when an Allow and a Disallow both match a URL the LONGER rule (by # character count) wins, and "/X/?*" is always exactly one "*" shorter than "/X/*?*" - i.e. the # Disallow above would always win the tie. The "=*" suffix is not decorative - it pads the # Allow past that length (real query strings always contain "key=value", so this doesn't # narrow what actually gets matched). # PAGINACAO FORA DO ALCANCE DOS ROBOS, so a primeira pagina de cada listagem. # # Decisao do dono em 2026-08-12, durante o incidente de lentidao. O que ela # resolve, medido no dia: `/articles/search/` era 6,6% de tudo que chegava nos # servidores, com a taxa de acerto da CDN em 4,4%. A pagina CACHEIA # corretamente (conferido: tres pedidos, tres HIT) - o problema e que cada # `?keyword=X&page=N` e uma URL diferente que quase ninguem pede duas vezes: # 862 pedidos para 429 URLs distintas, e como a bunny tem dezenas de pontos de # presenca, duas visitas no mundo costumam ser dois PoPs, logo dois misses. # Quem caminhava: GPTBot 56%, mais Amazonbot e ClaudeBot. # # A PRIMEIRA PAGINA CONTINUA LIVRE porque ela nao tem `page=` na URL: o # template canonicaliza `?keyword=&game=1&page=1` para o endereco limpo (ver o # comentario no topo de `templates/articles.html`). Estas regras so pegam quem # tem `page=` de verdade. # # O `?*page=*` de cada linha e MAIS LONGO que o `Allow` que ele disputa, de # proposito - vence o padrao mais longo, como explicado acima. Encurtar um # destes faz o Allow voltar a ganhar e a regra vira enfeite. O do `/card/` # passa por dentro do `card_name=` por essa razao, e nao por capricho. # `tests/test_robots.py` falha se isso for desfeito. # # O QUE SE PERDE, escrito aqui para nao virar surpresa depois: a paginacao # profunda era `noindex, follow` - o robo entrava, nao indexava, mas SEGUIA os # links para os artigos. Com `Disallow` ele nao entra, e esse caminho de # descoberta acaba. O substituto natural seria o sitemap, e o dono informou em # 2026-08-12 que o sitemap NAO FUNCIONA. Enquanto nao funcionar, artigo antigo # depende de link interno para ser reencontrado. Disallow: /*/decks/deckbuilder?* Disallow: /*/tools/*?* Disallow: /*/tools/getlands Disallow: /*/articles/*?* Allow: /*/articles/search/?*=* Disallow: /*/articles/search/?*page=* Disallow: /*/decks/*?* # Os DOIS formatos, com e sem barra antes do "?", de proposito. # # A linha `Disallow: /*/decks/*?*` acima pega qualquer URL de deck com query, e # estas duas sao a excecao que libera a busca. Em 2026-08-16 os links do site # passaram a usar `/decks/search/?...` (com barra), que e para onde o servidor # ja redirecionava - e a excecao, escrita so na forma SEM barra, deixaria de # casar: a busca de decks inteira cairia no Disallow de cima e sairia do indice. # A forma sem barra continua aqui porque e a que esta indexada hoje e a que # chega de link externo; ela responde 308 para a com barra. # As linhas de `articles` logo acima ja usavam a forma com barra. Allow: /*/decks/search?*=* Disallow: /*/decks/search?*page=* Allow: /*/decks/search/?*=* Disallow: /*/decks/search/?*page=* Disallow: /*/tournament/*?* Disallow: /*/combo-infinite/*?* Allow: /*/combo-infinite/?*=* Disallow: /*/combo-infinite/?*page=* Disallow: /*/meta-decks/*?* Disallow: /*/meta-decks/*/*?* Disallow: /*/sets/*?* Allow: /*/sets/?*=* Disallow: /*/sets/?*page=* Disallow: /*/references/*?* Allow: /*/references/?*=* Disallow: /*/references/?*page=* Disallow: /*/card/*?* Allow: /*/card/?card_name=* Disallow: /*/card/?card_name=*page=* # /videos/ is already fully blocked below (Disallow: /*/videos/*), not just its query-string # variants - left alone here rather than assumed into this pattern. Disallow: /*/api/* Disallow: /*/finance/* Disallow: /*/seller/* Disallow: /*/push/* # # LOCALES QUE NAO SAO PAGINA NOVA, SAO A MESMA PAGINA OUTRA VEZ. # # O `before_request` aceita qualquer um dos 228 `language_locale_code` da tabela, # e manda 307 para um deles conforme o `Accept-Language` do navegador. Mas o # site so RECONHECE 61: e o que o `get_all_languages_locales` devolve, o que # alimenta o seletor de idioma e os `hreflang`. Os 167 restantes respondem 200 e # renderizam `lang="en-us"` - conferido em 01/09/2026 em `/et-ee/`, `/th-th/`, # `/vi-vn/` e `/hi-in/`: byte por byte a pagina inglesa, noutro endereco. # # CADA UM DELES E UMA CHAVE DE CACHE SEPARADA na CDN. Medido no mesmo dia: 27% # de acerto (site de conteudo fica entre 80% e 95%), 29,2 milhoes de requisicoes # em 24h e 937 GB puxados da origem so na zona de Magic. A origem respondia em # ~5s pela medida da bunny contra 0,23s de processamento real no nginx - a # diferenca era fila, com os droplets em 60-100% de CPU o dia inteiro. # # A lista sai do banco (`mysql_share.get_locales_fora_da_lista`), nao esta # escrita a mao: ligar um locale no admin o tira daqui sozinho. # # ISTO NAO RESOLVE SOZINHO, e a limitacao importa: robots.txt fala com robo, e o # 307 por `Accept-Language` continua mandando GENTE para ca. Enquanto o # redirecionamento existir, a fragmentacao de cache continua para o trafego # humano - o conserto completo e o site parar de rotear para locale que ele nao # reconhece. Disallow: /af/ Disallow: /af-za/ Disallow: /ar/ Disallow: /ar-ae/ Disallow: /ar-bh/ Disallow: /ar-dz/ Disallow: /ar-iq/ Disallow: /ar-jo/ Disallow: /ar-kw/ Disallow: /ar-lb/ Disallow: /ar-ly/ Disallow: /ar-om/ Disallow: /ar-qa/ Disallow: /ar-sy/ Disallow: /ar-tn/ Disallow: /ar-ye/ Disallow: /az/ Disallow: /az-az/ Disallow: /be/ Disallow: /be-by/ Disallow: /bg/ Disallow: /bg-bg/ Disallow: /bs-ba/ Disallow: /ca/ Disallow: /cs/ Disallow: /cs-cz/ Disallow: /cy/ Disallow: /cy-gb/ Disallow: /da/ Disallow: /da-dk/ Disallow: /de/ Disallow: /dv/ Disallow: /dv-mv/ Disallow: /el/ Disallow: /el-gr/ Disallow: /en/ Disallow: /en-cb/ Disallow: /eo/ Disallow: /es/ Disallow: /et/ Disallow: /et-ee/ Disallow: /eu/ Disallow: /eu-es/ Disallow: /fa/ Disallow: /fa-ir/ Disallow: /fi/ Disallow: /fi-fi/ Disallow: /fo/ Disallow: /fo-fo/ Disallow: /fr/ Disallow: /gl/ Disallow: /gl-es/ Disallow: /gu/ Disallow: /gu-in/ Disallow: /he/ Disallow: /he-il/ Disallow: /hi/ Disallow: /hi-in/ Disallow: /hr/ Disallow: /hr-ba/ Disallow: /hr-hr/ Disallow: /hu/ Disallow: /hu-hu/ Disallow: /hy/ Disallow: /hy-am/ Disallow: /id/ Disallow: /id-id/ Disallow: /is/ Disallow: /is-is/ Disallow: /it/ Disallow: /ja/ Disallow: /ka/ Disallow: /ka-ge/ Disallow: /kk/ Disallow: /kk-kz/ Disallow: /kn/ Disallow: /kn-in/ Disallow: /ko/ Disallow: /kok/ Disallow: /kok-in/ Disallow: /ky/ Disallow: /ky-kg/ Disallow: /lt/ Disallow: /lt-lt/ Disallow: /lv/ Disallow: /lv-lv/ Disallow: /mi/ Disallow: /mi-nz/ Disallow: /mk/ Disallow: /mk-mk/ Disallow: /mn/ Disallow: /mn-mn/ Disallow: /mr/ Disallow: /mr-in/ Disallow: /ms/ Disallow: /ms-bn/ Disallow: /ms-my/ Disallow: /mt/ Disallow: /mt-mt/ Disallow: /nb/ Disallow: /nb-no/ Disallow: /nl/ Disallow: /nl-be/ Disallow: /nn-no/ Disallow: /ns/ Disallow: /ns-za/ Disallow: /pa/ Disallow: /pa-in/ Disallow: /pl/ Disallow: /pl-pl/ Disallow: /ps/ Disallow: /ps-ar/ Disallow: /pt/ Disallow: /qu/ Disallow: /qu-bo/ Disallow: /qu-ec/ Disallow: /qu-pe/ Disallow: /ro/ Disallow: /ro-ro/ Disallow: /ru/ Disallow: /sa/ Disallow: /sa-in/ Disallow: /se/ Disallow: /se-fi/ Disallow: /se-no/ Disallow: /se-se/ Disallow: /sk/ Disallow: /sk-sk/ Disallow: /sl/ Disallow: /sl-si/ Disallow: /sq/ Disallow: /sq-al/ Disallow: /sr-ba/ Disallow: /sr-sp/ Disallow: /sv/ Disallow: /sw/ Disallow: /sw-ke/ Disallow: /syr/ Disallow: /syr-sy/ Disallow: /ta/ Disallow: /ta-in/ Disallow: /te/ Disallow: /te-in/ Disallow: /th/ Disallow: /th-th/ Disallow: /tl/ Disallow: /tl-ph/ Disallow: /tn/ Disallow: /tn-za/ Disallow: /tr/ Disallow: /tr-tr/ Disallow: /ts/ Disallow: /tt/ Disallow: /tt-ru/ Disallow: /uk/ Disallow: /uk-ua/ Disallow: /ur/ Disallow: /ur-pk/ Disallow: /uz/ Disallow: /uz-uz/ Disallow: /vi/ Disallow: /vi-vn/ Disallow: /xh/ Disallow: /xh-za/ Disallow: /zh/ Disallow: /zu/ Disallow: /zu-za/ # XML sitemaps generated by update_sitemap.py (served from /sitemaps/.xml) # # Cada linha so sai se o ARQUIVO existir. `update_sitemap.py` nao escreve nada para # categoria vazia, entao declarar a lista fixa fazia lecursos, maratonapop, umgamer, # semfirula e rendaprime apontarem para 3 a 5 sitemaps que respondem 404 - 22 dos 50 # declarados na rede, medidos em 19/08/2026. `sitemaps_gerados` e o conjunto de # categorias achadas em disco para `g.website_id` (ver `_categorias_de_sitemap` no # `__init__.py`); quando ele vem `None` a leitura falhou e declara-se tudo, como antes. # # A flag do jogo NAO resolve isto: o robots.txt e por JOGO e o sitemap e por WEBSITE, # e um website (cardsrealm.com) reune varios jogos - `g.game_has_products` do jogo # padrao nao diz nada sobre o arquivo do website existir. Sitemap: https://umgamer.com/sitemaps/sitemap-4-articles-1.xml Sitemap: https://umgamer.com/sitemaps/sitemap-4-metagame-1.xml # Combos, ferramentas e desafios entraram em 18/08/2026. O de combos e o que # mais importa: sao ~5.200 paginas, a busca mostra 24 por vez e a paginacao # esta bloqueada aqui em cima - sem o sitemap nao havia caminho nenhum ate elas. Sitemap: https://umgamer.com/sitemaps/sitemap-4-tools-1.xml Sitemap: https://umgamer.com/sitemaps/sitemap-4-challenges-1.xml # O de referencias o `update_sitemap.py` ja gerava desde sempre e ninguem # declarava: o arquivo estava la, com as ~758 referencias, e o robots.txt so # falava de `/references/` para PROIBIR paginacao. Entrou em 18/08/2026. Sitemap: https://umgamer.com/sitemaps/sitemap-4-references-1.xml # RSS/Atom feeds are also valid "Sitemap:" entries per the sitemaps.org protocol and # help crawlers discover freshly-published content between XML sitemap regenerations. Sitemap: https://umgamer.com/en-us/en/feed.rss Sitemap: https://umgamer.com/pt-br/pt/feed.rss