<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Guilherme Marucchi</title>
    <description>The latest articles on DEV Community by Guilherme Marucchi (@l00p4).</description>
    <link>https://dev.to/l00p4</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1328310%2Ff7fd3863-5e62-4389-a5a9-92e2a26338a4.jpeg</url>
      <title>DEV Community: Guilherme Marucchi</title>
      <link>https://dev.to/l00p4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/l00p4"/>
    <language>en</language>
    <item>
      <title>Regra escrita é regra que falha</title>
      <dc:creator>Guilherme Marucchi</dc:creator>
      <pubDate>Thu, 17 Sep 2026 13:15:13 +0000</pubDate>
      <link>https://dev.to/l00p4/regra-escrita-e-regra-que-falha-kp2</link>
      <guid>https://dev.to/l00p4/regra-escrita-e-regra-que-falha-kp2</guid>
      <description>&lt;p&gt;Toda migração grande produz uma pilha de "não faça X".&lt;/p&gt;

&lt;p&gt;Não misture os dois padrões no mesmo arquivo. Não crie mais arquivo no formato antigo. Não coloque componente&lt;br&gt;
novo dentro de tela velha. Não use valor de cor direto, use o token.&lt;/p&gt;

&lt;p&gt;Escrevemos essas regras num documento, com o motivo de cada uma, numeradas e datadas. O documento ficou bom.&lt;/p&gt;

&lt;p&gt;E eu sei exatamente o que acontece com ele: alguém lê na primeira semana, ninguém lê na terceira, e em dois&lt;br&gt;
meses uma pessoa nova entra no time e viola três regras no primeiro dia. Sem má vontade, sem descuido, só&lt;br&gt;
por não saber que existiam.&lt;/p&gt;

&lt;p&gt;Documento não escala. Ferramenta escala.&lt;/p&gt;

&lt;p&gt;Isto é sobre o que aconteceu quando paramos de escrever regras e começamos a fazer as ferramentas recusarem.&lt;/p&gt;


&lt;h2&gt;
  
  
  A regra que virou verificação de build
&lt;/h2&gt;

&lt;p&gt;A regra mais importante da migração era: &lt;strong&gt;os dois design systems não se misturam no mesmo arquivo.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O motivo é real. Os dois geram classes CSS com a mesma especificidade, e quando duas regras empatam quem&lt;br&gt;
vence é decidido por ordem de injeção. Que muda entre ambiente de desenvolvimento e build de produção. O&lt;br&gt;
resultado é aquele bug que funciona na sua máquina e quebra em produção, e que ninguém reproduz.&lt;/p&gt;

&lt;p&gt;Isso ficou escrito no documento por semanas. Dependia de todo mundo lembrar.&lt;/p&gt;

&lt;p&gt;Aí, corrigindo um problema completamente diferente, restringimos onde a ferramenta de CSS pode procurar&lt;br&gt;
classes. Ela passou a olhar só o diretório do código novo, em vez do projeto inteiro.&lt;/p&gt;

&lt;p&gt;O efeito colateral foi melhor que a correção: &lt;strong&gt;classe do padrão novo escrita dentro de um arquivo do padrão&lt;br&gt;
antigo simplesmente não é gerada.&lt;/strong&gt; O componente aparece sem estilo nenhum. A pessoa percebe na hora, antes&lt;br&gt;
de commitar, sem ter lido regra nenhuma.&lt;/p&gt;

&lt;p&gt;A regra saiu do documento e virou comportamento de build.&lt;/p&gt;


&lt;h2&gt;
  
  
  A regra que virou recusa da ferramenta
&lt;/h2&gt;

&lt;p&gt;A segunda regra: &lt;strong&gt;migração acontece por bloco completo.&lt;/strong&gt; Uma tela inteira por vez, nunca um componente&lt;br&gt;
solto dentro de uma tela antiga.&lt;/p&gt;

&lt;p&gt;O motivo é o mesmo de antes. Um componente novo dentro de um container antigo é exatamente a mistura que a&lt;br&gt;
primeira regra proíbe.&lt;/p&gt;

&lt;p&gt;O projeto tem um gerador de componentes: você roda um comando, responde onde quer criar, e ele monta a&lt;br&gt;
estrutura de arquivos. Todo mundo usa, porque é mais rápido que criar à mão.&lt;/p&gt;

&lt;p&gt;Colocamos a regra ali dentro. Hoje, se você tenta criar um componente dentro de uma tela que ainda não foi&lt;br&gt;
migrada, o gerador &lt;strong&gt;para antes de criar qualquer arquivo&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A tela "x" ainda nao foi migrada para o design system novo.
Criar componente novo dentro de tela legada viola a regra de migracao
por bloco completo. Ver o documento de migracao.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare no que mudou. Antes, a regra dependia de a pessoa conhecer o documento. Agora, a ferramenta a&lt;br&gt;
apresenta &lt;strong&gt;no exato momento em que ela é relevante&lt;/strong&gt; e explica o porquê, para não parecer arbitrária.&lt;/p&gt;

&lt;p&gt;E tem um ganho que não estava planejado: como a ferramenta precisa saber quais telas foram migradas, essa&lt;br&gt;
lista virou um dado real no projeto, em vez de conhecimento na cabeça de alguém. A lista de configuração&lt;br&gt;
passou a ser o registro do que já mudou.&lt;/p&gt;


&lt;h2&gt;
  
  
  O contra-exemplo: a regra que continuou só escrita
&lt;/h2&gt;

&lt;p&gt;Uma das regras não tem nenhuma ferramenta atrás: &lt;strong&gt;nenhum arquivo novo no formato antigo.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O indicador da migração é a contagem desses arquivos. Ele só deveria descer.&lt;/p&gt;

&lt;p&gt;Fui conferir depois de algumas semanas. Tinha &lt;strong&gt;subido&lt;/strong&gt;: de 437 para 449.&lt;/p&gt;

&lt;p&gt;Não era vazamento da fronteira. Eram doze arquivos nascidos em funcionalidades que já estavam na esteira de&lt;br&gt;
produção, começadas antes de a fundação existir. Dez deles numa tela inteiramente nova, construída em&lt;br&gt;
paralelo enquanto eu preparava a base.&lt;/p&gt;

&lt;p&gt;Nada disso é erro de ninguém. É a consequência de migrar um sistema &lt;strong&gt;sem parar a entrega&lt;/strong&gt;. De um lado&lt;br&gt;
alguém prepara a fundação, do outro o produto continua saindo. Foi uma decisão, não um acidente.&lt;/p&gt;

&lt;p&gt;Mas o número deixou clara a diferença entre as duas categorias de regra:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Regra&lt;/th&gt;
&lt;th&gt;Estado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Não misture os padrões&lt;/td&gt;
&lt;td&gt;ferramenta recusa&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Não crie componente em tela não migrada&lt;/td&gt;
&lt;td&gt;ferramenta recusa&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Não crie arquivo no formato antigo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;só documento&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Adivinha qual foi violada.&lt;/p&gt;


&lt;h2&gt;
  
  
  A regra escrita que funcionou, porque tinha prazo
&lt;/h2&gt;

&lt;p&gt;Não é que documento nunca sirva. Serve como base.&lt;/p&gt;

&lt;p&gt;O menu novo tem 21 itens, e por semanas alguns não tinham destino definido. Em vez de deixar o link vazio,&lt;br&gt;
criamos uma constante com nome próprio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ROTA_PENDENTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O comentário dela dizia o que fazer com ela: &lt;code&gt;grep ROTA_PENDENTE src&lt;/code&gt; lista o que ainda falta, e essa é a&lt;br&gt;
lista de trabalho da task de rotas.&lt;/p&gt;

&lt;p&gt;Convenção pura. Nenhuma ferramenta atrás, dependendo de alguém rodar o grep. E funcionou, por um motivo que&lt;br&gt;
as outras regras escritas não tinham: &lt;strong&gt;ela era autoliquidante.&lt;/strong&gt; Cada item que ganhava destino saía da lista.&lt;br&gt;
Quando o último saiu, a constante não tinha mais razão de existir, e apaguei ela junto com o ramo de código&lt;br&gt;
que ela sustentava.&lt;/p&gt;

&lt;p&gt;A vigilância não desapareceu. Mudou de forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;todosOsItens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rota&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(\/&lt;/span&gt;&lt;span class="sr"&gt;app|https:&lt;/span&gt;&lt;span class="se"&gt;\/\/)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Item novo que entre com atalho, string vazia ou qualquer marcador de pendência quebra esse teste. Mesma&lt;br&gt;
proteção, agora sem depender de ninguém lembrar de nada.&lt;/p&gt;

&lt;p&gt;A diferença entre esta regra e a que foi violada é o prazo. Regra escrita para valer enquanto a migração&lt;br&gt;
durar é aposta na memória do time, e essa aposta perde. Regra escrita para valer até uma lista zerar é&lt;br&gt;
combinado com data, e data se cumpre.&lt;/p&gt;


&lt;h2&gt;
  
  
  Quando &lt;em&gt;não&lt;/em&gt; transformar a regra em bloqueio
&lt;/h2&gt;

&lt;p&gt;Aqui está a parte que eu quase errei.&lt;/p&gt;

&lt;p&gt;Bloquear a terceira regra é trivial. Cinco linhas num hook de commit resolvem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="nt"&gt;--diff-filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;A | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'\.styles\.ts$'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não fiz. E o motivo vale mais que a técnica.&lt;/p&gt;

&lt;p&gt;A primeira regra diz que componente novo não pode viver dentro de tela antiga. Então, se alguém precisa&lt;br&gt;
acrescentar um componente a uma tela legada e o formato antigo estiver bloqueado, sobram duas opções:&lt;br&gt;
&lt;strong&gt;migrar a tela inteira antes&lt;/strong&gt; ou &lt;strong&gt;ficar travado&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Migrar uma tela inteira pode ser semanas de trabalho não planejado, no meio de uma entrega com data.&lt;/p&gt;

&lt;p&gt;Ou seja: o bloqueio técnico transferiria um custo grande para pessoas que não participaram da decisão. Isso&lt;br&gt;
não é ajuste de ferramenta, é mudança de política de entrega. Política se acorda, não se impõe por um&lt;br&gt;
hook que aparece um dia sem aviso.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O critério que eu extraí disso:&lt;/strong&gt; transforme a regra em bloqueio quando cumprir a regra custa quase nada.&lt;br&gt;
Quando cumprir custa caro, o bloqueio precisa vir depois do acordo, não no lugar dele.&lt;/p&gt;

&lt;p&gt;Guardrail imposto sobre custo alto não produz conformidade. Produz gente procurando como contornar. E quem&lt;br&gt;
contorna uma vez contorna sempre.&lt;/p&gt;




&lt;h2&gt;
  
  
  O dia em que o guardrail me barrou
&lt;/h2&gt;

&lt;p&gt;Vale contar a vez em que ele me pegou, porque minha primeira reação estava errada.&lt;/p&gt;

&lt;p&gt;O pre-commit barrou um commit meu pelo mínimo de cobertura: 66,66% de linhas contra os 70% exigidos.&lt;/p&gt;

&lt;p&gt;Achei que era formalidade. Eu tinha mexido em três drawers de uma tela, e os testes que já existiam&lt;br&gt;
renderizavam todos eles. Fui olhar o relatório inteiro: cobertura de funções em 40%.&lt;/p&gt;

&lt;p&gt;Os testes montavam os drawers e paravam ali. Nenhum clicava em fechar. Então os três callbacks que avisam&lt;br&gt;
qual drawer foi fechado nunca tinham sido executados uma única vez. Se alguém trocasse as chaves entre si,&lt;br&gt;
fechar um drawer fecharia outro, e a suíte continuaria verde.&lt;/p&gt;

&lt;p&gt;Escrevi cinco testes. A cobertura foi para 85,71%, e um deles hoje afirma exatamente aquilo: cada botão de&lt;br&gt;
fechar avisa a chave certa.&lt;/p&gt;

&lt;p&gt;O hook não me barrou por formalidade. Me barrou porque faltava teste de verdade, e a porcentagem era o único&lt;br&gt;
sintoma visível de uma falha que eu não tinha percebido lendo o código.&lt;/p&gt;

&lt;p&gt;Foi também o caso em que cumprir a regra custava trinta minutos, porque o que faltava era teste do que eu&lt;br&gt;
mesmo tinha acabado de tocar. É exatamente por isso que ela deve ser bloqueio.&lt;/p&gt;




&lt;h2&gt;
  
  
  A lição aprendida
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Documentação é para explicar o porquê. Ferramenta é para garantir o quê.&lt;/strong&gt; Documento explica bem e garante&lt;br&gt;
mal. Quando eu escrevo uma regra num documento, o que estou realmente fazendo é apostar na memória coletiva do&lt;br&gt;
time. E essa aposta perde no longo prazo, sempre.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A melhor mensagem de erro é a que chega no momento certo.&lt;/strong&gt; A mesma frase, lida num documento em janeiro,&lt;br&gt;
não impede nada. Impressa pela ferramenta no segundo em que você tenta fazer a coisa errada, impede tudo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guardrail é gentileza, não desconfiança.&lt;/strong&gt; Ele não existe porque as pessoas são descuidadas. Existe porque&lt;br&gt;
ninguém deveria precisar carregar na cabeça o motivo de cada decisão tomada há três meses por outra pessoa.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Terceiro de três textos sobre migrar um design system em produção sem parar a entrega. Os outros são sobre um&lt;br&gt;
&lt;a href="https://dev.to/l00p4/-instalar-uma-biblioteca-de-css-quase-apagou-um-botao-do-sistema-4ohj"&gt;botão que quase desapareceu ao instalar uma biblioteca de CSS&lt;/a&gt;, e sobre &lt;a href="https://dev.to/l00p4/duas-identidades-visuais-no-mesmo-sistema-e-a-troca-que-custou-quatro-linhas-1jem"&gt;conviver com duas identidades visuais&lt;br&gt;
ao mesmo tempo&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
      <category>tools</category>
    </item>
    <item>
      <title>Duas identidades visuais no mesmo sistema, e a troca que custou quatro linhas</title>
      <dc:creator>Guilherme Marucchi</dc:creator>
      <pubDate>Tue, 08 Sep 2026 14:10:37 +0000</pubDate>
      <link>https://dev.to/l00p4/duas-identidades-visuais-no-mesmo-sistema-e-a-troca-que-custou-quatro-linhas-1jem</link>
      <guid>https://dev.to/l00p4/duas-identidades-visuais-no-mesmo-sistema-e-a-troca-que-custou-quatro-linhas-1jem</guid>
      <description>&lt;p&gt;No meio de uma migração de design system, a marca mudou.&lt;/p&gt;

&lt;p&gt;Não era o plano. O plano era trocar a base técnica dos componentes. O antigo saindo tela a tela, o novo&lt;br&gt;
entrando no lugar. Aí veio a informação de que a identidade visual também ia evoluir: cor primária diferente,&lt;br&gt;
neutros diferentes, tipografia diferente.&lt;/p&gt;

&lt;p&gt;Duas mudanças grandes ao mesmo tempo, num sistema com mais de 450 arquivos de estilo e mais de cem telas, sem&lt;br&gt;
poder parar a entrega de produto.&lt;/p&gt;

&lt;p&gt;Isto é o que fez a segunda mudança custar quatro linhas em vez de uma varredura.&lt;/p&gt;


&lt;h2&gt;
  
  
  O problema, sem a camada
&lt;/h2&gt;

&lt;p&gt;Num sistema comum, o componente sabe a cor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;o botão primário é laranja
o card tem fundo branco
a borda é cinza claro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Espalhe isso por algumas centenas de componentes e a troca de identidade vira uma varredura: abrir arquivo&lt;br&gt;
por arquivo, achar cada cor, trocar. E sempre escapa alguma. A que fica é a que ninguém vai encontrar até&lt;br&gt;
um usuário reclamar.&lt;/p&gt;

&lt;p&gt;O sistema já tinha um passo dado nessa direção: as cores estavam em variáveis CSS, não escritas à mão em cada&lt;br&gt;
lugar. Isso ajuda, mas não resolve. Porque a variável dizia &lt;strong&gt;qual cor é&lt;/strong&gt;, não &lt;strong&gt;para que ela serve&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;--marca-laranja-puro&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#f60&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o componente consumia isso direto. Se a marca deixasse de ser laranja, o nome mentia. E se você quisesse&lt;br&gt;
laranja em dois papéis diferentes: ação principal e destaque de aviso? Não havia como mudar um sem mudar&lt;br&gt;
o outro.&lt;/p&gt;


&lt;h2&gt;
  
  
  Duas camadas, e a distinção é tudo
&lt;/h2&gt;

&lt;p&gt;A separação que resolve é entre &lt;strong&gt;paleta&lt;/strong&gt; e &lt;strong&gt;papel&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paleta: o que a cor é.&lt;/strong&gt; Um dicionário de tintas. Não diz para que serve.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;--paleta-marca&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#f60&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--paleta-cinza-200&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#e5e5e5&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Papel: o que a cor significa.&lt;/strong&gt; Um dicionário de funções, apontando para o de tintas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;--primary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--paleta-marca&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;--border&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--paleta-cinza-200&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os componentes consomem &lt;strong&gt;só a segunda camada&lt;/strong&gt;. Nenhum componente sabe qual cor ele está usando; ele sabe&lt;br&gt;
que está pintando uma ação principal.&lt;/p&gt;

&lt;p&gt;Parece burocracia até você precisar trocar a identidade. Aí a troca acontece no lado direito de uma linha, e&lt;br&gt;
todos os componentes acompanham. Inclusive os que ainda não foram escritos.&lt;/p&gt;


&lt;h2&gt;
  
  
  O truque: construir a camada antes de as cores existirem
&lt;/h2&gt;

&lt;p&gt;Aqui está a parte que eu não teria pensado se não fosse a pressão de não ficar parado.&lt;/p&gt;

&lt;p&gt;Quando montamos a estrutura, o time de design ainda não tinha entregado a identidade nova. A tentação era&lt;br&gt;
esperar. Em vez disso, declaramos a camada de papéis inteira &lt;strong&gt;apontando para as cores antigas&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;--primary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--paleta-antiga-marca&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;--background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--paleta-antiga-fundo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Provisório de propósito. E não é rodeio. Tem duas razões concretas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Primeira: alguma coisa precisa estar lá.&lt;/strong&gt; Variável sem valor não renderiza nada, e o catálogo de&lt;br&gt;
componentes que adotamos vem com uma paleta padrão própria. Sem sobrescrever, o sistema inteiro renderizaria&lt;br&gt;
na cara genérica da biblioteca. Nem a identidade antiga, nem a nova.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Segunda, e é a que importa: com as cores antigas, dá para isolar a variável.&lt;/strong&gt; Montamos uma bancada com um&lt;br&gt;
componente antigo e um novo lado a lado. Se os dois aparecem na mesma cor, a corrente inteira funciona: &lt;br&gt;
token, mapeamento, geração de CSS, pixel na tela. Se aparecem diferentes, alguma coisa quebrou no meio. Com&lt;br&gt;
cores diferentes nos dois lados, não dá para saber se a diferença é bug ou é só a cor.&lt;/p&gt;

&lt;p&gt;As cores antigas viraram &lt;strong&gt;sinal de teste&lt;/strong&gt;, não escolha estética.&lt;/p&gt;

&lt;p&gt;Quando o design entregou a identidade nova, a implementação foi trocar o lado direito das declarações. A&lt;br&gt;
estrutura já estava provada.&lt;/p&gt;


&lt;h2&gt;
  
  
  Os dois cenários que a camada torna possíveis
&lt;/h2&gt;

&lt;p&gt;Com paleta e papel separados, existem duas trocas diferentes e a diferença entre elas é o que permite&lt;br&gt;
migrar sem quebrar nada.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trocar a paleta&lt;/strong&gt; muda os dois mundos juntos. O componente antigo lê a paleta direto; o novo lê o papel, que&lt;br&gt;
aponta para a paleta. Mudou a tinta, mudou tudo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trocar o papel&lt;/strong&gt; muda só o mundo novo. O componente antigo continua lendo a paleta antiga, intocado.&lt;/p&gt;

&lt;p&gt;O segundo é o que a coexistência precisa: &lt;strong&gt;a identidade nova entra nos componentes novos enquanto os antigos&lt;br&gt;
seguem como estão.&lt;/strong&gt; As duas gerações convivem, cada uma lendo a sua camada.&lt;/p&gt;


&lt;h2&gt;
  
  
  Onde o modelo cedeu
&lt;/h2&gt;

&lt;p&gt;Isso funcionou enquanto a migração só &lt;strong&gt;acrescentava&lt;/strong&gt;. Tela nova nascia lendo o papel, tela antiga seguia na&lt;br&gt;
paleta, e as duas não se cruzavam.&lt;/p&gt;

&lt;p&gt;Parou de valer no dia em que telas que já existiam tiveram que vestir a pele nova. Consolidamos cinco telas de&lt;br&gt;
área financeira numa página com abas, depois quatro de outra área. Não eram componentes novos: eram os mesmos&lt;br&gt;
de sempre, precisando de fundo e borda diferentes.&lt;/p&gt;

&lt;p&gt;Reescrever cada um na estrutura nova custaria semanas e não era o que estava sendo pedido. Então fizemos o que&lt;br&gt;
o modelo mandava não fazer: &lt;strong&gt;nove arquivos de estilo antigos passaram a ler a camada de papel.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* dentro de um componente antigo */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.menu-v2&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--card&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--sidebar-border&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso, "trocar o papel muda só o mundo novo" deixou de ser verdade. Mexer em &lt;code&gt;--card&lt;/code&gt; hoje afeta os dois&lt;br&gt;
lados.&lt;/p&gt;

&lt;p&gt;O que segurou a coexistência foi &lt;strong&gt;o portão mudar de natureza&lt;/strong&gt;. Antes ele era implícito, dado pela&lt;br&gt;
arquitetura: você estava protegido porque lia outra camada. Agora é explícito, numa classe no &lt;code&gt;body&lt;/code&gt; que só&lt;br&gt;
existe quando a flag do menu novo está ligada. Com a flag desligada, aquelas nove regras não casam com nada e&lt;br&gt;
o componente antigo renderiza exatamente como antes.&lt;/p&gt;

&lt;p&gt;Trocamos garantia estrutural por garantia condicional. É pior de auditar e melhor de entregar. E essa é a&lt;br&gt;
troca honesta: o modelo puro exigiria reescrever o componente antes de poder mudar a aparência dele, e isso&lt;br&gt;
não caberia no cronograma.&lt;/p&gt;


&lt;h2&gt;
  
  
  Um detalhe de CSS que me pegou
&lt;/h2&gt;

&lt;p&gt;Montei uma demonstração com botões para alternar entre os cenários e mostrar isso ao vivo. Aplicei as&lt;br&gt;
variáveis numa &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; que envolvia os componentes.&lt;/p&gt;

&lt;p&gt;Funcionou para um lado e não para o outro. Trocar o papel mudava o componente novo; trocar a paleta não&lt;br&gt;
mudava nada no novo.&lt;/p&gt;

&lt;p&gt;O motivo é uma sutileza que vale conhecer: &lt;strong&gt;a substituição do &lt;code&gt;var()&lt;/code&gt; acontece no elemento onde a&lt;br&gt;
propriedade é declarada, não onde ela é usada.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O papel estava declarado no &lt;code&gt;:root&lt;/code&gt;, apontando para a paleta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--paleta-marca&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--paleta-marca&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse momento, ali no &lt;code&gt;:root&lt;/code&gt;, o &lt;code&gt;--primary&lt;/code&gt; já foi resolvido para &lt;code&gt;#f60&lt;/code&gt;. O que desce por herança para os&lt;br&gt;
elementos filhos é &lt;strong&gt;a cor pronta&lt;/strong&gt;, não a fórmula. Sobrescrever &lt;code&gt;--paleta-marca&lt;/code&gt; numa &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; lá embaixo não&lt;br&gt;
tinha como voltar atrás e recalcular.&lt;/p&gt;

&lt;p&gt;Em produção isso não acontece, porque as duas camadas são declaradas no mesmo &lt;code&gt;:root&lt;/code&gt;. Trocar a paleta ali&lt;br&gt;
propaga de verdade. O erro era só da bancada, e a correção foi aplicar as variáveis no próprio &lt;code&gt;:root&lt;/code&gt;, que&lt;br&gt;
é o que espelha o comportamento real.&lt;/p&gt;


&lt;h2&gt;
  
  
  O nome do token é uma decisão de longo prazo
&lt;/h2&gt;

&lt;p&gt;Uma armadilha que aparece exatamente nesse momento: a tentação de marcar a geração no nome.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;--primary-v2&lt;/span&gt;
&lt;span class="nt"&gt;--marca-nova&lt;/span&gt;
&lt;span class="nt"&gt;--cor-primaria-2026&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parece organizado. É uma bomba-relógio: em dezoito meses a "v2" é a única que existe, e o nome mente para&lt;br&gt;
todo mundo que ler. Aí alguém cria a v3.&lt;/p&gt;

&lt;p&gt;A regra que sobrevive: &lt;strong&gt;nome de tinta descreve a cor; nome de papel descreve a função.&lt;/strong&gt; Nenhum dos dois&lt;br&gt;
carrega versão.&lt;/p&gt;

&lt;p&gt;Onde a versão aparece é no portão, e ali ela é bem-vinda: existe uma classe &lt;code&gt;menu-v2&lt;/code&gt; no &lt;code&gt;body&lt;/code&gt;, com o número&lt;br&gt;
no nome de propósito. A diferença é o tempo de vida. &lt;strong&gt;Token é vocabulário permanente&lt;/strong&gt;, e quando o nome mente&lt;br&gt;
a dívida fica para sempre. &lt;strong&gt;A classe é temporária por construção&lt;/strong&gt;: quando a migração terminar, ela sai e&lt;br&gt;
leva o número junto.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que não deu certo
&lt;/h2&gt;

&lt;p&gt;Duas coisas, para não parecer que foi tranquilo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A tipografia não cabe no mesmo modelo.&lt;/strong&gt; Cor é fácil de escopar: o componente novo lê o papel novo, o antigo&lt;br&gt;
lê a paleta antiga, e eles não se falam. Fonte é herdada. O texto que não declara família herda do &lt;code&gt;body&lt;/code&gt;, e&lt;br&gt;
trocar o padrão do &lt;code&gt;body&lt;/code&gt; mudaria a fonte de &lt;strong&gt;todo&lt;/strong&gt; o texto herdado de uma vez. Sem lista, sem teste que&lt;br&gt;
pegue.&lt;/p&gt;

&lt;p&gt;A saída foi escopar a fonte nova aos componentes novos por um atributo que só eles têm, e deixar a inversão&lt;br&gt;
para o fim da migração, quando o antigo não existir mais. Funciona, mas é remendo com data marcada, não&lt;br&gt;
elegância.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O contraste ficou abaixo do mínimo.&lt;/strong&gt; Medi os pares de cor da identidade nova contra o critério de&lt;br&gt;
acessibilidade: nenhum atinge o mínimo para texto pequeno, que é o tamanho do rótulo padrão dos botões. Levei&lt;br&gt;
ao design com os números; a decisão foi manter.&lt;/p&gt;

&lt;p&gt;Registro os dois porque é o que separa relato de propaganda. A camada de tokens resolveu o problema para o&lt;br&gt;
qual foi feita. Não resolveu tudo.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Segundo de três textos sobre migrar um design system em produção sem parar a entrega. O primeiro é sobre um&lt;br&gt;
&lt;a href="https://dev.to/l00p4/-instalar-uma-biblioteca-de-css-quase-apagou-um-botao-do-sistema-4ohj"&gt;botão que quase desapareceu ao instalar uma biblioteca de CSS&lt;/a&gt;. O próximo é sobre por que quase toda regra de&lt;br&gt;
migração que vive num documento acaba sendo violada, e o que fazer a respeito.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>design</category>
      <category>frontend</category>
      <category>ui</category>
    </item>
    <item>
      <title># Instalar uma biblioteca de CSS quase apagou um botão do sistema</title>
      <dc:creator>Guilherme Marucchi</dc:creator>
      <pubDate>Thu, 20 Aug 2026 11:52:58 +0000</pubDate>
      <link>https://dev.to/l00p4/-instalar-uma-biblioteca-de-css-quase-apagou-um-botao-do-sistema-4ohj</link>
      <guid>https://dev.to/l00p4/-instalar-uma-biblioteca-de-css-quase-apagou-um-botao-do-sistema-4ohj</guid>
      <description>&lt;p&gt;Eu tinha acabado de instalar o Tailwind em um sistema que roda sobre styled-components há anos. Build passou. Cinco mil e quinhentos testes, verdes. Novecentos e sessenta snapshots, intactos.&lt;/p&gt;

&lt;p&gt;Podia ter seguido em frente. Mas abri o CSS que o build tinha gerado só para ver como estava.&lt;/p&gt;

&lt;p&gt;Havia 41 classes utilitárias ali dentro. E eu não tinha escrito &lt;strong&gt;nenhuma&lt;/strong&gt; classe do Tailwind no projeto.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que estava acontecendo
&lt;/h2&gt;

&lt;p&gt;O Tailwind não sabe quais classes você vai usar. Ele descobre lendo os seus arquivos e procurando algo que&lt;br&gt;
pareça nome de classe. É por isso que ele é rápido: em vez de gerar milhares de regras e você jogar fora o&lt;br&gt;
que não usa, ele gera só o que encontrou.&lt;/p&gt;

&lt;p&gt;O detalhe é que essa leitura é &lt;strong&gt;textual&lt;/strong&gt;. Ele não entende TypeScript, não sabe o que é JSX, não distingue&lt;br&gt;
uma string de um comentário. Ele varre o arquivo procurando padrões que se pareçam com classes.&lt;/p&gt;

&lt;p&gt;E num projeto com styled-components, os arquivos de estilo são cheios de texto assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  display: flex;
  position: absolute;
  visibility: collapse;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para o Tailwind, aquele &lt;code&gt;flex&lt;/code&gt; é um candidato. &lt;code&gt;absolute&lt;/code&gt; também. E &lt;code&gt;collapse&lt;/code&gt; também.&lt;/p&gt;

&lt;p&gt;Eram esses os 41.&lt;/p&gt;




&lt;h2&gt;
  
  
  O problema não era o desperdício
&lt;/h2&gt;

&lt;p&gt;Oito quilobytes de CSS que ninguém usa é chato, não é grave. O problema apareceu quando fui cruzar as classes&lt;br&gt;
geradas com as que o sistema já usava de verdade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Doze colidiam.&lt;/strong&gt; E uma delas era esta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"collapse"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setIsOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um botão real, numa tela real, com uma classe chamada &lt;code&gt;collapse&lt;/code&gt; porque ele colapsa um painel.&lt;/p&gt;

&lt;p&gt;O Tailwind tinha gerado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.collapse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;visibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;collapse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em elemento que não é tabela, &lt;code&gt;visibility: collapse&lt;/code&gt; se comporta como &lt;code&gt;hidden&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aquele botão desapareceria da tela.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  "Mas o CSS antigo não venceria?"
&lt;/h2&gt;

&lt;p&gt;Foi a primeira coisa que eu pensei. As duas regras miram o mesmo elemento, e o styled-components injeta o CSS&lt;br&gt;
dele fora das cascade layers. O que, pela especificação, sempre ganha de quem está dentro de uma layer, como&lt;br&gt;
o Tailwind está.&lt;/p&gt;

&lt;p&gt;Só que a cascata não escolhe um vencedor por regra. &lt;strong&gt;Ela escolhe por propriedade.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A regra do sistema era assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nc"&gt;.collapse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;appearance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cinco propriedades. Nenhuma delas é &lt;code&gt;visibility&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Sem disputa, não há vencedor: as duas regras simplesmente &lt;strong&gt;se somam&lt;/strong&gt;. O &lt;code&gt;visibility: collapse&lt;/code&gt; do Tailwind&lt;br&gt;
entrava sem encontrar resistência.&lt;/p&gt;

&lt;p&gt;Essa é a parte que eu tinha entendido errado, e é a que mais vale levar daqui: &lt;em&gt;layer&lt;/em&gt; e especificidade só&lt;br&gt;
resolvem conflito &lt;strong&gt;na mesma propriedade&lt;/strong&gt;. Onde uma regra declara algo que a outra não declara, as duas&lt;br&gt;
valem.&lt;/p&gt;


&lt;h2&gt;
  
  
  Por que ninguém teria percebido
&lt;/h2&gt;

&lt;p&gt;É aqui que a coisa fica desconfortável.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;strong&gt;build&lt;/strong&gt; passa. É CSS válido&lt;/li&gt;
&lt;li&gt;Os &lt;strong&gt;testes&lt;/strong&gt; passam. Eles verificam comportamento e marcação, não estilo computado&lt;/li&gt;
&lt;li&gt;Os &lt;strong&gt;snapshots&lt;/strong&gt; passam. A marcação não muda — o botão continua no DOM, com a mesma classe&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;revisão de código&lt;/strong&gt; não pega. O diff mostra um arquivo de configuração de três linhas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Não existe ferramenta no caminho normal que veja isso. O único jeito de encontrar era fazer o que eu fiz por&lt;br&gt;
acaso: abrir o CSS gerado e olhar.&lt;/p&gt;

&lt;p&gt;E o mesmo mecanismo tinha produzido &lt;code&gt;.container { width: 100% }&lt;/code&gt;, que se aplicaria a 22 elementos espalhados&lt;br&gt;
por dez arquivos.&lt;/p&gt;


&lt;h2&gt;
  
  
  A correção, e o que ela revelou
&lt;/h2&gt;

&lt;p&gt;O Tailwind aceita desligar a varredura automática e declarar explicitamente onde ele pode procurar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;'tailwindcss/utilities.css'&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;@source&lt;/span&gt; &lt;span class="s2"&gt;'../components'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Segundo build: &lt;strong&gt;zero classes geradas a partir do código antigo. Zero colisões.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mas o que me fez gostar dessa correção não foi ela resolver o bug. Foi o efeito colateral.&lt;/p&gt;

&lt;p&gt;O projeto está numa migração gradual: um design system novo entrando enquanto o antigo sai, tela por tela. A&lt;br&gt;
regra número um dessa migração é que os dois não se misturem no mesmo arquivo — os dois geram classes com a&lt;br&gt;
mesma especificidade, e quem vence passa a depender de detalhes que ninguém controla.&lt;/p&gt;

&lt;p&gt;Essa regra estava num documento. Documento que alguém precisa ler, lembrar e aplicar.&lt;/p&gt;

&lt;p&gt;Com o &lt;code&gt;@source&lt;/code&gt; restrito, ela deixou de precisar disso: &lt;strong&gt;classe do padrão novo escrita dentro de um arquivo&lt;br&gt;
do padrão antigo simplesmente não é gerada.&lt;/strong&gt; O componente aparece sem estilo, a pessoa percebe na hora, e&lt;br&gt;
ninguém precisa ter lido nada.&lt;/p&gt;

&lt;p&gt;A regra saiu do documento e virou comportamento de build.&lt;/p&gt;


&lt;h2&gt;
  
  
  Não foi sorte
&lt;/h2&gt;

&lt;p&gt;Sei disso porque a mesma prática pegou um segundo problema, no mesmo dia.&lt;/p&gt;

&lt;p&gt;Os componentes que vêm do catálogo trazem classes de tema escuro de fábrica — coisas como&lt;br&gt;
&lt;code&gt;dark:bg-destructive/60&lt;/code&gt;. Vieram dez delas junto com os dois primeiros componentes.&lt;/p&gt;

&lt;p&gt;No comportamento padrão da ferramenta, o prefixo &lt;code&gt;dark:&lt;/code&gt; compila para:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou seja: &lt;strong&gt;essas dez regras passariam a valer sozinhas para todo usuário com o sistema operacional em tema&lt;br&gt;
escuro.&lt;/strong&gt; Num sistema que não tem tema escuro nenhum.&lt;/p&gt;

&lt;p&gt;Uma parcela enorme de gente usa o sistema em modo escuro. Todos eles veriam botões com tons ligeiramente&lt;br&gt;
diferentes, bordas trocadas e hovers estranhos.&lt;/p&gt;

&lt;p&gt;A correção é uma linha, que prende o prefixo a uma classe em vez de ao sistema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@custom-variant&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;dark&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como essa classe não existe no projeto, as dez regras ficam inertes. E no dia em que o tema escuro entrar,&lt;br&gt;
todas passam a valer de uma vez.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que eu levo disso
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Build verde não é verificação, é ausência de erro de compilação.&lt;/strong&gt; São coisas diferentes, e a distância&lt;br&gt;
entre elas é exatamente onde mora a classe de bug que ninguém encontra.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ler a saída da ferramenta é barato.&lt;/strong&gt; Os dois problemas apareceram em minutos, porque eu olhei o CSS&lt;br&gt;
gerado em vez de confiar no build. O custo de olhar é sempre menor que o custo de descobrir depois — e&lt;br&gt;
"depois" aqui significaria um chamado de usuário dizendo que não consegue mais abrir uma tela.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A melhor correção é a que transforma a regra em comportamento.&lt;/strong&gt; Toda migração produz um monte de "não faça&lt;br&gt;
X". Cada uma dessas regras depende de alguém lembrar, e memória de time não escala. Quando dá para fazer a&lt;br&gt;
ferramenta recusar, a regra para de ser combinada e passa a ser verdade.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Este é o primeiro de três textos sobre migrar um design system num sistema em produção sem parar a entrega.&lt;br&gt;
O próximo é sobre conviver com duas identidades visuais ao mesmo tempo, e como uma camada de tokens&lt;br&gt;
transformou uma troca de marca em quatro linhas alteradas.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>frontend</category>
      <category>software</category>
      <category>webdev</category>
    </item>
    <item>
      <title># Feature Flags em React/Next.js: Guia Completo com ConfigCat e Context API</title>
      <dc:creator>Guilherme Marucchi</dc:creator>
      <pubDate>Tue, 19 May 2026 10:52:39 +0000</pubDate>
      <link>https://dev.to/l00p4/-feature-flags-em-reactnextjs-guia-completo-com-configcat-e-context-api-4716</link>
      <guid>https://dev.to/l00p4/-feature-flags-em-reactnextjs-guia-completo-com-configcat-e-context-api-4716</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Se você já passou por alguma dessas situações, este artigo é pra você:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Precisou fazer rollback de um deploy e isso &lt;strong&gt;bloqueou toda a equipe&lt;/strong&gt; de subir código&lt;/li&gt;
&lt;li&gt;Teve &lt;strong&gt;conflitos intermináveis&lt;/strong&gt; na branch develop porque várias features estavam sendo desenvolvidas ao mesmo tempo&lt;/li&gt;
&lt;li&gt;Quis testar uma funcionalidade em produção &lt;strong&gt;apenas com um grupo específico&lt;/strong&gt; de usuários antes de liberar pra todos&lt;/li&gt;
&lt;li&gt;Descobriu um bug crítico em produção e precisou esperar um novo deploy pra resolver&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feature Flags (ou Feature Toggles) resolvem todos esses problemas. Neste guia, vou mostrar passo a passo como implementei feature flags em uma aplicação Next.js usando &lt;strong&gt;ConfigCat&lt;/strong&gt; como serviço externo e &lt;strong&gt;React Context API&lt;/strong&gt; como camada de abstração — uma arquitetura desacoplada, escalável e pronta pra produção.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que são Feature Flags?
&lt;/h2&gt;

&lt;p&gt;Feature Flags são interruptores que permitem ligar e desligar funcionalidades da sua aplicação &lt;strong&gt;sem precisar fazer deploy&lt;/strong&gt;. O código da feature já está em produção, mas só é executado quando a flag está ativa.&lt;/p&gt;

&lt;p&gt;Pense assim: é como ter um painel de controle onde você decide, em tempo real, o que cada usuário vê na aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  O que você ganha com isso?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Deploy contínuo sem medo&lt;/strong&gt; — suba o código com a feature desligada&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Teste em produção com segurança&lt;/strong&gt; — ligue apenas pro seu usuário&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Kill switch instantâneo&lt;/strong&gt; — desligou a flag, a feature some em segundos&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Rollout gradual&lt;/strong&gt; — libere pra 10%, depois 50%, depois 100%&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Sem conflitos de branch&lt;/strong&gt; — todo mundo sobe pra main/develop, a flag controla quem vê o quê&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Por que ConfigCat?
&lt;/h2&gt;

&lt;p&gt;Existem várias ferramentas de feature flags no mercado (LaunchDarkly, Unleash, Split.io). Escolhi o ConfigCat por:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Interface intuitiva&lt;/strong&gt; — dashboard simples e direto ao ponto&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suporte nativo a React&lt;/strong&gt; — SDK com Provider e hooks prontos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Targeting avançado&lt;/strong&gt; — controle por usuário, atributos customizados, porcentagem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plano gratuito generoso&lt;/strong&gt; — suficiente pra começar&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polling automático&lt;/strong&gt; — atualiza os valores das flags periodicamente sem você precisar fazer nada&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Arquitetura da Solução
&lt;/h2&gt;

&lt;p&gt;A decisão mais importante da implementação: &lt;strong&gt;não acoplar a aplicação ao ConfigCat&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Se amanhã você precisar trocar de ferramenta, só altera o Provider. Nenhum componente da aplicação sabe que o ConfigCat existe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estrutura de pastas
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── utils/consts/
│   └── featureFlags.ts          # Constantes das flags + SDK keys
├── providers/feature-flags/
│   └── featureFlagsContext.tsx   # Context + Provider + sincronização
└── pages/
    └── _app.tsx                 # Provider na árvore de componentes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fluxo da arquitetura
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ConfigCat (serviço externo)
    ↓ polling a cada N segundos
ConfigCatReactProvider (engine — busca, cache, polling)
    ↓
ConfigCatSync (sincroniza user + busca flags boolean e string + escuta mudanças)
    ↓ armazena no useState
FeatureFlagsContext.Provider (Context próprio do projeto)
    ↓ expõe via useContext
Componentes (consomem com getFlag ou getStringFlag, não sabem que ConfigCat existe)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Implementação Passo a Passo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Instalação
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;configcat-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Constantes tipadas
&lt;/h3&gt;

&lt;p&gt;Primeiro, crie as constantes das flags e as SDK keys. A implementação suporta dois tipos de flags: &lt;strong&gt;boolean&lt;/strong&gt; (liga/desliga) e &lt;strong&gt;string&lt;/strong&gt; (valor variável, útil para A/B testing e conteúdo dinâmico).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/utils/consts/featureFlags.ts&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;featureFlags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;SHOW_DASHBOARD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;showDashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ENABLE_NEW_CHECKOUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;enableNewCheckout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stringFeatureFlags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ACTIVE_PROMOTION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;activePromotion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;StringFeatureFlagKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;stringFeatureFlags&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;stringFeatureFlags&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configCatSdkKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;TEST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;your-configcat-sdk-key-test&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;PRODUCTION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;your-configcat-sdk-key-production&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Por que tipar?&lt;/strong&gt; O TypeScript garante que você não vai digitar o nome errado de uma flag. Se tentar usar uma string que não existe no objeto, o compilador avisa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por que dois objetos separados?&lt;/strong&gt; Flags boolean e string têm contratos de retorno diferentes — &lt;code&gt;{ isEnabled, isLoading }&lt;/code&gt; vs &lt;code&gt;{ value, isLoading }&lt;/code&gt;. Separar os objetos permite tipar cada método (&lt;code&gt;getFlag&lt;/code&gt; e &lt;code&gt;getStringFlag&lt;/code&gt;) de forma precisa, sem abrir mão de type safety.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por que as SDK keys estão no código e não em &lt;code&gt;.env&lt;/code&gt;?&lt;/strong&gt; As SDK keys do ConfigCat são &lt;strong&gt;públicas por design&lt;/strong&gt; — elas só permitem leitura das flags, não alteração. Colocá-las no código junto com uma função de detecção de ambiente (como veremos a seguir) elimina a necessidade de gerenciar arquivos &lt;code&gt;.env&lt;/code&gt; por ambiente.&lt;/p&gt;

&lt;p&gt;Agora exporte as constantes no barrel do projeto pra que fiquem acessíveis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/utils/consts/index.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stringFeatureFlags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;configCatSdkKeys&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./featureFlags&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Consts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... outras constantes do projeto&lt;/span&gt;
  &lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;stringFeatureFlags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;configCatSdkKeys&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Consts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E exporte os tipos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/utils/index.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StringFeatureFlagKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./consts/featureFlags&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Detecção de ambiente
&lt;/h3&gt;

&lt;p&gt;Em vez de depender de variáveis de ambiente (&lt;code&gt;.env.local&lt;/code&gt;, &lt;code&gt;.env.production&lt;/code&gt;), use uma função que detecta o ambiente em runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/getIsProduction.ts&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hostsProduction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.meudominio.com.br&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-stg.meudominio.com.br&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getIsProduction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BUILD_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;hostsProduction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;getIsProduction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso permite que o Provider escolha a SDK key correta automaticamente, sem depender de arquivos &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. O Provider — coração da implementação
&lt;/h3&gt;

&lt;p&gt;Aqui é onde tudo acontece. O Provider tem 3 responsabilidades:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inicializar o ConfigCat&lt;/strong&gt; com a SDK key correta&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sincronizar os dados do usuário&lt;/strong&gt; logado com o ConfigCat (pra targeting)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buscar todas as flags e expor via Context próprio&lt;/strong&gt; do projeto
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/providers/feature-flags/featureFlagsContext.tsx&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useState&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ConfigCatProvider&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ConfigCatReactProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useConfigCatClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;User&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;configcat-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getIsProduction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StringFeatureFlagKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/user/userContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FlagState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsContextProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FlagState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nl"&gt;getStringFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StringFeatureFlagKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultFlagState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultStringFlagState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FeatureFlagsContextProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="na"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;defaultFlagState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;getStringFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;defaultStringFlagState&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Detalhe importante:&lt;/strong&gt; o &lt;code&gt;defaultFlagState&lt;/code&gt; retorna &lt;code&gt;isEnabled: false&lt;/code&gt; e &lt;code&gt;isLoading: true&lt;/code&gt;. O &lt;code&gt;defaultStringFlagState&lt;/code&gt; retorna &lt;code&gt;value: ''&lt;/code&gt; e &lt;code&gt;isLoading: true&lt;/code&gt;. Enquanto as flags não carregaram, nenhuma feature controlada por flag aparece — comportamento seguro por padrão.&lt;/p&gt;

&lt;h4&gt;
  
  
  ConfigCatSync — o componente que faz a mágica
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ConfigCatSync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useConfigCatClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFlags&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FlagState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;

  &lt;span class="c1"&gt;// Sincroniza dados do usuário logado com o ConfigCat&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configCatUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;is_admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAdmin&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="c1"&gt;// Adicione quantos atributos precisar pro targeting&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;

      &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDefaultUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configCatUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearDefaultUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="c1"&gt;// Busca todas as flags e escuta mudanças&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchAllFlags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;booleanKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stringKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringFeatureFlags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;booleanEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;booleanKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getValueAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stringEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;stringKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getValueAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nf"&gt;setFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;booleanEntries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;stringEntries&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;fetchAllFlags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;fetchAllFlags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;configChanged&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;configChanged&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getFlag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;defaultFlagState&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getStringFlag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StringFeatureFlagKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;defaultStringFlagState&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contextValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getStringFlag&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getStringFlag&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contextValue&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;O que está acontecendo aqui:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O primeiro &lt;code&gt;useEffect&lt;/code&gt; sincroniza os dados do usuário logado com o ConfigCat. Isso permite targeting por atributos (ex: "mostrar só pra admins")&lt;/li&gt;
&lt;li&gt;O segundo &lt;code&gt;useEffect&lt;/code&gt; busca &lt;strong&gt;todas&lt;/strong&gt; as flags de uma vez — boolean e string separadamente — e armazena no &lt;code&gt;useState&lt;/code&gt;. Note que &lt;code&gt;user&lt;/code&gt; faz parte das dependências: quando o usuário troca (ex: login/logout), as flags são rebuscadas automaticamente com o novo contexto de targeting&lt;/li&gt;
&lt;li&gt;O &lt;code&gt;client.on('configChanged', handler)&lt;/code&gt; escuta mudanças: quando o ConfigCat detecta uma atualização via polling, o handler rebusca todas as flags automaticamente, sem refresh da página&lt;/li&gt;
&lt;li&gt;O &lt;code&gt;useMemo&lt;/code&gt; no &lt;code&gt;contextValue&lt;/code&gt; evita re-renders desnecessários nos componentes consumidores&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  O Provider principal
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsProviderProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsProviderProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sdkKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getIsProduction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;configCatSdkKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PRODUCTION&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;configCatSdkKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TEST&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ConfigCatReactProvider&lt;/span&gt;
      &lt;span class="na"&gt;sdkKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sdkKey&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;pollIntervalSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ConfigCatSync&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ConfigCatSync&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ConfigCatReactProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsProvider&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Sobre o &lt;code&gt;pollIntervalSeconds&lt;/code&gt;:&lt;/strong&gt; o padrão do ConfigCat é 60 segundos. Usamos 3600 (1 hora) porque, na maioria dos casos, flags não precisam propagar imediatamente — e intervalos curtos consomem quota do plano desnecessariamente. Se o seu cenário exigir propagação mais rápida (ex: kill switch urgente), reduzir para 60 ou 120 é razoável. O importante é calibrar conforme a necessidade real, não usar o menor valor possível.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Adicionar na árvore de componentes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/pages/_app.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsProvider&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/feature-flags/featureFlagsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FeatureFlagsProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;FeatureFlagsProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;UserProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ordem importa:&lt;/strong&gt; o &lt;code&gt;FeatureFlagsProvider&lt;/code&gt; precisa estar &lt;strong&gt;dentro&lt;/strong&gt; do &lt;code&gt;UserProvider&lt;/code&gt;, porque o &lt;code&gt;ConfigCatSync&lt;/code&gt; consome o &lt;code&gt;UserContext&lt;/code&gt; pra sincronizar os dados do usuário.&lt;/p&gt;




&lt;h2&gt;
  
  
  Configurando no Dashboard do ConfigCat
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Criando uma flag boolean
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Acesse o dashboard do ConfigCat&lt;/li&gt;
&lt;li&gt;Crie uma feature flag do tipo &lt;strong&gt;On/Off Toggle&lt;/strong&gt; com o nome exato que você definiu na constante (ex: &lt;code&gt;showDashboard&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Configure o valor padrão como &lt;code&gt;OFF&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslbwjyjpvpd8tzxbrzbn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslbwjyjpvpd8tzxbrzbn.png" alt="Imagem do dashboard do ConfigCat mostrando a criação de uma flag boolean" width="800" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Criando uma flag string
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;No dashboard, crie uma feature flag do tipo &lt;strong&gt;Text&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use o nome exato da constante em &lt;code&gt;stringFeatureFlags&lt;/code&gt; (ex: &lt;code&gt;activePromotion&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Configure o valor padrão como string vazia ou um valor seguro&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvmnlow44vd9z0sl53ri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvmnlow44vd9z0sl53ri.png" alt="Imagem do dashboard do ConfigCat mostrando a criação de uma flag string" width="800" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configurando ambientes
&lt;/h3&gt;

&lt;p&gt;O ConfigCat separa ambientes por &lt;strong&gt;SDK key&lt;/strong&gt;. Cada ambiente tem sua própria key:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test/Development&lt;/strong&gt; — use a key de teste&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production&lt;/strong&gt; — use a key de produção&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Isso significa que você pode ter a flag &lt;code&gt;ON&lt;/code&gt; em teste e &lt;code&gt;OFF&lt;/code&gt; em produção ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdiv19lpv4lts0571jaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdiv19lpv4lts0571jaf.png" alt="Imagem dos ambientes Test e Production" width="449" height="354"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Consumindo nos Componentes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Exemplo 1: Controlar visibilidade de um item no menu
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Consts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/feature-flags/featureFlagsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;loggedUser&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getFlag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;showDashboard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SHOW_DASHBOARD&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;menuItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Parcelas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/app/parcelas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Recibos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/app/recibos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loggedUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAdmin&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;showDashboard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/app/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loggedUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;showDashboard&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;menuItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Perceba:&lt;/strong&gt; o componente importa &lt;code&gt;FeatureFlagsContext&lt;/code&gt; — não sabe nada sobre ConfigCat. Se amanhã trocar de ferramenta, este componente não muda.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo 2: Proteger uma página inteira com redirect
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Consts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/feature-flags/featureFlagsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DashboardPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getFlag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;showDashboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SHOW_DASHBOARD&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;showDashboard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;showDashboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Conteúdo do Dashboard&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Por que checar &lt;code&gt;isLoading&lt;/code&gt;?&lt;/strong&gt; Sem essa checagem, o componente faria redirect imediatamente no primeiro render (porque &lt;code&gt;isEnabled&lt;/code&gt; começa como &lt;code&gt;false&lt;/code&gt; enquanto as flags carregam). O &lt;code&gt;isLoading&lt;/code&gt; garante que o redirect só acontece depois que o ConfigCat respondeu.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo 3: Exibição condicional de um componente
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Consts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/feature-flags/featureFlagsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HomePage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getFlag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;enableNewCheckout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENABLE_NEW_CHECKOUT&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Bem-vindo&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;enableNewCheckout&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;NewCheckout&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LegacyCheckout&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exemplo 4: Flag string para conteúdo dinâmico
&lt;/h3&gt;

&lt;p&gt;Flags string são ideais quando você precisa não só de ligar/desligar, mas de &lt;strong&gt;controlar qual variante&lt;/strong&gt; exibir — A/B testing, banners sazonais, temas, e afins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Consts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/feature-flags/featureFlagsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PromoBanner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getStringFlag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;activePromotion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getStringFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringFeatureFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ACTIVE_PROMOTION&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;activePromotion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Banner&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;activePromotion&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No dashboard do ConfigCat, você configura o valor da flag como &lt;code&gt;'black-friday'&lt;/code&gt;, &lt;code&gt;'cyber-monday'&lt;/code&gt; ou string vazia (desligado). Zero deploy pra trocar a campanha ativa.&lt;/p&gt;




&lt;h2&gt;
  
  
  User Targeting — A Mágica de Verdade
&lt;/h2&gt;

&lt;p&gt;A parte mais poderosa das feature flags é o targeting. Com os dados do usuário sincronizados no &lt;code&gt;ConfigCatSync&lt;/code&gt;, você pode criar regras no dashboard como:&lt;/p&gt;

&lt;h3&gt;
  
  
  Targeting por email (testar com seu próprio usuário)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IF User.email IS ONE OF ["dev@empresa.com"]
THEN serve: ON
To everyone else: OFF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9x2n8km21y35serdixti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9x2n8km21y35serdixti.png" alt="Imagem de flag com Targeting por email" width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Targeting por atributo (liberar pra admins)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IF User.is_admin EQUALS "1"
THEN serve: ON
To everyone else: OFF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rollout por porcentagem
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10% dos usuários: ON
90% dos usuários: OFF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso permite um rollout gradual: comece com 10%, monitore, aumente pra 50%, e finalmente 100%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu60apr4v6qdzzvkc1kp9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu60apr4v6qdzzvkc1kp9.png" alt="Imagem de flag com Targeting por atributo e Rollout por porcentagem" width="800" height="243"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Testes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mock do ConfigCat para Jest
&lt;/h3&gt;

&lt;p&gt;Como o ConfigCat é uma dependência externa, precisamos mocká-lo nos testes. O mock deve cobrir todos os símbolos usados pelo &lt;code&gt;featureFlagsContext.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// __mocks__/configcat-react.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ConfigCatProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;useConfigCatClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;getValueAsync&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;setDefaultUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="na"&gt;clearDefaultUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="na"&gt;off&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;User&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configurar no jest.config.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;moduleNameMapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;^configcat-react$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;rootDir&amp;gt;/__mocks__/configcat-react.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mock do Context nos testes de componentes
&lt;/h3&gt;

&lt;p&gt;Na prática, a maioria dos testes de componentes não precisa exercitar o Provider inteiro — basta mockar o Context diretamente. Inclua &lt;code&gt;getStringFlag&lt;/code&gt; junto com &lt;code&gt;getFlag&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/feature-flags/featureFlagsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;_currentValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
      &lt;span class="na"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;getStringFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso faz com que todas as flags boolean retornem &lt;code&gt;true&lt;/code&gt; e as string retornem &lt;code&gt;'default'&lt;/code&gt; nos testes — comportamento padrão que geralmente você quer ao testar o caminho feliz.&lt;/p&gt;

&lt;p&gt;Para testar o cenário com flag &lt;strong&gt;desligada&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/feature-flags/featureFlagsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;_currentValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
      &lt;span class="na"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;getStringFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para testar o estado de &lt;strong&gt;carregamento&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/feature-flags/featureFlagsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;_currentValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
      &lt;span class="na"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;getStringFlag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Casos de Uso Reais
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Deploy Seguro
&lt;/h3&gt;

&lt;p&gt;Você desenvolveu uma feature nova. Em vez de esperar pra fazer merge só quando estiver 100% pronta:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Suba o código com a flag &lt;code&gt;OFF&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No dashboard, ligue apenas pro seu email&lt;/li&gt;
&lt;li&gt;Teste em produção com dados reais&lt;/li&gt;
&lt;li&gt;Quando estiver pronto, ligue pra todos&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Zero conflito de branch. Zero rollback.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Kill Switch
&lt;/h3&gt;

&lt;p&gt;Feature causando problemas em produção?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abra o dashboard do ConfigCat&lt;/li&gt;
&lt;li&gt;Desligue a flag&lt;/li&gt;
&lt;li&gt;Em até uma hora (ou o intervalo de polling configurado), a feature desaparece&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Sem deploy. Sem rollback. Sem estresse.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Apresentação para Stakeholders
&lt;/h3&gt;

&lt;p&gt;Quer mostrar uma feature nova só pros diretores antes de liberar?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Crie uma regra de targeting com os emails dos diretores&lt;/li&gt;
&lt;li&gt;Ligue a flag&lt;/li&gt;
&lt;li&gt;Eles veem a feature, o resto dos usuários não&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4. Rollout Gradual
&lt;/h3&gt;

&lt;p&gt;Feature nova que pode impactar performance?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dia 1:&lt;/strong&gt; 10% dos usuários&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dia 3:&lt;/strong&gt; 50% dos usuários&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dia 5:&lt;/strong&gt; 100% dos usuários&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se em qualquer momento algo der errado, volte pra 0%.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Campanha ou Conteúdo Dinâmico (flag string)
&lt;/h3&gt;

&lt;p&gt;Você tem um banner que muda conforme a campanha ativa. Em vez de fazer deploy a cada troca:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Crie uma flag string &lt;code&gt;activePromotion&lt;/code&gt; no ConfigCat&lt;/li&gt;
&lt;li&gt;Configure o valor como &lt;code&gt;'black-friday'&lt;/code&gt; quando a campanha começa&lt;/li&gt;
&lt;li&gt;Mude para &lt;code&gt;''&lt;/code&gt; (vazio) quando terminar&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O componente reage automaticamente quando o polling detecta a mudança — sem deploy, sem redeploy, sem acionar o time de infra.&lt;/p&gt;




&lt;h2&gt;
  
  
  Boas Práticas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Nomenclatura consistente
&lt;/h3&gt;

&lt;p&gt;Use camelCase nas flags (padrão do ConfigCat) e UPPER_SNAKE_CASE nas constantes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ Bom — claro e descritivo&lt;/span&gt;
&lt;span class="nx"&gt;featureFlags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;SHOW_DASHBOARD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;showDashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ENABLE_NEW_CHECKOUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;enableNewCheckout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;stringFeatureFlags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ACTIVE_PROMOTION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;activePromotion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ❌ Ruim — ambíguo&lt;/span&gt;
&lt;span class="nx"&gt;featureFlags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;DASH&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;CHECKOUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Escolha o tipo certo de flag
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use boolean quando...&lt;/th&gt;
&lt;th&gt;Use string quando...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ligar/desligar uma feature&lt;/td&gt;
&lt;td&gt;Controlar qual variante exibir&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proteger uma rota&lt;/td&gt;
&lt;td&gt;Selecionar um tema ou layout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Feature em rollout gradual&lt;/td&gt;
&lt;td&gt;A/B testing com múltiplas variantes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kill switch de emergência&lt;/td&gt;
&lt;td&gt;Conteúdo dinâmico (banners, campanhas)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  3. Limpeza de flags antigas
&lt;/h3&gt;

&lt;p&gt;Flags são &lt;strong&gt;código temporário&lt;/strong&gt;. Quando a feature estiver 100% liberada e estável:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remova a flag do código (o &lt;code&gt;if&lt;/code&gt; com &lt;code&gt;getFlag&lt;/code&gt; ou o componente com &lt;code&gt;getStringFlag&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Remova a constante do &lt;code&gt;featureFlags&lt;/code&gt; ou &lt;code&gt;stringFeatureFlags&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Delete a flag do dashboard do ConfigCat&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Flag esquecida é dívida técnica.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Comportamento seguro por padrão
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;defaultFlagState&lt;/code&gt; retorna &lt;code&gt;isEnabled: false&lt;/code&gt; e o &lt;code&gt;defaultStringFlagState&lt;/code&gt; retorna &lt;code&gt;value: ''&lt;/code&gt;. Se o ConfigCat estiver fora do ar ou demorar pra responder, nenhuma feature nova aparece — o usuário vê a versão estável da aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Use &lt;code&gt;isLoading&lt;/code&gt; em páginas protegidas
&lt;/h3&gt;

&lt;p&gt;Sempre cheque &lt;code&gt;isLoading&lt;/code&gt; antes de tomar decisões como redirect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ Bom — espera carregar antes de decidir&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SHOW_DASHBOARD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;// ❌ Ruim — redireciona antes de saber o valor real&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isEnabled&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Consts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SHOW_DASHBOARD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Vai redirecionar no primeiro render!&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Vantagens da Arquitetura
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Desacoplamento total
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Componentes não conhecem ConfigCat&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;providers/feature-flags/featureFlagsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getFlag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getStringFlag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FeatureFlagsContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fácil migração
&lt;/h3&gt;

&lt;p&gt;Para trocar ConfigCat por outra ferramenta (ex: LaunchDarkly), você altera &lt;strong&gt;apenas&lt;/strong&gt; o &lt;code&gt;ConfigCatSync&lt;/code&gt; e o &lt;code&gt;FeatureFlagsProvider&lt;/code&gt;. Os componentes continuam usando &lt;code&gt;useContext(FeatureFlagsContext)&lt;/code&gt; + &lt;code&gt;getFlag&lt;/code&gt;/&lt;code&gt;getStringFlag&lt;/code&gt; — não mudam nada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estado centralizado
&lt;/h3&gt;

&lt;p&gt;Todas as flags são buscadas uma vez e compartilhadas via Context. Se 10 componentes usam a mesma flag, o ConfigCat é consultado uma vez só — não 10 vezes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reatividade automática
&lt;/h3&gt;

&lt;p&gt;O listener &lt;code&gt;configChanged&lt;/code&gt; garante que quando uma flag muda no dashboard, todos os componentes que a consomem atualizam automaticamente, sem refresh da página. Isso vale tanto para flags boolean quanto string.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dois tipos de flag, um contrato unificado
&lt;/h3&gt;

&lt;p&gt;O Context expõe &lt;code&gt;getFlag&lt;/code&gt; e &lt;code&gt;getStringFlag&lt;/code&gt; com contratos claros e tipados. Componentes nunca lidam com &lt;code&gt;any&lt;/code&gt; ou precisam fazer cast — o TypeScript guia o uso correto desde o autocompletar.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Feature Flags transformaram a forma como fazemos deploy. Com ConfigCat como engine e React Context API como camada de abstração, conseguimos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Deploy contínuo sem medo&lt;/li&gt;
&lt;li&gt;✅ Testes em produção com segurança&lt;/li&gt;
&lt;li&gt;✅ Kill switch instantâneo&lt;/li&gt;
&lt;li&gt;✅ Targeting avançado por usuário&lt;/li&gt;
&lt;li&gt;✅ Suporte a flags boolean e string&lt;/li&gt;
&lt;li&gt;✅ Estado centralizado e reativo&lt;/li&gt;
&lt;li&gt;✅ Arquitetura desacoplada — pronta pra trocar de ferramenta&lt;/li&gt;
&lt;li&gt;✅ TypeScript garantindo type safety nas flags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O investimento de criar a camada de abstração com Context API vale muito a pena. O código fica limpo, testável e preparado pro futuro.&lt;/p&gt;




&lt;h2&gt;
  
  
  Indo Além — O que este guia não cobre
&lt;/h2&gt;

&lt;p&gt;O que implementamos aqui é uma base sólida e pronta pra produção. Mas feature flags como conceito têm muito mais profundidade. Se você quiser continuar explorando:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outros tipos de valor&lt;/strong&gt;&lt;br&gt;
Além de boolean e string, ferramentas como ConfigCat suportam flags do tipo &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt; e até &lt;code&gt;JSON&lt;/code&gt;. Isso abre espaço para casos como configurar limites dinâmicos (rate limit, tamanho de paginação, timeout de requisição) ou passar objetos de configuração inteiros sem deploy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flags no servidor&lt;/strong&gt;&lt;br&gt;
A implementação deste artigo é inteiramente client-side. Em aplicações Next.js com uso intenso de SSR ou Server Components, você pode — e muitas vezes deve — avaliar flags no servidor, antes de renderizar a página. Isso evita flashes de conteúdo (o usuário nunca vê o estado "carregando") e permite decisões de roteamento ainda na borda.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testes com flags em múltiplos estados no CI&lt;/strong&gt;&lt;br&gt;
Uma flag desligada em produção não significa que o código por trás dela está livre de bugs. Estratégias de CI/CD mais avançadas rodam o pipeline com a flag ligada e desligada, garantindo que ambos os caminhos sejam validados antes do merge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gestão do ciclo de vida das flags&lt;/strong&gt;&lt;br&gt;
Flags acumuladas viram dívida técnica silenciosa. Existem abordagens para rastrear a idade de cada flag, definir uma data de expiração desde a criação, e automatizar alertas quando uma flag passa do prazo esperado — antes que ela vire um &lt;code&gt;if&lt;/code&gt; esquecido no código.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plataformas de experimentação&lt;/strong&gt;&lt;br&gt;
Feature flags são o passo zero de um experimento. Ferramentas como LaunchDarkly, Split.io e GrowthBook vão além: medem o impacto estatístico de cada variante, calculam significância e ajudam a tomar decisões de produto baseadas em dados — não em intuição.&lt;/p&gt;

&lt;p&gt;Cada um desses tópicos rende um artigo próprio. O importante é que a arquitetura que construímos aqui já está preparada para evoluir em qualquer dessas direções — o desacoplamento via Context API garante isso.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recursos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://configcat.com/docs/" rel="noopener noreferrer"&gt;ConfigCat Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://configcat.com/docs/sdk-reference/react/" rel="noopener noreferrer"&gt;ConfigCat React SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://react.dev/reference/react/createContext" rel="noopener noreferrer"&gt;React Context API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Escrito por Guilherme Marucchi — &lt;a href="https://www.linkedin.com/in/guilherme-marucchi/" rel="noopener noreferrer"&gt;Meu LinkedIn&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>nextjs</category>
      <category>react</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
