[{"data":1,"prerenderedAt":1384},["ShallowReactive",2],{"blog-pt-supabase-relation-does-not-exist":3,"blog-index-pt":858},{"id":4,"title":5,"body":6,"category":814,"cover":815,"coverAlt":816,"description":817,"draft":818,"extension":819,"faq":820,"image":836,"keywords":837,"meta":847,"navigation":848,"ogTitle":5,"path":849,"published":850,"seo":851,"stem":852,"tldr":853,"updated":850,"__hash__":857},"blog_pt\u002Fblog\u002Fsupabase-relation-does-not-exist.md","Supabase \"relation does not exist\" e a tabela está lá",{"type":7,"value":8,"toc":801},"minimark",[9,18,28,35,38,43,61,72,75,148,181,192,196,199,208,245,302,314,317,325,336,340,353,356,403,419,425,438,443,449,453,456,463,469,483,490,493,499,516,519,525,533,538,542,548,551,557,564,579,583,596,608,611,617,624,642,647,651,654,665,674,678,681,691,714,723,741,745,794],[10,11,12,13,17],"p",{},"Seu builder criou uma tabela ",[14,15,16],"code",{},"invoices",". Você a vê no Table Editor, com as linhas\ne tudo, e a página que deveria listá-las fica vazia. O console do navegador mostra\nisto:",[19,20,25],"pre",{"className":21,"code":23,"language":24},[22],"language-text","{\n  \"code\": \"PGRST205\",\n  \"details\": null,\n  \"hint\": \"Perhaps you meant the table 'public.Invoices'\",\n  \"message\": \"Could not find the table 'public.invoices' in the schema cache\"\n}\n","text",[14,26,23],{"__ignoreMap":27},"",[10,29,30,31,34],{},"Supabase \"relation does not exist\" significa que o Postgres não achou nenhuma\ntabela ou view com esse nome exato nos schemas que a consulta percorreu. O\nPGRST205 é a mesma resposta dada pelo PostgREST, a parte do Supabase que\ntransforma as chamadas ",[14,32,33],{},"supabase.from(...)"," do seu app em consultas ao banco,\nantes mesmo de a consulta chegar ao Postgres.",[10,36,37],{},"A solução que circula para esse erro é adicionar o schema em Exposed schemas nas\nconfigurações do projeto. Isso resolve uma das quatro causas abaixo. Também deixa\nqualquer pessoa com a chave pública do seu app alcançar todas as tabelas desse\nschema, então leia o que isso abre antes de ligar.",[39,40,42],"h2",{"id":41},"o-que-significa-relation-does-not-exist-no-supabase","O que significa \"relation does not exist\" no Supabase?",[10,44,45,46,49,50,60],{},"O banco procurou uma tabela com esse nome exato, nos schemas que mandaram ele\npercorrer, e não achou nenhuma. \"Relation\" é a palavra do Postgres para qualquer\ncoisa de onde saem linhas, uma tabela ou uma view. O código do erro é ",[14,47,48],{},"42P01",", que\no ",[51,52,56,57],"a",{"href":53,"rel":54},"https:\u002F\u002Fgithub.com\u002Fpostgres\u002Fpostgres\u002Fblob\u002Fmaster\u002Fsrc\u002Fbackend\u002Futils\u002Ferrcodes.txt",[55],"nofollow","Postgres chama de ",[14,58,59],{},"undefined_table",".",[10,62,63,64,67,68,71],{},"Pense no seu banco como um prédio. Cada schema é um andar: ",[14,65,66],{},"public"," é o térreo, e\n",[14,69,70],{},"auth",", onde o Supabase guarda seus usuários, é outro. Cada tabela é uma sala com\no nome na porta. Uma consulta que dá só o nome de uma sala procura por ela nos\nandares listados no caminho de busca dela. As requisições do seu app sobem de\nelevador, e o elevador só para nos andares que seu projeto expõe. O erro quer\ndizer que ninguém achou uma porta com esse nome nos andares que olhou.",[10,73,74],{},"A redação que você vê depende de onde a consulta rodou:",[76,77,78,91],"table",{},[79,80,81],"thead",{},[82,83,84,88],"tr",{},[85,86,87],"th",{},"Onde a consulta rodou",[85,89,90],{},"O que volta",[92,93,94,108,122,134],"tbody",{},[82,95,96,100],{},[97,98,99],"td",{},"O SQL Editor, uma migration, uma função ou um trigger",[97,101,102,105,106],{},[14,103,104],{},"relation \"invoices\" does not exist",", código ",[14,107,48],{},[82,109,110,113],{},[97,111,112],{},"Seu app, com PostgREST 13 ou mais novo",[97,114,115,105,118,121],{},[14,116,117],{},"Could not find the table 'public.invoices' in the schema cache",[14,119,120],{},"PGRST205",", HTTP 404",[82,123,124,127],{},[97,125,126],{},"Seu app, com um PostgREST mais antigo",[97,128,129,130,133],{},"uma leitura recebe ",[14,131,132],{},"relation \"public.invoices\" does not exist",", HTTP 404, e um insert recebe um erro vazio",[82,135,136,139],{},[97,137,138],{},"Seu app, pedindo um schema que o projeto não expõe",[97,140,141,105,144,147],{},[14,142,143],{},"Invalid schema: billing",[14,145,146],{},"PGRST106",", HTTP 406",[10,149,150,151,156,157,159,160,165,166,168,169,174,175,180],{},"O ",[51,152,155],{"href":153,"rel":154},"https:\u002F\u002Fgithub.com\u002FPostgREST\u002Fpostgrest\u002Fblob\u002Fmain\u002FCHANGELOG.md",[55],"changelog do PostgREST","\ndata a redação nova da versão 13.0.0, lançada em 8 de maio de 2025: \"Querying\nnon-existent table now returns ",[14,158,120],{}," error\". Antes disso, como\n",[51,161,164],{"href":162,"rel":163},"https:\u002F\u002Fgithub.com\u002FPostgREST\u002Fpostgrest\u002Fissues\u002F3697",[55],"explicou um dos mantenedores na issue #3697",",\numa leitura ia para o Postgres sem checagem e voltava como ",[14,167,48],{},". O\n",[51,170,173],{"href":171,"rel":172},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fdatabase\u002Fhardening-data-api",[55],"guia do Supabase para proteger a Data API","\ndiz que você pode ver a versão do PostgREST do seu projeto no Dashboard.\n",[51,176,179],{"href":177,"rel":178},"https:\u002F\u002Fgithub.com\u002FPostgREST\u002Fpostgrest\u002Fblob\u002Fmain\u002Fsrc\u002Flibrary\u002FPostgREST\u002FError.hs",[55],"O próprio código do PostgREST","\ndefine o resto: a dica do PGRST205, quando existe, nomeia a tabela mais parecida\nque ele conhece no mesmo andar.",[10,182,183,184,187,188,60],{},"Se a mensagem disser ",[14,185,186],{},"permission denied for table",", a tabela foi achada e seu app\nfoi barrado na porta. Esse tem\n",[51,189,191],{"href":190},"\u002Fblog\u002Fsupabase-permission-denied-for-table","outra solução",[39,193,195],{"id":194},"causa-1-o-nome-na-porta-tem-uma-letra-maiúscula","Causa 1: o nome na porta tem uma letra maiúscula",[10,197,198],{},"O nome precisa bater exatamente, maiúsculas incluídas, e duas das ferramentas que\nvocê usa tratam maiúsculas de um jeito diferente da terceira.",[10,200,201,202,207],{},"A\n",[51,203,206],{"href":204,"rel":205},"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fsql-syntax-lexical.html",[55],"documentação do Postgres","\nresume a regra numa frase: \"Quoting an identifier also makes it case-sensitive,\nwhereas unquoted names are always folded to lower case.\" As outras duas mantêm o\nque você digitou:",[209,210,211,227],"ul",{},[212,213,214,215,220,221,224,225],"li",{},"o Table Editor do Supabase cria a tabela com exatamente o nome que você dá.\n",[51,216,219],{"href":217,"rel":218},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase\u002Fblob\u002Fmaster\u002Fpackages\u002Fpg-meta\u002Fsrc\u002Fpg-meta-tables.ts",[55],"O código dele","\npõe o nome entre aspas quando precisa, então ",[14,222,223],{},"Invoices"," continua ",[14,226,223],{},[212,228,229,230,237,238,241,242,244],{},"o PostgREST põe entre aspas duplas cada nome que seu app envia\n(",[51,231,234],{"href":232,"rel":233},"https:\u002F\u002Fgithub.com\u002FPostgREST\u002Fpostgrest\u002Fblob\u002Fmain\u002Fsrc\u002Flibrary\u002FPostgREST\u002FQuery\u002FSqlFragment.hs",[55],[14,235,236],{},"pgFmtIdent","),\nentão ",[14,239,240],{},".from('invoices')"," pede ",[14,243,16],{}," e mais nada",[76,246,247,260],{},[79,248,249],{},[82,250,251,254,257],{},[85,252,253],{},"Como a tabela foi criada",[85,255,256],{},"Em SQL, escreva",[85,258,259],{},"No seu app, escreva",[92,261,262,281],{},[82,263,264,273,277],{},[97,265,266,269,270,272],{},[14,267,268],{},"create table invoices",", ou ",[14,271,223],{}," digitado em SQL sem aspas",[97,274,275],{},[14,276,16],{},[97,278,279],{},[14,280,240],{},[82,282,283,291,297],{},[97,284,285,269,288,290],{},[14,286,287],{},"create table \"Invoices\"",[14,289,223],{}," digitado no Table Editor",[97,292,293,296],{},[14,294,295],{},"\"Invoices\"",", com aspas",[97,298,299],{},[14,300,301],{},".from('Invoices')",[10,303,304,305,307,308,310,311,313],{},"A segunda linha produz esse erro pelos dois lados. Seu app chama\n",[14,306,240],{}," e recebe PGRST205, com o nome real na dica, como na mensagem do\ncomeço desta página. Ou o app funciona, e uma função ou policy que cita ",[14,309,223],{},"\nsem aspas falha com ",[14,312,104],{},", porque o Postgres passou\no nome para minúsculas antes de procurar.",[10,315,316],{},"Para ver todas as tabelas com esse nome, em qualquer andar e com qualquer\ncombinação de maiúsculas, rode isto no SQL Editor:",[19,318,323],{"className":319,"code":321,"language":322,"meta":27},[320],"language-sql","select table_schema, table_name\nfrom information_schema.tables\nwhere table_name ilike 'invoices';\n","sql",[14,324,321],{"__ignoreMap":27},[10,326,327,328,330,331,335],{},"A solução que não mexe em nada dos seus dados está no código: escreva\n",[14,329,295],{}," com as aspas em SQL, e as maiúsculas exatas no app. Renomear a tabela\nno lugar disso quebra toda tela que ainda usa o nome antigo.\n",[51,332,334],{"href":333},"\u002Fblog\u002Fsupabase-schema-cache-column-error","A versão deste erro para colunas"," tem a\nmesma armadilha com nomes de coluna.",[39,337,339],{"id":338},"causa-2-a-tabela-está-em-outro-andar","Causa 2: a tabela está em outro andar",[10,341,342,343,345,346,349,350,352],{},"Seu app procura em ",[14,344,66],{}," a não ser que você diga outra coisa, então uma tabela\nem qualquer outro schema não existe para ele. É por isso que a mensagem diz\n",[14,347,348],{},"public.invoices",": ",[14,351,66],{}," é o andar aonde o elevador foi.",[10,354,355],{},"Isso acontece de três jeitos:",[209,357,358,371,380],{},[212,359,360,361,364,365,368,369],{},"seu builder criou a tabela num schema próprio, como ",[14,362,363],{},"billing"," ou ",[14,366,367],{},"private",", e o\napp chama um simples ",[14,370,240],{},[212,372,373,374,377,378],{},"o schema está escrito dentro do nome, como ",[14,375,376],{},".from('billing.invoices')",". O\nPostgREST lê a string inteira como um único nome de tabela e procura por ela em\n",[14,379,66],{},[212,381,382,383,168,386,391,392,394,395,398,399],{},"a tabela é ",[14,384,385],{},"auth.users",[51,387,390],{"href":388,"rel":389},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fmanaging-user-data",[55],"guia do Supabase sobre dados de usuários","\ndiz: \"For security, the Auth schema is not exposed in the auto-generated API.\"\nA resposta dele é uma tabela sua em ",[14,393,66],{},", ",[14,396,397],{},"profiles"," no exemplo dele,\npreenchida por um trigger quando alguém se cadastra, e\n",[51,400,402],{"href":401},"\u002Fblog\u002Fdatabase-error-saving-new-user","esse trigger pode falhar do jeito dele",[10,404,405,406,409,410,415,416,418],{},"Uma tabela em outro andar é lida com ",[14,407,408],{},".schema('billing').from('invoices')",", e esse\nschema precisa estar em Exposed schemas nas configurações de API do projeto, como\nmostra o\n",[51,411,414],{"href":412,"rel":413},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fapi\u002Fusing-custom-schemas",[55],"guia do Supabase sobre schemas próprios",".\nAté lá, a resposta passa a ser ",[14,417,146],{},":",[19,420,423],{"className":421,"code":422,"language":24},[22],"{\n  \"code\": \"PGRST106\",\n  \"details\": null,\n  \"hint\": \"Only the following schemas are exposed: public, graphql_public\",\n  \"message\": \"Invalid schema: billing\"\n}\n",[14,424,422],{"__ignoreMap":27},[10,426,427,428,431,432,437],{},"A dica lista os andares em que o elevador para de fato. O PostgREST 12 escreve o\nmesmo erro de outro jeito, com a lista dentro da própria mensagem:\n",[14,429,430],{},"The schema must be one of the following: public, graphql_public",". É o texto que\n",[51,433,436],{"href":434,"rel":435},"https:\u002F\u002Fgithub.com\u002FPostgREST\u002Fpostgrest\u002Fblob\u002Fv12.2.12\u002Fsrc\u002FPostgREST\u002FError.hs",[55],"o código dele para essa versão","\nproduz, e o changelog levou o nome do schema para a mensagem na 13.0.7.",[10,439,440,441,60],{},"Sua chave secreta sobe no mesmo elevador. A exposição é uma configuração da API,\nentão código de servidor que usa o supabase-js com essa chave recebe o mesmo\n",[14,442,146],{},[444,445],"diagram",{"alt":446,"caption":447,"src":448},"Um prédio em corte com três andares, public embaixo, billing no meio e auth em cima, e o poço de um elevador à direita. O elevador para em public, onde a porta invoices é um espaço vazio tracejado que leva a uma placa com PGRST205 e 404. A parada dele em billing, onde fica a porta invoices, é um vão tracejado em âmbar que leva a uma placa com PGRST106 e 406. O andar auth não tem parada nenhuma.","O elevador só para nos andares expostos. Uma tabela em outro andar não está em public, e pedir esse andar pelo nome é recusado até ele ser exposto.","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fthe-lift-stops-at-public-1600x760.png",[39,450,452],{"id":451},"o-que-expor-um-schema-abre","O que expor um schema abre?",[10,454,455],{},"O elevador passa a parar naquele andar, e com as permissões que o guia do\nSupabase dá, todo visitante recebe uma chave de cada sala dele. A Row Level\nSecurity vira então a única coisa que decide o que cada um pode ler ou mudar.",[10,457,150,458,462],{},[51,459,461],{"href":412,"rel":460},[55],"guia sobre schemas próprios","\ntem dois passos. O primeiro é a configuração Exposed schemas. O segundo é um bloco\nde SQL, e as duas primeiras linhas dele são:",[19,464,467],{"className":465,"code":466,"language":322,"meta":27},[320],"GRANT USAGE ON SCHEMA myschema TO anon, authenticated, service_role;\nGRANT ALL ON ALL TABLES IN SCHEMA myschema TO anon, authenticated, service_role;\n",[14,468,466],{"__ignoreMap":27},[10,470,471,474,475,478,479,482],{},[14,472,473],{},"anon"," é o papel por trás de toda requisição de quem não fez login. ",[14,476,477],{},"ALL"," é ler,\nadicionar, mudar e apagar. O bloco continua com ",[14,480,481],{},"ALTER DEFAULT PRIVILEGES",", que dá\no mesmo acesso a toda tabela criada depois naquele andar.",[10,484,485,486,489],{},"Isso é seguro onde a Row Level Security, as regras por linha que o Supabase\nconfere a cada requisição, está ligada e escrita para cada tabela. O\n",[51,487,173],{"href":171,"rel":488},[55],"\ndiz: \"Tables created through the Supabase Dashboard have RLS enabled by default.\nEnable RLS explicitly for tables created in the SQL Editor or through another\ntool.\" Um schema que seu builder montou em SQL pode ter tabelas com ela desligada.\nExposta com essas permissões, uma tabela assim entrega cada linha a quem tiver sua\nchave pública, e ainda aceita as mudanças dessa pessoa.",[10,491,492],{},"Confira antes de expor:",[19,494,497],{"className":495,"code":496,"language":322,"meta":27},[320],"select tablename, rowsecurity\nfrom pg_tables\nwhere schemaname = 'billing';\n",[14,498,496],{"__ignoreMap":27},[10,500,501,502,505,506,510,511,515],{},"Cada linha que diz ",[14,503,504],{},"false"," é uma tabela sem regra nenhuma.\n",[51,507,509],{"href":508},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Ligar a Row Level Security em toda tabela","\nmostra como ligar e escrever a primeira regra, e\n",[51,512,514],{"href":513},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","\"RLS disabled in public\""," mostra a regra de\nleitura aberta que deixa uma tabela tão alcançável quanto antes mesmo com ela\nligada.",[10,517,518],{},"Você também pode dar menos permissões que o guia. Um andar com uma tabela que só\nusuários logados leem precisa de duas linhas:",[19,520,523],{"className":521,"code":522,"language":322,"meta":27},[320],"grant usage on schema billing to authenticated;\ngrant select on billing.invoices to authenticated;\n",[14,524,522],{"__ignoreMap":27},[10,526,527,528,532],{},"Se suas tabelas respondem a um desconhecido é algo que dá para conferir de fora.\nNosso ",[51,529,531],{"href":530},"\u002Fsecurity-scanner","scan gratuito"," lê seu app no ar com a mesma chave\npública que um visitante recebe, mostra quais tabelas devolvem linhas e não pede\nconta.",[444,534],{"alt":535,"caption":536,"src":537},"O andar billing desenhado duas vezes. À esquerda o elevador não para ali e três portas estão fechadas. À direita o elevador para ali e as três portas estão abertas: duas salas têm um cadeado sobre as linhas, e a terceira não tem nenhum e as linhas dela estão em âmbar.","Expor um andar com as permissões do guia abre todas as portas dele. A Row Level Security é o cadeado de cada sala, e uma sala sem cadeado está aberta a quem tiver sua chave pública.","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fexposing-opens-every-room-1600x700.png",[39,539,541],{"id":540},"expor-o-schema-ou-mover-a-tabela","Expor o schema ou mover a tabela?",[10,543,544,545,547],{},"Decida pensando em quem lê a tabela. Uma tabela que seu app lê pelo navegador precisa de\numa permissão para o papel que lê e de Row Level Security com uma regra, onde quer\nque esteja. Mover para ",[14,546,66],{}," só poupa o passo de expor o schema.",[10,549,550],{},"Se for mover:",[19,552,555],{"className":553,"code":554,"language":322,"meta":27},[320],"alter table billing.invoices set schema public;\n",[14,556,554],{"__ignoreMap":27},[10,558,559,560,563],{},"A tabela mantém as permissões e as regras. Uma função cujo corpo cita\n",[14,561,562],{},"billing.invoices"," passa a falhar com este mesmo erro, porque o corpo guarda o nome\ndo jeito que foi escrito.",[10,565,566,567,569,570,574,575,578],{},"Uma tabela de que só o código de servidor precisa pode ficar num andar aonde o\nelevador nunca vai. Uma função em ",[14,568,66],{}," pode fazer com ela o único trabalho de\nque seu app precisa, e\n",[51,571,573],{"href":572},"\u002Fblog\u002Fsupabase-function-not-found","chamar uma função do Supabase"," mostra como\ntirar o ",[14,576,577],{},"execute"," de visitantes que não fizeram login.",[39,580,582],{"id":581},"causa-3-uma-função-com-caminho-de-busca-vazio","Causa 3: uma função com caminho de busca vazio",[10,584,585,586,589,590,592,593,595],{},"Uma função com ",[14,587,588],{},"search_path = ''"," não percorre andar nenhum, então toda tabela que\nela usa precisa do schema na frente: ",[14,591,348],{},", nunca um ",[14,594,16],{},"\nsozinho.",[10,597,598,599,607],{},"O Security Advisor do Supabase pede exatamente essa configuração. O\n",[51,600,603,604],{"href":601,"rel":602},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsplinter\u002Fblob\u002Fmain\u002Fdocs\u002F0011_function_search_path_mutable.md",[55],"aviso ",[14,605,606],{},"function_search_path_mutable","\ndiz: \"We recommend pinning functions' search_path to an empty string\". A mesma\npágina termina com: \"once you set the search_path = '' all references to\ntables\u002Ffunctions\u002Fviews\u002Fetc in your function's body must be qualified with a\nschema name.\"",[10,609,610],{},"Então o aviso se resolve com uma linha, e a função passa a falhar no primeiro nome\nde tabela sem schema:",[19,612,615],{"className":613,"code":614,"language":322,"meta":27},[320],"create or replace function public.count_invoices()\nreturns bigint\nlanguage plpgsql\nset search_path = ''\nas $$\nbegin\n  return (select count(*) from invoices);  -- relation \"invoices\" does not exist\nend;\n$$;\n",[14,616,614],{"__ignoreMap":27},[10,618,619,620,623],{},"Escreva ",[14,621,622],{},"from public.invoices"," e ela volta a funcionar. Mantenha a configuração:\nela existe para que quem chama a função não consiga apontar um nome sem schema\npara uma tabela própria.",[10,625,626,627,630,631,633,634,638,639,60],{},"Chamada do seu app com ",[14,628,629],{},".rpc()",", o erro atravessa o PostgREST como ",[14,632,48],{}," com\nHTTP 404, o status que\n",[51,635,637],{"href":177,"rel":636},[55],"o código do PostgREST","\ndá a uma tabela desconhecida. Um trigger de novos cadastros que falha assim\naparece como\n",[51,640,641],{"href":401},"\"Database error saving new user\"",[444,643],{"alt":644,"caption":645,"src":646},"Duas buscas de dentro de uma função marcada com search_path = ''. A de cima pede invoices sem andar, encontra uma lista de andares vazia e termina numa placa com 42P01. A de baixo pede public.invoices, vai direto à porta invoices do andar public e recebe um visto.","Com o caminho de busca vazio não há andar nenhum para percorrer, então só um endereço completo encontra a sala.","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fan-empty-search-path-1600x620.png",[39,648,650],{"id":649},"causa-4-a-tabela-ainda-não-está-nesse-projeto","Causa 4: a tabela ainda não está nesse projeto",[10,652,653],{},"A tabela existe em outro banco, ou só no seu código.",[10,655,656,657,661,662,664],{},"Uma conta do Supabase pode ter vários projetos, e\n",[51,658,660],{"href":659},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","uma branch é um projeto separado"," com o\npróprio banco. Uma tabela criada no SQL Editor do projeto errado é uma sala em\noutro prédio.\n",[51,663,334],{"href":333},"\nmostra como comparar a referência do projeto no endereço do Supabase do seu app\ncom a do dashboard.",[10,666,667,668,673],{},"Se você constrói com Lovable, volte no chat procurando um SQL que pediram para você\naprovar. A\n",[51,669,672],{"href":670,"rel":671},"https:\u002F\u002Fdocs.lovable.dev\u002Fintegrations\u002Fsupabase",[55],"documentação de Supabase do Lovable","\ndiz que ele \"writes the SQL, shows it to you, and asks for your approval in the\nproject chat before running it\". Enquanto você não aprova, a tabela só existe no\ncódigo que a lê.",[39,675,677],{"id":676},"mover-uma-tabela-de-que-seu-app-depende","Mover uma tabela de que seu app depende",[10,679,680],{},"Guarde uma cópia do banco de antes da mudança, e fique sabendo quando algo que seu\napp expõe mudar.",[10,682,683],{},[684,685,686,690],"strong",{},[51,687,689],{"href":688},"\u002Fsupabase-backups","Reeve Care"," guarda uma cópia do seu banco no Supabase:",[209,692,693,696,702,705,708,711],{},[212,694,695],{},"uma cópia criptografada num cronograma, no armazenamento próprio da Reeve na UE, fora da sua conta do Supabase",[212,697,698,699,701],{},"cada schema que você criou, ",[14,700,66],{}," e os outros, com as tabelas e linhas como estavam antes da sua mudança",[212,703,704],{},"cada cópia verificada antes de valer, contando as linhas de cada tabela",[212,706,707],{},"seus arquivos enviados também, assim que você conecta uma credencial do Storage",[212,709,710],{},"uma restauração com um clique, com uma cópia de segurança do estado atual feita antes",[212,712,713],{},"tudo o que o Monitor faz",[10,715,716],{},[684,717,718,722],{},[51,719,721],{"href":720},"\u002Fwebsite-monitoring","Reeve Monitor"," continua conferindo de fora:",[209,724,725,728,731,738],{},[212,726,727],{},"se seu app está no ar, conferido a cada minuto",[212,729,730],{},"a verificação de segurança completa a cada hora, em até três apps",[212,732,733,734,737],{},"uma mensagem quando um resultado ",[684,735,736],{},"muda",", para que um deploy que muda o que seu app expõe chegue até você sem você ter que ir olhar",[212,739,740],{},"um relatório mensal, em linguagem simples, do que ele viu",[39,742,744],{"id":743},"o-que-fazer-agora","O que fazer agora",[746,747,748],"key-takeaways",{},[209,749,750,757,760,773,782,791],{},[212,751,752,753,756],{},"Leia a mensagem: o nome entre aspas é o que foi pedido, e ",[14,754,755],{},"public."," na frente é o schema que foi percorrido.",[212,758,759],{},"Compare o nome com o Table Editor, maiúsculas incluídas. Uma tabela com maiúscula no nome precisa de aspas duplas em SQL.",[212,761,762,763,766,767,769,770,60],{},"Descubra em que schema a tabela está com a consulta em ",[14,764,765],{},"information_schema.tables",", e chame uma tabela fora de ",[14,768,66],{}," com ",[14,771,772],{},".schema('nome').from(...)",[212,774,775,776,779,780,60],{},"Antes de expor um schema, rode a consulta em ",[14,777,778],{},"pg_tables"," e ligue a Row Level Security em cada tabela que disser ",[14,781,504],{},[212,783,784,785,787,788,60],{},"Dentro de uma função com ",[14,786,588],{},", escreva cada tabela como ",[14,789,790],{},"public.nome",[212,792,793],{},"Confira se o projeto que seu app chama é aquele em que você criou a tabela.",[10,795,796,797,800],{},"Comece pelos dois nomes da mensagem, a tabela e o schema na frente dela, porque\neles dizem exatamente qual porta foi pedida e em que andar. Antes de mover,\nrenomear ou expor algo que as pessoas usam,\n",[51,798,799],{"href":688},"guarde uma cópia do banco"," de antes da mudança.",{"title":27,"searchDepth":802,"depth":802,"links":803},3,[804,806,807,808,809,810,811,812,813],{"id":41,"depth":805,"text":42},2,{"id":194,"depth":805,"text":195},{"id":338,"depth":805,"text":339},{"id":451,"depth":805,"text":452},{"id":540,"depth":805,"text":541},{"id":581,"depth":805,"text":582},{"id":649,"depth":805,"text":650},{"id":676,"depth":805,"text":677},{"id":743,"depth":805,"text":744},"Noções de segurança","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcover-1200x630.png","Um prédio em corte ao lado do poço de um elevador. O elevador está no térreo, e a parada dele um andar acima é um vão tracejado em âmbar.","Supabase \"relation does not exist\" ou PGRST205: nenhuma tabela tem esse nome nesse schema. Quatro verificações, e o que expor um schema abre.",false,"md",[821,824,827,830,833],{"q":822,"a":823},"Por que o Supabase diz que minha tabela não existe?","Porque nenhuma tabela com esse nome exato está no schema que a consulta percorreu. Confira quatro coisas, nesta ordem: as maiúsculas do nome, o schema onde a tabela está (seu app procura em public a não ser que você diga outra coisa), o projeto com que seu app fala, e se a consulta roda dentro de uma função com search_path vazio, onde toda tabela precisa do schema na frente.",{"q":825,"a":826},"O que significa \"the schema must be one of the following\"?","É o erro PGRST106 com a redação das versões antigas do PostgREST. Seu app pediu um schema que o projeto não expõe, por exemplo com .schema('nome'), e a lista que vem depois são os schemas expostos. As versões novas dizem \"Invalid schema: nome\" e põem a mesma lista na dica. Expor o schema resolve, e vale decidir isso com calma.",{"q":828,"a":829},"É seguro expor um schema no Supabase?","Só quando cada tabela dele tem a Row Level Security ligada e uma regra escrita. O guia do Supabase sobre schemas próprios dá a anon, o papel de todo visitante que não fez login, acesso total a cada tabela do schema, inclusive às criadas depois. O guia de segurança dele acrescenta que tabelas criadas no SQL Editor não vêm com Row Level Security ligada.",{"q":831,"a":832},"Maiúsculas fazem diferença no nome de uma tabela do Supabase?","Sim. Um nome escrito em SQL sem aspas duplas vira minúsculo, enquanto o Table Editor e o supabase-js mantêm as maiúsculas exatamente como foram escritas. Uma tabela criada como Invoices se escreve \"Invoices\", com aspas, em SQL, e .from('Invoices') no seu app.",{"q":834,"a":835},"Devo mover a tabela para public?","Mover resolve a metade do erro que é sobre o schema e nada da segurança: uma tabela que seu app lê pelo navegador precisa de uma permissão para o papel que lê e de Row Level Security com uma regra, onde quer que esteja. Uma tabela de que só o código de servidor precisa pode ficar em um schema não exposto, alcançada por uma função em public que faz o único trabalho de que seu app precisa.","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",[838,839,840,841,842,843,844,845,846],"relation does not exist supabase","supabase relation does not exist","could not find the table in the schema cache","pgrst205","42p01","the schema must be one of the following","pgrst106","supabase schema não exposto","supabase tabela não encontrada api",{},true,"\u002Fblog\u002Fsupabase-relation-does-not-exist","2026-10-23",{"title":5,"description":817},"blog\u002Fsupabase-relation-does-not-exist",[854,855,856],"Supabase \"relation does not exist\" (código do Postgres 42P01) significa que nenhuma tabela ou view com esse nome exato está nos schemas que a consulta percorreu. No seu app, em um projeto atual, o mesmo problema aparece como \"Could not find the table in the schema cache\" (PGRST205).","Confira primeiro o nome letra por letra, maiúsculas incluídas, depois o schema, depois o projeto. Dentro de uma função com search_path vazio, toda tabela precisa do schema na frente: public.invoices.","Expor um schema faz o erro sumir e deixa a API alcançar todas as tabelas dele, então confira a Row Level Security de cada uma antes de fazer isso.","phgzUk_kURyuLmGs-u6VVCBZ_dghfuLTCnQrZhK2goo",[859,865,871,877,883,889,895,901,907,913,919,926,932,938,944,950,956,962,963,968,973,979,985,991,997,1003,1009,1014,1020,1026,1032,1038,1044,1050,1056,1062,1068,1074,1080,1086,1092,1098,1104,1110,1116,1122,1126,1132,1138,1144,1150,1156,1162,1168,1174,1180,1186,1192,1198,1204,1210,1216,1221,1226,1232,1238,1244,1250,1256,1262,1268,1274,1280,1286,1292,1298,1304,1310,1315,1321,1327,1333,1339,1345,1350,1356,1362,1368,1373,1379],{"path":860,"title":861,"description":862,"published":863,"category":814,"image":864,"draft":818},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\", explicado","Supabase \"max client connections reached\": o pooler não tem lugar para mais um cliente. A porta da sua string de conexão define o limite.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":866,"title":867,"description":868,"published":869,"category":814,"image":870,"draft":818},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Erro do Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": o Google está desativado no seu projeto Supabase. Como ativar e corrigir o redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":872,"title":873,"description":874,"published":875,"category":814,"image":876,"draft":818},"\u002Fblog\u002Fviolates-foreign-key-constraint","Erro do Supabase \"violates foreign key constraint\" ao inserir","Supabase \"insert or update on table violates foreign key constraint\": sua linha aponta para uma linha que não existe. Qual, por quê, e como corrigir.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":878,"title":879,"description":880,"published":881,"category":814,"image":882,"draft":818},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Erro do Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": uma coluna obrigatória chegou vazia. De onde veio o null, e como corrigir.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":884,"title":885,"description":886,"published":887,"category":814,"image":888,"draft":818},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": para onde foi a sessão","\"Auth session missing!\" é o supabase-js sem achar nenhuma sessão logada e sem chegar a perguntar ao Supabase. Para onde foi a sessão, e a correção.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":890,"title":891,"description":892,"published":893,"category":814,"image":894,"draft":818},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": ninguém está logado","\"invalid claim: missing sub claim\": o Supabase Auth recebeu um token autêntico sem nenhum usuário, a chave do projeto no lugar de uma sessão.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":896,"title":897,"description":898,"published":899,"category":814,"image":900,"draft":818},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": a causa real","\"Failed to send a request to the Edge Function\": o navegador não recebeu uma resposta legível. O console dele diz por quê e se a sua função rodou.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":902,"title":903,"description":904,"published":905,"category":814,"image":906,"draft":818},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Por que o Supabase redireciona links de e-mail para localhost:3000","Se o Supabase redireciona para localhost:3000, a Site URL nunca foi trocada ou o seu endereço falta em Redirect URLs. A solução, e o curinga a evitar.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":908,"title":909,"description":910,"published":911,"category":814,"image":912,"draft":818},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" num link novo","Num link enviado há um minuto, \"Email link is invalid or has expired\" no Supabase costuma significar que um filtro de e-mail o usou antes. Como resolver.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":914,"title":915,"description":916,"published":917,"category":814,"image":918,"draft":818},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\", explicado","Supabase \"canceling statement due to statement timeout\": uma consulta passou do limite do seu papel, 3 segundos para um visitante. Veja antes a política RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":920,"title":921,"description":922,"published":923,"category":924,"image":925,"draft":818},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" no Supabase, e o que vai junto","\"Database error deleting user\" no Supabase: seu banco recusou a exclusão. O motivo está nos seus logs, e a correção decide o que mais é apagado.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":927,"title":928,"description":929,"published":930,"category":814,"image":931,"draft":818},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" no Supabase","O webhook do Stripe numa Edge Function do Supabase diz \"No signatures found matching the expected signature\"? São duas causas. Continue verificando.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":933,"title":934,"description":935,"published":936,"category":814,"image":937,"draft":818},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" no Supabase: as três causas","O Supabase diz \"Invalid login credentials\" para senha errada, e-mail desconhecido e conta Google. Como saber qual é, e por que é vago.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":939,"title":940,"description":941,"published":942,"category":814,"image":943,"draft":818},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": o erro real","\"Edge Function returned a non-2xx status code\" quer dizer que sua função do Supabase respondeu com um erro. Veja onde ler o erro real.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":945,"title":946,"description":947,"published":948,"category":814,"image":949,"draft":818},"\u002Fblog\u002Fcertificate-not-trusted","Certificado não confiável: três causas além do vencimento","Certificado não confiável mesmo com a data certa? Ele cita outro endereço, assinou a si mesmo ou falta um elo na cadeia. Veja como saber qual.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":951,"title":952,"description":953,"published":954,"category":814,"image":955,"draft":818},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": leia as aspas","Supabase \"invalid input syntax for type uuid\": seu app enviou algo que não é um id. Leia as aspas, segure a consulta, mantenha a coluna.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":957,"title":958,"description":959,"published":960,"category":814,"image":961,"draft":818},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\", explicado","Supabase \"duplicate key value violates unique constraint\": o valor já está em uso. Ache a coluna, escolha uma correção e tire o valor da tela.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":849,"title":5,"description":817,"published":850,"category":814,"image":836,"draft":818},{"path":572,"title":964,"description":965,"published":966,"category":814,"image":967,"draft":818},"Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" mostra os nomes de argumentos que seu app enviou. Compare-os com a função.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":333,"title":969,"description":970,"published":971,"category":814,"image":972,"draft":818},"Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" costuma ser um nome que não bate. Quatro verificações e a linha que recarrega.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":974,"title":975,"description":976,"published":977,"category":814,"image":978,"draft":818},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": dois limites, um só código","Supabase \"Email Rate Limit Exceeded\" limita cada email que seu projeto envia: 2 por hora no remetente embutido. O que conta e como aumentar.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":980,"title":981,"description":982,"published":983,"category":814,"image":984,"draft":818},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" desconecta seus usuários. Três causas, e como o log do Auth separa cada uma.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":986,"title":987,"description":988,"published":989,"category":814,"image":990,"draft":818},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": três causas","Supabase \"permission denied for schema public\" é um grant que falta no schema. O que o removeu, e a linha que o devolve.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":992,"title":993,"description":994,"published":995,"category":814,"image":996,"draft":818},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": as três coisas que isso significa","Supabase \"Bucket not found\" é uma de três coisas: um link público para um bucket privado, um nome que não bate exatamente ou o projeto errado.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":998,"title":999,"description":1000,"published":1001,"category":814,"image":1002,"draft":818},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: qual chave parou de funcionar?","Um erro Supabase invalid JWT é o PGRST301: um token assinado não passou na verificação. Num projeto novo isso é a sessão, não a chave de API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":1004,"title":1005,"description":1006,"published":1007,"category":814,"image":1008,"draft":818},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" quase sempre é nenhuma","O Supabase devolve PGRST116, \"JSON object requested, multiple (or no) rows returned\", quando a consulta não achou nada. Linha escondida parece ausente.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":401,"title":1010,"description":1011,"published":1012,"category":814,"image":1013,"draft":818},"\"Database error saving new user\" no Supabase: onde olhar","\"Database error saving new user\" quer dizer que algo preso ao seu cadastro no Supabase falhou e tudo foi desfeito. O erro real está nos seus logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":1015,"title":1016,"description":1017,"published":1018,"category":814,"image":1019,"draft":818},"\u002Fblog\u002Fwhat-is-supabase","O que é Supabase? O banco de dados que seu builder escolheu","O que é Supabase: o banco de dados, o login e o armazenamento de arquivos do seu app. O Supabase cuida dos servidores; as regras das suas linhas são suas.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":1021,"title":1022,"description":1023,"published":1024,"category":814,"image":1025,"draft":818},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Uma chave AWS exposta no seu frontend não é como uma chave OpenAI","Uma chave de acesso da AWS exposta no seu frontend lê e grava no seu armazenamento. A solução costuma ser uma presigned URL, não uma chave nova.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1027,"title":1028,"description":1029,"published":1030,"category":814,"image":1031,"draft":818},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" ao enviar","\"New row violates row-level security policy for table objects\" quer dizer que o seu envio não tem regra insert. Deixar o bucket público não cria nenhuma.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":1033,"title":1034,"description":1035,"published":1036,"category":814,"image":1037,"draft":818},"\u002Fblog\u002Fbase44-security-scan","Scan de segurança do Base44: o que só ele enxerga","O scan de segurança do Base44 verifica sete tipos de problema por dentro. Esta é a metade que ele lê e mais ninguém, e a metade que ele nunca olha.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":1039,"title":1040,"description":1041,"published":1042,"category":814,"image":1043,"draft":818},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Sua chave de API vazou. A ordem em que agir","Uma chave de API vazou e você não sabe o que fazer primeiro. Nem toda chave no seu frontend é um vazamento, e a ordem importa mais que a pressa.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":1045,"title":1046,"description":1047,"published":1048,"category":814,"image":1049,"draft":818},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" sem desligar o RLS","\"Infinite recursion detected in policy for relation\" significa que a sua policy perguntou à tabela que ela protege. Veja como quebrar o círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":1051,"title":1052,"description":1053,"published":1054,"category":814,"image":1055,"draft":818},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" no Supabase, e a correção errada","\"No API key found in request\" significa que sua requisição chegou ao Supabase sem chave. Quase toda resposta aponta para as regras do seu banco.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":1057,"title":1058,"description":1059,"published":1060,"category":814,"image":1061,"draft":818},"\u002Fblog\u002Fis-base44-safe","O Base44 é seguro? O que vimos em 5.442 apps Base44","O Base44 é seguro? Rodamos nove verificações em 5.442 apps Base44 no ar. Quase todas tiraram B por motivos que o dono nunca escolheu.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":1063,"title":1064,"description":1065,"published":1066,"category":814,"image":1067,"draft":818},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Esconder uma chave de API: mova para uma Edge Function do Supabase","Esconder uma chave de API é tirá-la do navegador, e uma Edge Function do Supabase é o menor lugar para guardá-la. Dois passos em volta pesam mais.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":1069,"title":1070,"description":1071,"published":1072,"category":814,"image":1073,"draft":818},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Seu arquivo .env está exposto? Os doze caminhos para testar","Seu arquivo .env está exposto no seu próprio servidor web? Doze endereços dizem isso em um minuto, e um acerto significa que tudo nele já é público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":1075,"title":1076,"description":1077,"published":1078,"category":814,"image":1079,"draft":818},"\u002Fblog\u002Fis-v0-safe","Segurança do v0: os 1.790 aplicativos v0 escaneados tiraram A","A segurança do v0 medida em 1.790 aplicativos v0 no ar: todos tiraram A. Só 17 citavam um banco de dados, e é sobretudo isso que esse A mede.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":1081,"title":1082,"description":1083,"published":1084,"category":814,"image":1085,"draft":818},"\u002Fblog\u002Fis-bolt-safe","O Bolt é seguro? O que vimos em 1.123 aplicativos Bolt","O Bolt é seguro? Passamos 1.123 aplicativos Bolt no ar por nove verificações. A hospedagem saiu limpa. Os achados: chaves e tabelas abertas nos aplicativos.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":1087,"title":1088,"description":1089,"published":1090,"category":814,"image":1091,"draft":818},"\u002Fblog\u002Fis-supabase-down-or-your-app","O Supabase caiu ou o problema é o seu app? Como saber","O Supabase caiu ou o problema é o seu app? Um projeto pausado, um banco cheio e um erro seu parecem iguais. Quatro verificações separam os casos.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":1093,"title":1094,"description":1095,"published":1096,"category":814,"image":1097,"draft":818},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","O Supabase criptografa meus dados? Sim. Veja o que isso impede","O Supabase criptografa os dados? Sim: AES-256 em repouso, TLS em trânsito, SOC 2 e ISO 27001. O que cada um cobre, e o vazamento que nenhum deles impede.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":1099,"title":1100,"description":1101,"published":1102,"category":814,"image":1103,"draft":818},"\u002Fblog\u002Fsupabase-free-plan-limits","O Supabase é gratuito? Sim, com estes limites e sem backups","Sim: o plano gratuito do Supabase vai até 500 MB de banco e 5 GB de egress, sem nenhum backup. O que para em cada limite e o que muda no Pro de $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":1105,"title":1106,"description":1107,"published":1108,"category":924,"image":1109,"draft":818},"\u002Fblog\u002Ftest-your-supabase-backup","Teste o backup do seu Supabase antes do dia em que precisar","Como testar o backup do seu Supabase: restaurar num projeto de teste, contar as linhas, entrar e procurar a linha que falta num arquivo cortado.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":1111,"title":1112,"description":1113,"published":1114,"category":924,"image":1115,"draft":818},"\u002Fblog\u002Fsupabase-backup-github-action","Backup grátis do Supabase com uma GitHub Action, e a pegadinha","Um backup do Supabase com GitHub Action é grátis e serve para muitos apps. O workflow, a connection string certa e o egress de cada execução.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":1117,"title":1118,"description":1119,"published":1120,"category":924,"image":1121,"draft":818},"\u002Fblog\u002Fdownload-your-supabase-backup","Por que você não consegue baixar seu backup do Supabase","Você não consegue baixar seu backup do Supabase num projeto atual, porque a cópia diária é um snapshot físico. Como conferir e como ter uma cópia só sua.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":190,"title":1123,"description":1124,"published":1120,"category":814,"image":1125,"draft":818},"Supabase \"permission denied for table\": o grant que falta","A partir de 30 de outubro, uma tabela nova no Supabase responde \"permission denied for table\" até receber um grant. O e-mail mostra só metade.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":1127,"title":1128,"description":1129,"published":1130,"category":814,"image":1131,"draft":818},"\u002Fblog\u002Fopen-api-endpoint-exposed","Um endpoint de API aberto é um problema? Leia o JSON","Seu scan apontou um endpoint de API aberto. Se isso importa depende do que voltou, e a maioria dos que encontramos era da própria plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":1133,"title":1134,"description":1135,"published":1136,"category":814,"image":1137,"draft":818},"\u002Fblog\u002Flovable-security-scan","Escaneamento de segurança do Lovable: o que ele não prova","Escaneamento de segurança do Lovable: o que o Quick scan e o Deep scan checam, quando cada um roda, e a única coisa que nenhum escaneamento por dentro prova.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":1139,"title":1140,"description":1141,"published":1142,"category":924,"image":1143,"draft":818},"\u002Fblog\u002Fsupabase-backup-auth-users","Por que seu dump do Supabase não tem usuários dentro","Rode supabase db dump sozinho e você recebe a forma do seu banco e nenhuma das linhas dele, sem o schema auth onde seus usuários moram.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":1145,"title":1146,"description":1147,"published":1148,"category":814,"image":1149,"draft":818},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domínio expirado, site fora do ar: o que acontece agora","Seu domínio expirou e seu site está fora do ar. O relógio que começa a correr, por que o certificado é o problema menor, e como conferir os dois.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":1151,"title":1152,"description":1153,"published":1154,"category":814,"image":1155,"draft":818},"\u002Fblog\u002Fis-lovable-safe","O Lovable é seguro? O que vimos em 18.554 aplicativos Lovable","O Lovable é seguro? Passamos 18.554 aplicativos Lovable no ar por nove verificações. A plataforma foi a mais limpa de cinco. Os achados estavam nos aplicativos.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":1157,"title":1158,"description":1159,"published":1160,"category":814,"image":1161,"draft":818},"\u002Fblog\u002Fvibe-coded-app-security-checklist","O checklist de segurança do vibe coding, em nove verificações","Um checklist de segurança do vibe coding com nove itens, cada um verificável no seu app de fora por qualquer pessoa, e cada um com um teste de uma linha.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":1163,"title":1164,"description":1165,"published":1166,"category":814,"image":1167,"draft":818},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Uma chave secreta da Stripe no frontend pode mover dinheiro","Uma chave secreta da Stripe exposta no seu frontend pode reembolsar, cobrar e ler cada ficha de cliente que você tem. Sua chave pk_live_ é que deve estar aí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":1169,"title":1170,"description":1171,"published":1172,"category":814,"image":1173,"draft":818},"\u002Fblog\u002Fvite-and-next-public-env-vars","Variáveis de ambiente do Vite expostas: o prefixo diz publique isto","Variáveis de ambiente do Vite expostas no seu app: fizeram o que o prefixo pediu. VITE_ e NEXT_PUBLIC_ significam publique isto, e a IA nunca soube o custo.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":1175,"title":1176,"description":1177,"published":1178,"category":814,"image":1179,"draft":818},"\u002Fblog\u002Fbase44-source-maps","Segurança no Base44: o que um scan aponta e o que é seu para corrigir","Segurança no Base44 em 5.438 apps escaneados: três achados em quase todos são da plataforma, o source map é o selo do Base44, e a sua parte é uma lista curta.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":1181,"title":1182,"description":1183,"published":1184,"category":814,"image":1185,"draft":818},"\u002Fblog\u002Fis-cursor-ai-safe","O Cursor AI é seguro? O editor, o código e o app que você publicou","O Cursor AI é seguro? Três perguntas em uma busca: o que o Cursor guarda, o que o código que ele escreve erra, e se o app que você publicou está aberto.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":1187,"title":1188,"description":1189,"published":1190,"category":814,"image":1191,"draft":818},"\u002Fblog\u002Fis-replit-safe","O Replit é seguro? O que vimos em 3.042 aplicativos Replit no ar","O Replit é seguro? Passamos 3.042 aplicativos Replit no ar por nove verificações externas. Os achados estavam no aplicativo publicado, não no host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":1193,"title":1194,"description":1195,"published":1196,"category":924,"image":1197,"draft":818},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: sua cópia do banco não tem nenhum arquivo","Um Supabase storage backup é uma tarefa à parte. Os backups do banco guardam a lista dos seus arquivos e nenhum deles, então cada upload fica quebrado.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":1199,"title":1200,"description":1201,"published":1202,"category":924,"image":1203,"draft":818},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery do Supabase: preço e limites","O point-in-time recovery do Supabase rebobina seu banco para qualquer segundo da última semana. Custa $100 por mês além do Pro e cobre só o banco.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":1205,"title":1206,"description":1207,"published":1208,"category":924,"image":1209,"draft":818},"\u002Fblog\u002Fsupabase-project-paused-recover","Projeto Supabase pausado? Seus dados continuam lá","O Supabase pausou seu projeto depois de uma semana sem atividade. Nada foi apagado, Restaurar fica ao lado do nome e você tem um ano antes disso mudar.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":1211,"title":1212,"description":1213,"published":1214,"category":814,"image":1215,"draft":818},"\u002Fblog\u002Fsafest-ai-app-builder","Qual builder de apps com IA é mais seguro? 30.998 apps testados","Qual builder de apps com IA é mais seguro? Escaneamos 30.998 apps no ar do Lovable, Base44, Replit, v0 e Bolt. O builder não é o que decide sua nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":508,"title":1217,"description":1218,"published":1219,"category":814,"image":1220,"draft":818},"Ative Row Level Security em toda tabela do Supabase e comprove","Ativar Row Level Security no Supabase sem política fecha a tabela por completo. Uma política sem a chave ligada não faz nada. Aqui está o SQL, e o teste.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":513,"title":1222,"description":1223,"published":1224,"category":814,"image":1225,"draft":818},"Supabase \"RLS disabled in public\": o que o aviso não vê","O Supabase marca \"RLS disabled in public\" como erro. Ele não diz nada sobre a política de leitura que deixa a sua tabela igualmente aberta.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":1227,"title":1228,"description":1229,"published":1230,"category":814,"image":1231,"draft":818},"\u002Fblog\u002Frotate-supabase-service-role-key","Como rotacionar uma chave service_role do Supabase vazada","O Supabase manda fechar o vazamento primeiro. Outros guias mandam rotacionar agora. O que vale depende de para onde a sua chave service_role vazou.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1233,"title":1234,"description":1235,"published":1236,"category":814,"image":1237,"draft":818},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Scanners de segurança para vibe coding comparados, o nosso incluído","O melhor scanner de segurança para vibe coding depende de três perguntas que nenhuma lista de recursos responde. Oito ferramentas comparadas, com preços.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1239,"title":1240,"description":1241,"published":1242,"category":814,"image":1243,"draft":818},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: faça você mesmo as cinco verificações","Um Supabase security checker lê o seu app publicado em vez das configurações do projeto. Aqui estão as cinco verificações e como fazer cada uma sozinho.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1245,"title":1246,"description":1247,"published":1248,"category":814,"image":1249,"draft":818},"\u002Fblog\u002Fvibe-coding-security-scanner","Scanner de segurança para vibe coding: o que ele não vê","Um scanner de segurança para vibe coding lê seu app no ar, de fora. O que isso cobre, as quatro coisas que ele não consegue ver e como ler o resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1251,"title":1252,"description":1253,"published":1254,"category":814,"image":1255,"draft":818},"\u002Fblog\u002Fmissing-security-headers","Cabeçalhos de segurança faltando: quando isso importa","Cabeçalhos de segurança faltando é o achado que nosso scanner mais imprime. Contra o que eles protegem e quando são a linha menos urgente do relatório.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1257,"title":1258,"description":1259,"published":1260,"category":814,"image":1261,"draft":818},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Sua chave de API da OpenAI está exposta no frontend. Troque-a.","Uma chave de API da OpenAI exposta no frontend não pode ser presa a um domínio. Troque-a hoje, mova a chamada para o seu servidor e limite o gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1263,"title":1264,"description":1265,"published":1266,"category":814,"image":1267,"draft":818},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Chave de API exposta no frontend: o que 30.998 apps entregam","Uma chave de API exposta no seu frontend costuma ser uma chave do Google Maps. Escaneamos 30.998 apps vibe-coded e contamos quais segredos vazam de verdade.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1269,"title":1270,"description":1271,"published":1272,"category":924,"image":1273,"draft":818},"\u002Fblog\u002Fsupabase-backup-tools-compared","Ferramentas de backup do Supabase comparadas, a nossa incluída","Quatro tipos de ferramenta de backup do Supabase, o que cada uma copia de verdade e quando uma GitHub Action gratuita ganha de pagar, nós inclusive.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1275,"title":1276,"description":1277,"published":1278,"category":814,"image":1279,"draft":818},"\u002Fblog\u002Freplit-secrets-explained","Como usar secrets no Replit, e o que ainda assim é publicado","Como usar secrets no Replit: adicionar um, ler de volta e resolver as duas causas do undefined. E as chaves que a ferramenta Secrets não consegue proteger.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1281,"title":1282,"description":1283,"published":1284,"category":924,"image":1285,"draft":818},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups do plano gratuito do Supabase: como fazer sem terminal","No plano gratuito do Supabase não existe backup nenhum: a cópia é você que faz. Como fazer uma pelo painel e o que a rota do CSV deixa para trás.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1287,"title":1288,"description":1289,"published":1290,"category":814,"image":1291,"draft":818},"\u002Fblog\u002Fis-supabase-secure","O Supabase é seguro? É. Seu projeto é outra pergunta","O Supabase é seguro? A plataforma é auditada, criptografada e passa por pentests. A documentação deles diz onde isso termina e começam suas configurações.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1293,"title":1294,"description":1295,"published":1296,"category":814,"image":1297,"draft":818},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Onde ficam as chaves de API do Supabase: anon, service_role e URL","A URL do projeto, a chave anon e a chave service_role ficam todas numa página do painel. Aqui está onde ela fica, e qual dos quatro valores vai no seu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1299,"title":1300,"description":1301,"published":1302,"category":814,"image":1303,"draft":818},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy no Supabase. E agora?","\"New row violates row-level security policy\" significa que o Supabase recusou uma escrita. O conserto rápido reabre a tabela para qualquer um.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1305,"title":1306,"description":1307,"published":1308,"category":814,"image":1309,"draft":818},"\u002Fblog\u002Fcors-wildcard-security-risk","Um curinga CORS é um risco de segurança? Quase nunca.","Um curinga CORS é um risco de segurança? Em geral é o padrão do seu builder e não entrega nada que o seu servidor já não desse a qualquer um que pedisse.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":659,"title":1311,"description":1312,"published":1313,"category":924,"image":1314,"draft":818},"Branching do Supabase não é backup. Ele só anda para a frente.","Por que o branching do Supabase não é backup: um branch começa sem os seus dados e um merge só leva o esquema. Para que ele serve e o que usar no lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1316,"title":1317,"description":1318,"published":1319,"category":924,"image":1320,"draft":818},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Como restaurar um backup do Supabase, e o que quebra depois","Como restaurar um backup do Supabase pelo painel ou por um arquivo de dump, o que a restauração substitui e por que o seu app pode continuar quebrado no fim.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1322,"title":1323,"description":1324,"published":1325,"category":814,"image":1326,"draft":818},"\u002Fblog\u002Fsupabase-storage-bucket-public","Seu bucket do Supabase Storage é público. Isso é um problema?","Um bucket público do Supabase Storage significa que quem tem a URL de um arquivo pode abri-lo. Não significa que alguém possa listar o que está lá dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1328,"title":1329,"description":1330,"published":1331,"category":814,"image":1332,"draft":818},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Uma chave de API do Google no frontend é um problema?","Uma chave de API do Google exposta no seu frontend é a chave que nosso scanner mais encontra, e quase sempre está tudo bem. Um ajuste gratuito decide isso.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1334,"title":1335,"description":1336,"published":1337,"category":924,"image":1338,"draft":818},"\u002Fblog\u002Fai-agent-deleted-my-database","Um agente de IA apagou meus dados do Supabase. O que eu recupero?","Um agente de IA apagou dados do seu banco. O que você recupera já estava decidido antes de ele rodar, e os próximos minutos decidem o resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1340,"title":1341,"description":1342,"published":1343,"category":814,"image":1344,"draft":818},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Qualquer um consegue ler seu banco Supabase? Testamos 3.680 apps","Qualquer um consegue ler seu banco de dados Supabase sem fazer login? Escaneamos 30.998 apps no ar criadas com builders de IA e medimos quantas dizem que sim.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1346,"title":1347,"description":1348,"published":1343,"category":814,"image":1349,"draft":818},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps expostos: seu app está publicando o código original","Um source map exposto deixa qualquer um ler o código original do seu app, comentários incluídos. A verificação de 30 segundos e o que importa de verdade.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1351,"title":1352,"description":1353,"published":1354,"category":814,"image":1355,"draft":818},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: é a mesma coisa que a anon key?","O Supabase trocou anon e service_role por chaves publicáveis e secretas. Qual delas pertence ao seu app e qual nunca deve estar lá?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1357,"title":1358,"description":1359,"published":1360,"category":924,"image":1361,"draft":818},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","O Supabase faz backup do meu banco de dados? Depende do plano.","O Supabase faz backup do seu banco de dados? Todo dia nos planos pagos, e nada no gratuito. Como descobrir o que você tem e o que essa cópia não cobre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1363,"title":1364,"description":1365,"published":1366,"category":814,"image":1367,"draft":818},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","O Supabase Row Level Security está ligado. A tabela continua pública.","Ligar o Supabase Row Level Security não protege uma tabela. Quem protege são as políticas, e a que consertou o seu app pode deixar qualquer um entrar.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1369,"title":1370,"description":1371,"published":1366,"category":924,"image":1372,"draft":818},"\u002Fblog\u002Fversion-history-is-not-a-backup","O histórico de versões não é backup. Ele não desfaz um delete.","Lovable e Bolt guardam um histórico de versões do seu código. Seu banco de dados é um serviço à parte, e voltar atrás não traz os seus dados de volta.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1374,"title":1375,"description":1376,"published":1377,"category":924,"image":1378,"draft":818},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Três formas de fazer backup de um banco Supabase, e o que falta","O painel, o pg_dump e um serviço gerenciado. O que cada um salva de verdade, o que deixa de fora sem avisar e qual sobrevive a perder a conta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1380,"title":1381,"description":1382,"published":1377,"category":814,"image":1383,"draft":818},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Quais chaves de API são seguras no navegador e quais não são","Sua chave anon do Supabase foi feita para ser pública. Sua chave service_role não, e ela ignora todas as regras que você criar. Como diferenciar as duas.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213649127]