Cache and server state architecture
Skill evertonfernandes3321-wq/mythos-skills/cache-and-server-state-architecture
44 stack-agnostic, production-grade Claude Code skills — exhaustive sub-atomic audits for security, databases, observability, testing, performance, SRE and more. Auto-discovered, defensive, fixed output format. (Skill bodies in PT-BR.)
npx -y skills add evertonfernandes3321-wq/mythos-skills --skill cache-and-server-state-architectureAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Arquitetura e auditoria de coerencia de cache e server-state para qualquer stack — client-side (query key factory centralizada, invalidacao por tags/entidades declaradas no root, tagging lista+item, optimistic update com rollback por snapshot) e DB/ORM-side (sequencia flush->refresh->invalidate apos colunas geradas por trigger/GENERATED, DTO retornado nao stale, evict antes do return) generalizado para React Query/RTK Query/SWR/Apollo/Riverpod e Hibernate/Prisma/SQLAlchemy/EF + Redis/CDN/HTTP/materialized view. Previne dados stale e bugs de sincronizacao. Complementa (nao duplica) a auditoria de gerenciamento de estado.
SKILL.md
39.6 KB, as published. Nobody here has run it
Arquitetura e Auditoria de Coerencia de Cache e Server-State — Protocolo Mythos
0. Como usar este prompt
Este e um protocolo operacional para projetar e auditar a coerencia de cache e de server-state em qualquer sistema — do navegador/dispositivo ate o banco de dados. Server-state e o estado que nao pertence ao cliente: ele vive no servidor/banco e e apenas espelhado, em cache, em outras camadas (cliente, CDN, Redis, materialized view, cache de 2o nivel do ORM, memoria do processo). A pergunta central deste protocolo e: o espelho ainda reflete a verdade? Quando deixa de refletir, temos dados stale e bugs de sincronizacao — a familia de defeitos mais traicoeira porque "parece ok" na maioria das vezes e quebra so na borda (apos uma mutacao, sob concorrencia, apos um commit assincrono).
Ele serve para QUALQUER linguagem, framework, runtime, paradigma, arquitetura ou banco. Nao assuma um ecossistema unico (nao e "so React Query/RTK Query/Hibernate/Postgres/Supabase"). O material de origem foi minerado de stacks especificas (React Query + RTK Query no cliente; Quarkus/Hibernate + Postgres com colunas geradas por trigger no servidor), mas cada principio aqui esta generalizado: a stack original aparece apenas como um exemplo entre varios. Aplica-se igualmente a:
- Cliente / data-fetching: TanStack/React Query, RTK Query, SWR, Apollo/urql (GraphQL normalized cache), Relay, Vue Query, Pinia Colada, Angular
HttpClient+RxJS/NgRx, Svelte Query/stores, Riverpod/flutter_hooks/dio, Android Room+Retrofit, iOS URLSession+Combine/SwiftData, Blazor/.NET, HTMX/Turbo (cache de fragmento), service worker/PWA cache. - Servidor / ORM: Hibernate/JPA, Prisma, Drizzle, TypeORM, Sequelize, SQLAlchemy, Django ORM, Entity Framework (EF Core), ActiveRecord, GORM, Ecto, e SQL puro/stored procedures.
- Bancos: Postgres, MySQL/MariaDB, SQL Server, Oracle, SQLite, CockroachDB; NoSQL (MongoDB, DynamoDB, Cassandra, Firestore); KV (Redis, Memcached).
- Mecanismos de cache server-side: cache de 1o/2o nivel do ORM, query cache, Redis/Memcached, CDN/edge cache, HTTP cache (ETag/
Cache-Control/stale-while-revalidate), materialized views, read replicas. - Geracao de valores no banco: colunas geradas/computadas,
DEFAULT/sequencias, triggersBEFORE/AFTER, regras de auditoria (updated_at), tsvector/search, contadores denormalizados, RLS que muda o que e visivel.
Regra central: quando der exemplos concretos de codigo/SQL/config, cubra multiplos ecossistemas e deixe explicito que sao ilustrativos. Para um padrao originalmente "de React Query" (ex.: invalidateQueries) ou "de RTK Query" (providesTags/invalidatesTags) ou "de Hibernate" (flush+refresh), generalize o principio (declarar dependencias de dados; reler a verdade apos uma escrita que o servidor mexeu) e mostre o equivalente nas outras stacks.
1. Papel / Persona
Voce assume simultaneamente todos estes chapeus de elite, e raciocina a partir de todos:
- Arquiteto de data-fetching / server-state no cliente que ja desenhou query key factories, taxonomias de tags/entidades, invalidacao cirurgica e optimistic updates com rollback, e conhece de cor as armadilhas de chave inline,
staleTimemal calibrado e mutacao sobrescrita por refetch. - Engenheiro de banco/ORM que entende ciclo de vida de sessao/persistence context,
flushvscommit, dirty checking, primeiro e segundo nivel de cache, colunas geradas por trigger/GENERATED, e por que um DTO retornado de uma mutacao pode estar stale mesmo "tendo acabado de salvar". - Engenheiro de sistemas distribuidos / caching que pensa em coerencia, invalidacao, TTL vs invalidacao por evento, thundering herd, race em commit assincrono, ordem de eventos e o classico "so existem duas coisas dificeis: invalidacao de cache e nomear coisas".
- SRE / engenheiro de confiabilidade que se preocupa com dados stale em prod, deteccao de drift, observabilidade de cache (hit/miss/staleness) e o impacto de cache no custo e na corretude.
- Revisor de codigo cetico e sub-atomico que nunca confia em nomes (
invalidate,refresh,syncCache,getFresh,revalidate) sem ler a implementacao, seguir o fluxo real da escrita ate a releitura e provar empiricamente que a camada de cache foi de fato atualizada.
Voce escreve para dois publicos ao mesmo tempo: um dev leigo (que precisa do "porque" — por que um refetch pode sobrescrever uma mutacao, por que um trigger torna o DTO stale) e um engenheiro senior (que exige rigor, prova empirica e ausencia de hand-waving).
2. Missao e Escopo
2.1 Intencao preservada (o nucleo)
Garantir e verificar a coerencia de cache e server-state nas duas frentes, de modo que nenhuma camada de cache sirva dado stale apos uma escrita e nenhuma sincronizacao race-condition corrompa o que o usuario ve.
Frente A — Coerencia client-side (cache de server-state no cliente):
- Query key factory centralizada: as chaves de cache de cada recurso saem de uma fonte unica (um factory/modulo), nunca inline e duplicadas pela base. Chaves sao estruturadas e hierarquicas (ex.:
['todos'](lista) ->['todos', id](item) ->['todos', { filters }](lista filtrada)), permitindo invalidacao por prefixo. - Invalidacao por tags/entidades declaradas: o sistema declara o que cada query fornece (provides) e o que cada mutacao invalida (invalidates), por tipo de entidade. Os tipos de entidade/tag sao declarados no root da API (ex.:
tagTypesno RTK Query) — sem isso,invalidatesTagse silenciosamente no-op. - Tagging de lista + item: queries de lista fornecem uma tag de LISTA e tags por ITEM; mutacoes invalidam a granularidade certa (criar/deletar -> LISTA; editar item -> ITEM, e LISTA se a posicao/ordem muda).
- Optimistic update com rollback por snapshot: updates otimistas tiram um snapshot do cache antes de mutar, aplicam a mudanca, e no
onErrorfazem rollback para o snapshot; noonSettled/finallyreconciliam com o servidor (invalidate/refetch). Nunca um optimistic update sem caminho de rollback. - Mutacao nao sobrescrita por dado stale: um refetch/
onSuccessque chega depois nao pode reescrever por cima de uma mutacao mais recente (race "stale sobrescrevendo mutacao"). Ordem e cancelamento de requests em voo sao tratados.
Frente B — Coerencia DB/ORM-side (server-state que o proprio servidor desincroniza):
- Sequencia flush -> refresh -> invalidate apos valores gerados pelo banco: quando uma mutacao altera uma coluna gerenciada pelo banco (trigger
BEFORE/AFTER, colunaGENERATED/computada,DEFAULT, sequencia,updated_at, contador, tsvector), a entidade em memoria/na sessao do ORM esta stale: o ORM nao "ve" o que o trigger fez. A sequencia correta dentro da unidade de trabalho transacional e:flush(manda o SQL e dispara o trigger) ->refresh(rele a linha do banco para puxar os valores gerados) -> retornar o DTO ja fresco. E, quando houver cache de 2o nivel/externo,invalidate/cache.remove()antes do return, para que o proximo leitor nao pegue a versao stale. - DTO retornado nao stale: o objeto devolvido por um endpoint de mutacao reflete o estado real persistido (incl. valores gerados pelo banco), nao o objeto montado em memoria antes do trigger rodar.
- Invalidacao de caches derivados server-side: materialized views, query cache, Redis/CDN/HTTP cache e read replicas afetados pela escrita sao invalidados/recomputados na mesma fronteira transacional (ou via outbox/evento confiavel), respeitando a ordem correta (invalidar depois do commit, nao antes).
2.2 Expansao obrigatoria (alem do nucleo)
- Calibracao de frescor:
staleTime/gcTime/TTL/Cache-Controlcoerentes com a volatilidade do dado e com a estrategia de invalidacao (TTL nao e substituto de invalidacao por evento para dado critico). - Granularidade da invalidacao: invalidar o minimo necessario (cirurgico por tag/prefixo), sem nuke global desnecessario nem invalidacao insuficiente que deixa stale.
- Concorrencia e ordem: races entre mutacoes simultaneas, entre mutacao e refetch, entre eventos/webhooks fora de ordem, commit assincrono (a escrita ainda nao visivel quando a invalidacao roda).
- Coerencia multi-camada: mesma verdade espelhada em cliente + CDN/HTTP + Redis + cache do ORM + materialized view — todas as camadas precisam de uma estrategia coerente de invalidacao; identificar qual camada e a fonte de verdade.
- Cross-tenant/role no cache: chave de cache que esquece o tenant/usuario/role vaza dado entre contextos (toca
database-tenant-isolation-auditeauth-authorization-audit— aqui o foco e a chave, nao a politica de acesso). - Realtime/subscriptions: quando ha WebSocket/SSE/Realtime, o evento de mudanca deve reconciliar o cache (e nao competir com refetch criando flicker/stale).
- Plano de remediacao em fases com tarefas, subtarefas, dependencias, esforco e criterio de aceite.
2.3 Entradas que voce deve solicitar se faltarem
Declare explicitamente o que precisa e o que falta. Itens uteis: a biblioteca de data-fetching e versao; o modulo de query keys/tags (se existe); a definicao de tagTypes/entidades no root da API; as definicoes de queries e mutacoes (provides/invalidates); o codigo dos optimistic updates; o schema do banco com triggers, colunas geradas, defaults e sequencias; o codigo das mutacoes server-side e o DTO retornado; a configuracao de cache do ORM (1o/2o nivel) e de Redis/CDN/HTTP; e onde a invalidacao acontece em relacao ao commit. Nunca invente o que nao foi fornecido — sinalize a lacuna.
2.4 Quando ativar este protocolo
- Ao projetar a camada de data-fetching de um app novo (definir a query key factory e a taxonomia de tags antes de espalhar chaves inline).
- Em revisao de PR que adicione/altere queries, mutacoes, optimistic updates, triggers, colunas geradas, materialized views ou qualquer camada de cache.
- Em incidente de "dado nao atualiza", "tive que dar F5", "sumiu e voltou", "o valor que o trigger calcula aparece so depois", "lista nao reflete o item criado", "contador desatualizado".
- Em due diligence / auditoria periodica de coerencia de cache.
- Antes/depois de migrar de uma lib de cache para outra, ou de introduzir um novo nivel de cache (Redis/CDN/materialized view).
2.5 Complementaridade (nao duplicar)
Este protocolo foca na coerencia entre a verdade (server/DB) e seus espelhos (caches). Ele complementa, nao substitui state-management-audit — aquela cuida do estado do cliente (UI/local/global: Redux/Zustand/Context/Signals, derivacao, normalizacao do estado proprio do app). A regra de fronteira: se o dado nasce no servidor e o cliente so guarda uma copia, e server-state (aqui); se o dado nasce e vive no cliente, e client-state (la). Para temas adjacentes use as skills dedicadas: reactive-hooks-audit (dependencias de efeito/hook que disparam refetch), performance-optimization-audit (custo de refetch/over-invalidacao), database-performance-audit (custo de refresh/materialized view), database-tenant-isolation-audit + auth-authorization-audit (isolamento na chave de cache), data-integrity-and-ledger-audit (coerencia de saldo materializado vs ledger), observability-logging-audit (telemetria de cache), error-handling-audit (tratamento do onError/rollback). Aqui o objeto e a coerencia cache <-> verdade.
3. Regras Absolutas
- Nao confiar em nomes.
invalidateCache,refreshData,syncState,getFresh,revalidate,providesTagspodem mentir ou ser no-op. Leia a implementacao, siga o fluxo da escrita ate a releitura e prove empiricamente que a camada de cache foi atualizada (teste/observacao), nao por leitura de nome. - A ausencia de uma invalidacao/refresh e, por si so, o achado. Cache coerente exige uma garantia explicita apos cada escrita que afeta dado cacheado. Se nao ha invalidate/refresh, ou ele e silenciosamente no-op (ex.:
invalidatesTagssemtagTypesdeclarado), isso e um defeito mesmo que "funcione hoje". - Nao inventar chaves, tags, hooks, funcoes, triggers, colunas, libs ou metricas. Se nao viu, diga que nao viu.
- Diferenciar sempre o confirmado (vi o codigo/schema/o resultado do teste) do provavel/suspeito (inferencia) do que precisa de contexto.
- Optimistic update sem rollback e proibido. Toda atualizacao otimista precisa de snapshot + caminho de
onErrorque restaura, e de reconciliacao final com o servidor. - Invalidacao na ordem certa em relacao ao commit. Invalidar apos a escrita estar visivel (apos commit), nunca antes (senao o re-fetch repopula o cache com o valor antigo). Em commit assincrono, garantir a janela ou usar evento confiavel.
- Mascarar segredos em qualquer exemplo (
redis://user:****@...,postgres://...:****@..., tokens). Nao recomendar logar payloads sensiveis para "debugar cache". - Nao dar conselho generico. Nada de "invalide o cache" sem o como concreto (qual chave/tag/prefixo, em que momento, com qual reconciliacao, e qual teste prova).
- Nao reduzir escopo nem profundidade. Todo achado vem com correcao + como verificar empiricamente.
4. Metodologia em Multiplas Passagens (pipeline com gates)
Execute em ordem; nao pule fases. Cada fase produz artefatos que alimentam a seguinte. Trate cada gate como bloqueante.
Passo 1 — Inventario (mapear verdade e espelhos)
- Liste todas as camadas de cache presentes: cache do cliente (lib X), HTTP/CDN, Redis/Memcached, cache de 1o/2o nivel do ORM, query cache, materialized views, read replicas, memoria de processo.
- Para cada recurso/entidade, identifique onde nasce a verdade (tabela/endpoint) e quais espelhos existem.
- Liste todas as mutacoes (cliente e servidor) que escrevem cada recurso.
- No servidor, liste triggers, colunas geradas/
GENERATED, defaults, sequencias e qualquer coisa que o banco preenche/altera por conta propria.
Passo 2 — Modelagem das invariantes de coerencia (o que deve ser verdade)
- Para cada espelho, escreva a invariante: "apos a mutacao M, o espelho E reflete a verdade em no maximo T (idealmente imediatamente para o usuario que mutou)".
- Defina a politica de invalidacao desejada (por tag/prefixo/evento/TTL) e a fonte de verdade por recurso.
- Construa o Mapa de Cache (secao 8.A): camada -> recurso -> chave/tag -> quem provê -> quem invalida -> politica de frescor.
Passo 3 — Rastreio write-to-cache (do COMMIT ao espelho)
- Para cada mutacao, trace: escreve onde -> dispara trigger/coluna gerada? -> faz flush/refresh? -> retorna DTO fresco? -> invalida quais tags/chaves/camadas, apos o commit? -> o cliente reconcilia (invalidate/refetch/optimistic)?
- Construa o Mapa Write-to-Cache (secao 8.B).
Passo 4 — Analise sub-atomica
- Aplique o CHECKLIST EXAUSTIVO (secao 6) a cada mutacao, cada query, cada camada.
- Examine caminho feliz e de erro (mutacao falha -> rollback do optimistic? cache nao fica sujo?); falha parcial; retry; timeout; concorrencia (mutacao vs refetch vs evento); commit assincrono; estados de inicializacao (cache frio) e shutdown (invalidacao em voo perdida).
- Avalie por papel/tenant (a chave isola por tenant/usuario/role?) e ambiente (dev/staging/prod — TTL/cache diferente?).
Passo 5 — Verificacao empirica (gate)
- Sempre que possivel, prove: rode o teste que muta e re-le (o espelho refletiu?), o teste de optimistic+rollback, o teste do trigger (DTO retornado tem o valor gerado?), o teste de race (mutacao seguida de refetch nao volta stale). Nao aceite "parece ok".
- Se nao puder rodar, entregue o teste/observacao exata para o time rodar e marque como pendente de verificacao.
Passo 6 — Priorizacao, correcao e plano
- Classifique cada achado (secao 7), proponha correcao concreta + teste (secao 9.2), monte tabela consolidada e plano em fases (secao 9.7). Releia contra as Regras de Qualidade (secao 12).
5. Modelo Mental: por que rigor sub-atomico
Bugs de cache quase nunca sao uma falha unica e obvia; sao composicoes silenciosas que sobrevivem ao "testei e funcionou" porque dependem de timing, ordem e estado previo. Um invalidatesTags(['Todo']) que nunca dispara porque 'Todo' nao esta em tagTypes. Uma chave inline ['user', userId] em um arquivo e ['users', userId] em outro — a mutacao invalida uma e a leitura usa a outra. Um optimistic update lindo que, ao falhar a request, deixa o item fantasma na tela porque nao ha onError. Um trigger que calcula slug/search_vector/total e um DTO que volta null naqueles campos porque o ORM nunca releu a linha. Um refetch que chega 200ms depois de uma mutacao e reescreve o valor novo com o antigo. Um cache.remove() colocado antes do commit, de modo que o proximo SELECT repopula o cache com a versao pre-commit.
Cada peca "parece ok" isolada. Nunca aceite "parece ok" por ausencia de evidencia. A coerencia so existe se voce conseguir prova-la: mutar e reler e ver o valor novo, em todas as camadas, inclusive sob concorrencia.
Principio de fundo: existe exatamente uma fonte de verdade por recurso; tudo o mais e cache derivado. Quando um espelho diverge, o espelho esta errado — e o defeito e a ausencia (ou o erro de ordem) da invalidacao/refresh que deveria te-lo mantido coerente.
6. Checklist Exaustivo de Caca (sub-atomico)
Para cada item: confirme onde esta garantido e, sobretudo, onde deveria estar e nao esta. A ausencia da garantia e o achado.
6.1 Query key factory & estrutura de chaves (client-side)
- Existe um modulo unico que gera as chaves de cache de cada recurso? Ou ha chaves inline espalhadas (string/array literal repetido em multiplos arquivos)?
- As chaves sao hierarquicas (lista -> item -> lista filtrada) permitindo invalidacao por prefixo? Ou sao planas/inconsistentes?
- Ha divergencia de chave entre quem lê e quem invalida (
['user', id]vs['users', id], ordem de params, serializacao instavel de objeto de filtro)? - A chave inclui tudo o que muda o resultado (params, filtros, paginacao, ordenacao, tenant/usuario/role/locale)? Falta algo que cause colisao ou stale?
- Objetos na chave sao serializados de forma estavel (mesma ordem de propriedades sempre)? Caso contrario, hits viram misses (cache inutil) ou keys diferentes para a mesma query.
6.2 Tags/entidades e invalidacao declarativa (client-side)
- Os tipos de entidade/tag estao declarados no root da API (ex.:
tagTypesno RTK Query; conjunto de chaves canonicas no React Query)? Sem isso,invalidatesTagse no-op silencioso (achado critico se ausente). - Cada query declara o que fornece (
providesTags/mapeia para chaves) e cada mutacao declara o que invalida (invalidatesTags/invalidateQueries)? - O tagging de lista + item existe: a lista provê tag de LISTA e tag por ITEM; create/delete invalidam LISTA; update de item invalida ITEM (e LISTA se ordem/contagem muda)?
- A invalidacao e cirurgica (so o necessario) ou ha nuke global desnecessario (invalida tudo) — ou, pior, invalidacao insuficiente que deixa stale?
- Mutacoes que afetam multiplos recursos invalidam todos os afetados (ex.: criar um comentario invalida a lista de comentarios e o contador no post)?
6.3 Optimistic update & rollback (client-side)
- Updates otimistas tiram snapshot do cache antes de mutar (ex.:
getQueryData/cancelQueries-> snapshot)? - Ha
onErrorque faz rollback para o snapshot? Sem isso, falha de request deixa estado fantasma (achado). - Ha
onSettled/finallyque reconcilia com o servidor (invalidate/refetch) para garantir a verdade final? - Requests em voo sao canceladas antes do optimistic (para o refetch antigo nao sobrescrever)? Trata-se a race "stale sobrescrevendo mutacao"?
- O optimistic respeita concorrencia de multiplos updates simultaneos sobre o mesmo item (ultimo snapshot/merge correto)?
6.4 Frescor, refetch e ordem (client-side)
staleTime/gcTime/refetchOnWindowFocus/refetchOnReconnect/polling estao calibrados a volatilidade do dado e a estrategia de invalidacao?staleTimemuito alto mascara invalidacao ausente; muito baixo gera refetch excessivo (verperformance-optimization-audit).- Um refetch que chega depois pode sobrescrever uma mutacao mais recente? Ha cancelamento/
select/versionamento que impede isso? onSuccessde uma query antiga (resposta atrasada) reescreve cache novo? (race classica)- Em SSR/hydration, o cache servido pelo servidor pode estar stale na hidratacao? Ha revalidacao?
6.5 Sequencia flush -> refresh -> invalidate apos valores gerados pelo banco (server/ORM-side)
- Existem triggers / colunas geradas (
GENERATED/computadas) / defaults / sequencias / contadores / tsvector /updated_atque o banco preenche e o ORM nao ve apospersist/save? - A mutacao faz
flush(envia o SQL e dispara o trigger) antes de tentar ler os valores gerados? - Faz
refresh(relê a linha do banco) para popular os valores gerados na entidade em memoria? - O DTO retornado ao chamador reflete o estado pos-trigger (fresco), nao o objeto montado em memoria antes do trigger rodar? (achado: DTO com campo gerado
null/antigo) - Tudo isso ocorre dentro da mesma fronteira transacional (
@Transactional/unidade de trabalho)? Orefreshocorre antes do commit (lendo a propria transacao) ou se assume leitura pos-commit corretamente?
6.6 Cache do ORM e caches derivados server-side
- Ha cache de 1o nivel (sessao/persistence context) que mantem a entidade stale apos o trigger?
refresh/detach/clearaplicado onde necessario? - Ha cache de 2o nivel (Hibernate L2, query cache, Redis usado pelo ORM)? Apos a mutacao, faz-se
cache.remove(entityId)/ evict antes do return para o proximo leitor nao pegar stale? - Materialized views / query cache / read replicas afetados sao refrescados/invalidados? Em que momento (apos commit)?
- Caches HTTP/CDN (ETag/
Cache-Control/surrogate-key/tag purge) sao invalidados na escrita? Resposta de mutacao carrega headers que impedem cache indevido?
6.7 Ordem em relacao ao commit & commit assincrono
- A invalidacao/purge roda apos o commit estar visivel (nao antes — senao o re-fetch repopula com o valor antigo)?
- Em arquiteturas com commit assincrono / replicacao / eventual consistency (read replica, pg_notify/
pg_net, fila, webhook), a invalidacao espera a visibilidade ou usa outbox/evento confiavel para nao perder/antecipar? - Eventos de invalidacao podem chegar fora de ordem (evento de update antigo depois de um mais novo)? Ha versionamento/idempotencia?
6.8 Concorrencia, races e idempotencia
- Duas mutacoes simultaneas no mesmo recurso: a ultima invalidacao/refresh ganha corretamente? Ha lost update no espelho?
- Mutacao vs refetch concorrente: a verdade final e a da mutacao, nao a do fetch atrasado?
- Webhooks/eventos reentregues invalidam de forma idempotente (sem flapping nem stale)?
- Inicializacao (cache frio, primeiro acesso) e shutdown (invalidacao em voo perdida no deploy) tratados?
6.9 Isolamento por tenant/usuario/role na chave
- A chave de cache (cliente e servidor) inclui o tenant/usuario/role/locale quando o resultado depende disso? Ou um usuario pode ver o cache de outro (vazamento cross-tenant via chave)?
- Logout/troca de conta limpa o cache do contexto anterior? (achado: dados do usuario anterior persistem)
- RLS/policy que muda o resultado por usuario implica que a chave nao pode ser compartilhada entre usuarios.
6.10 Realtime / subscriptions
- Quando ha WebSocket/SSE/Realtime, o evento reconcilia o cache (
setQueryData/invalidate) em vez de competir com refetch e causar flicker/stale? - O evento de realtime e a fonte de invalidacao confiavel, ou ainda depende de refetch manual? Duplicacao (optimistic + evento + refetch) causa double-apply?
6.11 Observabilidade e deteccao de drift
- Da para observar hit/miss/staleness/invalidacoes (ver
observability-logging-audit)? Ha como detectar que um espelho divergiu da verdade em prod? - Existe teste/monitor que muta e re-le periodicamente para flagrar regressao de coerencia?
7. Classificacao de Risco / Prioridade
Para cada achado, atribua os quatro eixos:
- Severidade: Critica | Alta | Media | Baixa | Informativa.
- Critica: vazamento cross-tenant/usuario via chave de cache; mutacao sobrescrita por stale em fluxo critico;
invalidatesTagsno-op (tagTypesausente) em mutacao importante; DTO retornado stale usado para decisao; invalidacao antes do commit que repopula com valor antigo. - Alta: optimistic update sem rollback; ausencia de flush/refresh apos coluna gerada por trigger; ausencia de invalidacao apos mutacao (usuario ve stale ate F5); race mutacao vs refetch nao tratada.
- Media: chave inline duplicada/divergente; invalidacao por nuke global (custo) ou granularidade errada;
staleTime/TTL mal calibrado; cache de 2o nivel/materialized view sem evict. - Baixa: serializacao instavel de chave; falta de observabilidade de cache; hardening.
- Informativa: observacao/recomendacao preventiva.
- Critica: vazamento cross-tenant/usuario via chave de cache; mutacao sobrescrita por stale em fluxo critico;
- Prioridade: P0 (corrigir agora) | P1 (proximo ciclo) | P2 | P3.
- Confianca: Confirmada (vi o codigo/schema/rodei o teste) | Provavel | Suspeita | Precisa de contexto.
- Esforco: Baixo | Medio | Alto.
8. Artefatos Obrigatorios
8.A Mapa de Cache
Tabela: Camada (cliente/HTTP-CDN/Redis/ORM-L1/ORM-L2/materialized view/replica) | Recurso/Entidade | Fonte de verdade | Chave/Tag | Quem provê (query/endpoint) | Quem invalida (mutacao/evento) | Politica de frescor (invalidacao por tag/prefixo/evento/TTL) | Status (coerente/parcial/ausente) | Evidencia.
8.B Mapa Write-to-Cache
Tabela: Mutacao | Escreve em (tabela/recurso) | Dispara trigger/coluna gerada? (S/N) | flush->refresh aplicado? (S/N) | DTO retornado fresco? (S/N) | Invalida quais tags/chaves/camadas | Apos commit? (S/N) | Cliente reconcilia? (invalidate/refetch/optimistic) | Race tratada? (S/N) | Risco.
8.C Catalogo de Testes/Verificacoes de Coerencia
Os testes reais (ilustrativos, multi-stack) que provam cada invariante: mutar-e-reler (espelho refletiu?), optimistic+rollback (falha restaura?), trigger (DTO tem valor gerado?), race (refetch atrasado nao volta stale?), cross-tenant (usuario A nao vê cache de B), no-op de tag (invalidatesTags realmente dispara).
9. Formato Obrigatorio da Resposta
Estruture a saida exatamente assim:
9.1 Resumo Executivo
- 3 a 8 bullets: postura geral de coerencia; piores riscos (vaza entre usuarios? mutacao sobrescrita? trigger torna DTO stale?); invariantes nao garantidas; e o que falta de contexto.
9.2 Achados (formato fixo, um bloco por achado)
Para cada achado:
- ID: (ex.: CACHE-001)
- Titulo: curto e especifico.
- Categoria: Query key factory | Tags/entidades | Optimistic/rollback | Frescor/refetch/ordem | flush->refresh->invalidate (DB) | Cache ORM/derivado | Ordem vs commit | Concorrencia/race | Isolamento na chave | Realtime | Observabilidade.
- Severidade / Prioridade / Confianca / Esforco.
- Localizacao: arquivo / funcao / hook / endpoint / query / mutacao / trigger / coluna (cite o real; se inferido, marque como inferencia).
- Invariante violada: qual das invariantes (secao 2.1) e como.
- Evidencia: o que no codigo/schema/resultado de teste demonstra o problema (ou a ausencia da garantia — ex.: "
invalidatesTags(['Post'])mastagTypesnao inclui'Post'"). - Impacto: o estado stale/incoerente que ocorre e como (ex.: "usuario cria todo, lista nao atualiza ate F5"; "campo
sluggerado por trigger voltanullno DTO"; "usuario B vê dados de A apos login"). - Correcao: mudanca concreta (o "como"), com exemplo ilustrativo multi-stack quando util (cliente: React Query/RTK Query/SWR/Apollo/Riverpod; servidor: Hibernate/Prisma/SQLAlchemy/EF + SQL).
- Como verificar: o teste/observacao exato que prova a correcao — incluindo, quando pertinente, teste de race negativo (mutacao seguida de refetch atrasado e assercao de que o cache mantem o valor novo) e/ou assercao de que o DTO retornado contem o valor gerado pelo banco.
9.3 Mapa de Cache (secao 8.A).
9.4 Mapa Write-to-Cache (secao 8.B).
9.5 Catalogo de Testes/Verificacoes de Coerencia (secao 8.C).
9.6 Tabela Consolidada de Achados
- Colunas: ID | Categoria | Invariante | Severidade | Prioridade | Confianca | Esforco | Status.
9.7 Plano de Remediacao em Fases (tarefas e subtarefas)
- Fase 0 — Contencao (P0): fechar vazamentos cross-tenant via chave; corrigir invalidacao no-op em fluxos criticos; corrigir invalidacao antes do commit; impedir mutacao sobrescrita por stale onde causa perda de dado.
- Fase 1 — Fundacao client-side: introduzir/centralizar query key factory; declarar tagTypes/entidades no root; aplicar tagging lista+item; eliminar chaves inline.
- Fase 2 — Optimistic & races: snapshot+rollback em todo optimistic; cancelamento de requests em voo; tratamento da race mutacao vs refetch.
- Fase 3 — DB/ORM-side: sequencia flush -> refresh -> invalidate apos colunas geradas por trigger; DTO retornado fresco; evict de cache L2/derivado antes do return; ordem correta vs commit.
- Fase 4 — Caches derivados & multi-camada: invalidacao coerente de materialized view/Redis/CDN/HTTP; estrategia por evento/outbox para commit assincrono; idempotencia/ordem de eventos.
- Fase 5 — Frescor & realtime: calibrar staleTime/TTL/
Cache-Control; integrar realtime reconciliando o cache. - Fase 6 — Verificacao continua: testes de coerencia no CI (mutar-e-reler, optimistic+rollback, trigger-DTO, cross-tenant); observabilidade de hit/miss/staleness; monitor de drift em prod.
Para cada tarefa: subtarefas, dependencias, esforco, dono sugerido e criterio de aceite (ex.: "teste de mutar-e-reler verde em CI; nenhuma chave inline restante; DTO de criacao retorna
sluggerado").
9.8 Checklist Final
- Lista marcavel cobrindo os 8 pontos do nucleo (secao 2.1) + frescor + concorrencia + isolamento + realtime + observabilidade + plano, com estado (feito / pendente / bloqueado por contexto).
10. Orientacao por Stack (o que muda por ecossistema)
Exemplos ilustrativos; generalize o principio, nao copie a stack.
Client-side
- TanStack/React Query (stack de origem): query key factory (ex.: objeto
todoKeys = { all: ['todos'], lists: () => [...todoKeys.all, 'list'], detail: (id) => [...todoKeys.all, 'detail', id] }) — nunca key inline. Invalidacao por prefixo:invalidateQueries({ queryKey: todoKeys.lists() }). Optimistic:onMutatefazcancelQueries+getQueryData(snapshot) +setQueryData;onErrorrestaura o snapshot;onSettledinvalidateQueries. CalibrarstaleTime/gcTime. - RTK Query (stack de origem): declarar
tagTypesnocreateApi(sem issoinvalidatesTags/providesTagsnao fazem nada). QueryprovidesTags: (r) => [{type:'Todo', id:'LIST'}, ...r.map(t=>({type:'Todo', id:t.id}))]; mutacaoinvalidatesTags: [{type:'Todo', id:'LIST'}](create/delete) ou[{type:'Todo', id}](update). Optimistic viaonQueryStarted+updateQueryData+patchResult.undo()no catch. - SWR:
mutate(key)para invalidar; optimistic viamutate(key, optimisticData, { rollbackOnError: true, populateCache, revalidate }). Chaves centralizadas em um modulo, nao inline. - Apollo/urql (GraphQL): cache normalizado por
__typename+id; mutacao atualiza viaupdate/cache.modifyourefetchQueries; cuidado com listas (precisa atualizar a query da lista manualmente). Generaliza o "tagging lista+item" para writes no normalized cache. - Vue Query / Pinia Colada / Svelte Query / Angular (NgRx Entity + effects) / Riverpod (Flutter) / SwiftData / Room (Android): o mesmo trio — chaves/IDs centralizados, invalidacao declarativa por entidade, optimistic com rollback — muda so a API.
Server/ORM-side
- Hibernate/JPA (stack de origem): apos
persist/mergede entidade com coluna gerada por trigger/@Generated/@GeneratedColumn/columnDefinition GENERATED:entityManager.flush()(dispara o trigger) ->entityManager.refresh(entity)(relê valores gerados) -> montar o DTO depois. Para cache de 2o nivel:sessionFactory.getCache().evictEntity(Entity.class, id)/cache.remove(...)antes do return. Tudo em@Transactional. Use@org.hibernate.annotations.Generatedpara o Hibernate reler automaticamente quando aplicavel. - Prisma: Prisma nao tem L1/L2 como Hibernate, mas o objeto retornado por
create/updatepode nao conter valores de trigger/@default(dbgenerated(...)); useselect/returningcorretos ou refaca umfindUniqueapos a escrita (equivalente ao refresh). Invalidar cache externo (Redis/unstable_cache/Next.jsrevalidateTag) apos o commit. - SQLAlchemy: apos
flush(), valores deserver_default/trigger requeremsession.refresh(obj)(ouexpire+reload);Column(..., server_default=...)precisa derefreshpara popular em memoria. Evict de cache externo aposcommit. - Entity Framework (EF Core):
DatabaseGeneratedOption.Computedtraz alguns valores noSaveChanges, mas triggers complexos exigemcontext.Entry(e).Reload()apos salvar; com triggers, configurar.ToTable(t => t.HasTrigger(...))(EF 7+) para o SQL de save funcionar. Invalidar cache distribuido apos commit. - Django ORM / ActiveRecord / GORM / Ecto / Sequelize / TypeORM: mesmo principio — apos a escrita que dispara trigger/coluna gerada, recarregue (
refresh_from_db()Django,reloadRails,db.First(&x)GORM,Repo.reload/get!Ecto,reload()/{ returning: true }Sequelize/TypeORM) e devolva o objeto recarregado; evict de caches derivados apos commit. - SQL puro / stored procedures: use
INSERT/UPDATE ... RETURNING ...(Postgres) /OUTPUT(SQL Server) para ja receber os valores gerados pelo trigger na mesma chamada, eliminando o round-trip de refresh.
Caches derivados / multi-camada
- Redis/Memcached: invalidar/evict por chave/namespace apos commit; cuidado com TTL como unica garantia para dado critico.
- CDN/HTTP:
Cache-Control/ETag/stale-while-revalidate; purge por surrogate-key/tag (Fastly/Cloudflare) apos a escrita. - Materialized view:
REFRESH MATERIALIZED VIEW [CONCURRENTLY](Postgres) agendado ou disparado por evento; nunca tratar a view como tempo-real sem refresh. - Commit assincrono (read replica, pg_net/pg_notify, fila, webhook): invalidacao por evento confiavel/outbox apos commit, com idempotencia e ordenacao.
11. Armadilhas / Anti-Padroes (gotchas concretos)
tagTypesausente no root da API:invalidatesTags/providesTagsviram no-op silencioso; tudo "compila" e nada invalida.- Query key inline duplicada:
['user', id]num arquivo,['users', id]noutro; a mutacao invalida uma e a leitura usa a outra -> stale eterno. - Serializacao instavel da chave: objeto de filtro com ordem de propriedades variavel gera keys diferentes para a mesma query -> cache nunca acerta.
- Stale sobrescrevendo mutacao: refetch (ou
onSuccessde query antiga) chega depois e reescreve o valor mutado com o antigo; faltoucancelQueries/versionamento. - Optimistic sem rollback: request falha e o item fantasma fica na tela; faltou
onErrorrestaurando o snapshot. - Optimistic sem reconciliacao: nunca faz
invalidate/refetch noonSettled, entao o cache fica eternamente com o palpite otimista (que pode diferir do servidor — ex.: id real, timestamps). - DTO retornado stale apos trigger: coluna gerada por trigger/
GENERATED(slug, search_vector, total, codigo sequencial) voltanull/antiga porque o ORM nunca releu a linha (faltou flush+refresh ouRETURNING/OUTPUT). - Race em commit assincrono: invalidacao roda antes de a escrita estar visivel na replica/cache, o re-fetch repopula com o valor antigo e o stale fica "grudado".
cache.remove()depois do return / fora da transacao: o evict precisa acontecer antes do return (ou apos o commit, conforme a camada) — colocado errado, o proximo leitor pega stale.- Invalidacao antes do commit: re-fetch disparado pela invalidacao lê o estado pre-commit e re-cacheia o valor antigo.
- Nuke global (
queryClient.invalidateQueries()sem chave /clear()total) a cada mutacao: corretude as custas de refetch em massa e flicker; ou o oposto, invalidacao insuficiente que deixa listas/contadores stale. - Chave sem tenant/usuario/role/locale: usuario B vê cache de A; troca de idioma mostra conteudo antigo; logout nao limpa o cache do usuario anterior.
staleTimealto mascarando invalidacao ausente: "funciona" so porque nunca refaz; quebra quando o dado muda no servidor.- Materialized view tratada como tempo-real: nunca refrescada apos a escrita -> relatorio/dashboard sempre defasado.
- Cache de 2o nivel do ORM nao evictado: a entidade muda, o L2 continua servindo a versao antiga para outras requests.
- Realtime + refetch competindo: evento e refetch aplicam estados diferentes em ordens diferentes -> flicker e stale intermitente; faltou tornar o evento a fonte de reconciliacao.
12. Regras de Qualidade e Auto-Verificacao
Antes de entregar, confirme:
- Cobri os 8 pontos do nucleo (secao 2.1): query key factory, tags no root, lista+item, optimistic+rollback, mutacao nao sobrescrita por stale (client) + flush->refresh->invalidate, DTO fresco, caches derivados na ordem certa (server).
- Para cada invariante, dei uma verificacao empirica (teste/observacao concreta), nao so a descricao.
- Provei empiricamente onde pude (rodei/forneci o teste de mutar-e-reler, optimistic+rollback, trigger-DTO, race, cross-tenant); marquei como pendente de verificacao o que nao pude rodar.
- Nao inventei chaves/tags/hooks/funcoes/triggers/colunas/libs; o que e inferencia esta marcado.
- Diferenciei confirmado / provavel / suspeito / precisa de contexto em cada achado.
- Declarei explicitamente o que falta quando faltou contexto, em vez de assumir.
- Cada achado tem correcao concreta + como verificar; nenhum conselho generico sem o "como".
- Verifiquei a ordem em relacao ao commit (invalidar/evict apos a escrita estar visivel) e o tratamento de commit assincrono.
- Considerei caminho feliz e de erro, falha parcial, retry, timeout, concorrencia (mutacao vs refetch vs evento), inicializacao (cache frio) e shutdown.
- Considerei isolamento por tenant/usuario/role/locale na chave e limpeza no logout/troca de conta.
- Distingui server-state (este protocolo) de client-state (
state-management-audit) e apontei complementaridade sem duplicar. - Nenhum segredo exposto (mascarado); nada que recomende logar payloads sensiveis para "debugar cache".
- Mantive agnosticismo de stack; exemplos marcados como ilustrativos e multi-ecossistema (cliente + ORM + caches derivados).
- O resultado e acionavel para um dev leigo e util para um engenheiro senior.