[{"data":1,"prerenderedAt":1145},["ShallowReactive",2],{"blog-pt-database-error-deleting-user":3,"blog-index-pt":619},{"id":4,"title":5,"body":6,"category":577,"cover":578,"coverAlt":579,"description":580,"draft":581,"extension":582,"faq":583,"image":598,"keywords":599,"meta":607,"navigation":608,"ogTitle":609,"path":610,"published":611,"seo":612,"stem":613,"tldr":614,"updated":611,"__hash__":618},"blog_pt\u002Fblog\u002Fdatabase-error-deleting-user.md","\"Database error deleting user\" no Supabase, e o que vai junto",{"type":7,"value":8,"toc":563},"minimark",[9,13,24,27,34,39,42,59,65,69,72,75,98,101,120,124,131,134,140,155,166,181,184,192,206,210,213,219,222,225,231,234,238,241,305,322,325,331,334,348,353,357,366,379,393,398,402,405,433,444,451,455,458,474,477,485,489,495,503,525,529,555],[10,11,12],"p",{},"Você abre Authentication → Users no painel do Supabase e exclui uma conta.\nTalvez a pessoa tenha pedido para ser removida, talvez seja uma conta de teste\nque você criou na semana passada. O painel responde:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","Failed to delete user: Database error deleting user\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"A conta continua na lista. O app que você fez com Lovable, Bolt, v0, Cursor,\nClaude Code ou Replit funcionou o tempo todo, e a frase não cita tabela nenhuma\nnem motivo nenhum.",[10,28,29,30,33],{},"A primeira resposta que você vai achar é uma linha de SQL: coloque\n",[21,31,32],{},"on delete cascade"," no que está atrapalhando. Funciona. Também decide, para cada\nconta excluída dali em diante, quais outras linhas vão junto, e ninguém volta a\nperguntar isso para você. Então leia primeiro o erro real, e depois tome essa\ndecisão tabela por tabela.",[35,36,38],"h2",{"id":37},"o-que-quer-dizer-database-error-deleting-user-no-supabase","O que quer dizer \"Database error deleting user\" no Supabase?",[10,40,41],{},"O seu banco recusou a exclusão e o Supabase desfez tudo, então a conta está\nexatamente como estava.",[10,43,44,45,48,49,52,53,58],{},"Excluir um usuário é trabalho do Supabase Auth, o serviço por trás do login do\nseu app. No código-fonte do Auth, a exclusão acontece dentro de uma única\ntransação, um grupo de mudanças que acontecem todas ou nenhuma, e o passo central\ndela tira a linha da pessoa de ",[21,46,47],{},"auth.users",". Se qualquer coisa no seu banco se\nopõe, a transação é revertida e o Auth responde com essa única frase. O Supabase\nlista a mensagem como HTTP 500 com o código ",[21,50,51],{},"unexpected_failure",", ao lado da\ngêmea do cadastro,\n",[54,55,57],"a",{"href":56},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\"",".",[10,60,61,62,64],{},"Pense no seu banco como um clube. ",[21,63,47],{}," é o livro de sócios, e cada sócio\ntem um número: o id de usuário. Os seus outros livros copiam esse número nas\nlinhas deles, seja um perfil, um pedido, um post ou um comentário. Riscar alguém\ndo livro de sócios é coisa de uma linha. Só que todo outro livro ainda carrega o\nnúmero, e enquanto ninguém escreveu o que fazer com essas linhas, o secretário do\nclube se recusa.",[35,66,68],{"id":67},"onde-está-o-erro-real","Onde está o erro real?",[10,70,71],{},"Nos logs do Postgres do seu projeto, no momento em que a exclusão falhou.",[10,73,74],{},"A nota de troubleshooting do Supabase sobre os erros na gestão de usuários\nmostra o caminho. Tente a exclusão uma vez e anote a hora. Depois, no painel:",[76,77,78,91],"ol",{},[79,80,81,82,86,87,90],"li",{},"Abra ",[83,84,85],"strong",{},"Logs"," e leia os logs de ",[83,88,89],{},"Auth"," nesse horário. A entrada é o registro\nque o próprio Auth guardou da exclusão que falhou.",[79,92,93,94,97],{},"Abra os logs do ",[83,95,96],{},"Postgres"," no mesmo horário. Essa linha é o erro real, e ela\ncita uma tabela, uma regra ou uma permissão.",[10,99,100],{},"A mesma nota lista três causas, e a linha do log diz qual é a sua:",[102,103,104,110,115],"ul",{},[79,105,106,107,109],{},"um trigger na tabela ",[21,108,47],{}," que falha",[79,111,112,113],{},"uma restrição que não está sendo cumprida, o que numa exclusão quer dizer uma\nforeign key de outra tabela apontando para ",[21,114,47],{},[79,116,117,118],{},"o Prisma, que segundo a nota pode quebrar as permissões em ",[21,119,47],{},[35,121,123],{"id":122},"uma-tabela-que-ainda-aponta-para-o-usuário","Uma tabela que ainda aponta para o usuário",[10,125,126,127,130],{},"Se a linha do Postgres diz ",[21,128,129],{},"violates foreign key constraint",", uma linha de alguma\ndas suas tabelas ainda guarda o id desse usuário, e o Postgres não remove uma\npessoa para quem algo ainda aponta.",[10,132,133],{},"A nota do Supabase imprime a forma que isso toma:",[14,135,138],{"className":136,"code":137,"language":19},[17],"ERROR:  23503: update or delete on table \"users\" violates foreign key constraint \"profiles_id_fkey\" on table \"profiles\"\nDETAIL:  Key (id)=(7428a53c-75b7-4531-9ae9-1567d9c4ac0a) is still referenced from table \"profiles\".\n",[21,139,137],{"__ignoreMap":23},[10,141,142,143,146,147,150,151,154],{},"Uma foreign key é uma regra numa coluna que diz que todo valor dela precisa\nexistir em outra tabela. Aqui a regra se chama ",[21,144,145],{},"profiles_id_fkey",", fica na sua\ntabela ",[21,148,149],{},"profiles",", e a linha ",[21,152,153],{},"Key"," é o id do usuário que você tentou excluir. No\nclube, é uma linha do livro de perfis com o número do sócio, e o secretário se\nrecusando a riscar o nome enquanto ela estiver lá.",[10,156,157,158,161,162,58],{},"A mesma regra também recusa pelo outro lado. Uma linha nova que cita um usuário\nque não existe volta como\n",[21,159,160],{},"insert or update on table … violates foreign key constraint",", e\n",[54,163,165],{"href":164},"\u002Fblog\u002Fviolates-foreign-key-constraint","essa mensagem tem um post só dela",[10,167,168,169,172,173,176,177,180],{},"A recusa é o padrão. Uma foreign key criada sem nada depois de\n",[21,170,171],{},"references auth.users"," recebe o comportamento que o Postgres chama de\n",[21,174,175],{},"no action",", e o guia do Supabase sobre exclusões em cascata diz isso com todas\nas letras: ",[21,178,179],{},"NO ACTION"," é o comportamento padrão se você não especificar nada. Uma\ntabela que o seu builder criou assim funciona perfeitamente até a primeira vez\nque alguém é excluído.",[10,182,183],{},"Para ver cada tabela que aponta para os seus usuários, e o que cada uma faz numa\nexclusão, rode isto no SQL Editor:",[14,185,190],{"className":186,"code":188,"language":189,"meta":23},[187],"language-sql","select conrelid::regclass as table_name,\n       conname as rule,\n       case confdeltype\n         when 'c' then 'cascade'\n         when 'n' then 'set null'\n         when 'd' then 'set default'\n         when 'r' then 'restrict'\n         else 'no action'\n       end as on_delete\nfrom pg_constraint\nwhere contype = 'f'\n  and confrelid = 'auth.users'::regclass\n  and connamespace \u003C> 'auth'::regnamespace;\n","sql",[21,191,188],{"__ignoreMap":23},[10,193,194,195,198,199,201,202,205],{},"Ela só lê o catálogo do próprio Postgres e não muda nada. A última linha deixa\nde fora as tabelas do Supabase no schema ",[21,196,197],{},"auth",". Cada linha que mostra\n",[21,200,175],{}," ou ",[21,203,204],{},"restrict"," é uma tabela que vai recusar a exclusão sempre que\ntiver uma linha desse usuário.",[35,207,209],{"id":208},"o-que-o-on-delete-cascade-apaga","O que o on delete cascade apaga?",[10,211,212],{},"Cada linha que aponta para o usuário, depois cada linha que aponta para essas, em\ntoda exclusão a partir daí.",[10,214,215,216,218],{},"É a correção que entregam para você primeiro, e o guia de gestão de usuários do\nSupabase usa essa correção numa tabela de perfis: ele pede que você especifique\n",[21,217,32],{}," na referência. Para um perfil, está certo. Um perfil descreve\na pessoa e mais nada, então deve sair quando ela sai.",[10,220,221],{},"O problema começa quando as mesmas palavras vão para todas as tabelas. O guia de\ncascata do Supabase descreve o comportamento sem rodeios: quando uma linha é\napagada da tabela pai, todas as linhas relacionadas nas tabelas filhas são\napagadas também. E continua descendo. No próprio exemplo do guia, uma única\nexclusão na tabela de cima esvazia as duas tabelas abaixo dela.",[10,223,224],{},"No clube, uma cascata manda o secretário arrancar cada linha com o número do\nsócio, e depois cada linha de qualquer outro livro que apontava para uma linha\narrancada. Imagine um usuário que escreveu posts, com comentários de outras\npessoas apontando para esses posts. Com cascata nos dois, excluir esse único\nusuário remove os posts dele e os comentários de todo mundo neles.",[226,227],"diagram",{"alt":228,"caption":229,"src":230},"Três livros lado a lado ligados por setas. No livro de sócios à esquerda, uma linha está riscada. No livro do meio, as duas linhas com a ficha desse sócio foram arrancadas. No livro da direita também foram arrancadas as linhas que apontavam para essas duas, e a maioria leva fichas de outros sócios, em outras cores.","Uma cascata segue cada regra que aponta para a linha apagada, e depois cada regra que aponta para essas. O último livro perde linhas que eram de outras pessoas.","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fthe-chain-1600x700.png",[10,232,233],{},"Nada avisa o que foi junto. O Auth responde a uma exclusão bem-sucedida com uma\nresposta vazia, o painel mostra uma conta a menos, e as linhas que saíram no\nmesmo momento estão faltando na próxima vez que alguém procura por elas.",[35,235,237],{"id":236},"o-que-cada-tabela-guarda","O que cada tabela guarda",[10,239,240],{},"Decida tabela por tabela, porque cada uma guarda algo diferente sobre a pessoa\nque saiu.",[242,243,244,262],"table",{},[245,246,247],"thead",{},[248,249,250,254,259],"tr",{},[251,252,253],"th",{},"O que a tabela guarda",[251,255,256],{},[21,257,258],{},"on delete",[251,260,261],{},"Quando o usuário é excluído",[263,264,265,279,292],"tbody",{},[248,266,267,271,276],{},[268,269,270],"td",{},"Só a pessoa: um perfil, as configurações dela",[268,272,273],{},[21,274,275],{},"cascade",[268,277,278],{},"As linhas vão junto",[248,280,281,284,289],{},[268,282,283],{},"Coisas de que outros ainda precisam: um comentário na conversa de outro, um pagamento",[268,285,286],{},[21,287,288],{},"set null",[268,290,291],{},"As linhas ficam, com a coluna de dono vazia",[248,293,294,297,302],{},[268,295,296],{},"Qualquer coisa que você queira resolver à mão primeiro",[268,298,299,301],{},[21,300,175],{}," (o padrão)",[268,303,304],{},"A exclusão é recusada enquanto elas existirem",[10,306,307,308,310,311,317,318,321],{},"O ",[21,309,288],{}," vem com duas condições. A coluna precisa aceitar valores vazios, ou\na exclusão falha de novo com uma mensagem própria,\n",[54,312,314],{"href":313},"\u002Fblog\u002Fnull-value-violates-not-null-constraint",[21,315,316],{},"null value in column … violates not-null constraint",". E uma policy escrita como\n",[21,319,320],{},"user_id = auth.uid()"," nunca mais vai mostrar essa linha para ninguém, porque em\nSQL nada é igual a um valor vazio. A linha fica guardada, e o seu app deixa de\nmostrar essa linha para qualquer pessoa.",[10,323,324],{},"Mudar uma regra quer dizer tirar e colocar de novo com o comportamento novo, que\né o que a nota do Supabase recomenda:",[14,326,329],{"className":327,"code":328,"language":189,"meta":23},[187],"alter table public.profiles\n  drop constraint profiles_id_fkey,\n  add constraint profiles_id_fkey\n    foreign key (id) references auth.users (id) on delete cascade;\n",[21,330,328],{"__ignoreMap":23},[10,332,333],{},"Use o nome de regra que a consulta acima mostrou, com a sua própria tabela e\ncoluna.",[10,335,336,337,340,341,344,345,347],{},"Existe mais um caminho, e ele mantém todas as linhas. O Supabase Auth consegue\nfazer uma exclusão suave de uma conta: ",[21,338,339],{},"auth.admin.deleteUser()"," aceita a opção\n",[21,342,343],{},"shouldSoftDelete",", e com ela o Auth mantém a linha em ",[21,346,47],{},", marca como\nexcluída, embaralha o email e o telefone, apaga a senha e os metadados, e encerra\nas sessões. Nada foi removido, então nenhuma foreign key dispara. Isso roda num\nservidor com a sua chave secreta, nunca no navegador.",[226,349],{"alt":350,"caption":351,"src":352},"O mesmo sócio excluído desenhado três vezes, uma faixa para no action, cascade e set null. Na primeira, uma barreira para a exclusão e tanto a linha do sócio quanto a que aponta para ela ficam. Na segunda, a linha que aponta para o sócio é arrancada junto. Na terceira, essa linha fica, com um espaço tracejado vazio onde estava a ficha do sócio.","A mesma exclusão sob três regras. A primeira recusa e não muda nada, a segunda leva junto a linha que aponta para o sócio, e a terceira mantém essa linha com um espaço vazio.","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fthree-outcomes-1600x760.png",[35,354,356],{"id":355},"um-trigger-que-não-alcança-a-sua-tabela","Um trigger que não alcança a sua tabela",[10,358,126,359,362,363,365],{},[21,360,361],{},"permission denied for table",", um trigger em\n",[21,364,47],{}," rodou durante a exclusão e tentou mexer numa tabela em que não tem\npermissão de entrar.",[10,367,368,369,372,373,375,376,58],{},"O papel com que o Supabase Auth trabalha, ",[21,370,371],{},"supabase_auth_admin",", só tem as\npermissões que o trabalho dele precisa. A nota do Supabase diz assim: quando um\ntrigger executado por ",[21,374,371],{}," age fora do schema auth, ele causa um\nerro de permissão. Um trigger que faz a limpeza depois de uma conta excluída, por\nexemplo gravando numa tabela de log sua, falha exatamente assim, a menos que a\nfunção dele tenha sido criada com ",[21,377,378],{},"security definer",[10,380,381,382,384,385,388,389,392],{},"O conserto é o mesmo do cadastro: uma função ",[21,383,378],{},", criada pelo\npapel ",[21,386,387],{},"postgres",", que faz uma única coisa bem delimitada.\n",[54,390,391],{"href":56},"A versão deste erro no cadastro"," explica\nlinha por linha, incluindo o search path vazio que a mantém segura.",[10,394,395,396,58],{},"Se o seu app usa Prisma, leia primeiro a terceira causa na nota do Supabase,\nporque ela cita o Prisma como uma das formas de quebrar as permissões em\n",[21,397,47],{},[35,399,401],{"id":400},"o-que-acontece-com-os-arquivos-que-a-pessoa-enviou","O que acontece com os arquivos que a pessoa enviou?",[10,403,404],{},"Num projeto atual, a exclusão passa, e os arquivos ficam onde estão.",[10,406,407,408,411,412,415,416,418,419,422,423,426,427,429,430,432],{},"O guia de gestão de usuários do Supabase ainda avisa que você não consegue\nexcluir um usuário que é dono de objetos no Supabase Storage. Isso era verdade\nenquanto ",[21,409,410],{},"storage.objects",", a tabela em que o Storage guarda uma linha para cada\narquivo, tinha uma foreign key chamada ",[21,413,414],{},"objects_owner_fkey"," apontando para\n",[21,417,47],{},". O Storage já removeu essa chave nas próprias migrações de schema\n(",[21,420,421],{},"0017-drop-owner-foreign-key.sql","), e o guia dele sobre propriedade de arquivos\nagora diz que o dono fica numa coluna ",[21,424,425],{},"owner_id",". Se a consulta lá em cima listar\n",[21,428,410],{}," com ",[21,431,414],{},", o seu projeto ainda tem a regra\nantiga e o aviso do guia vale para você.",[10,434,435,436,439,440,58],{},"Senão, cada arquivo que a pessoa enviou fica no bucket depois que ela vai\nembora. No clube, os casacos continuam nos ganchos com uma ficha que ninguém tem\nmais. Uma policy escrita como ",[21,437,438],{},"owner_id = auth.uid()::text"," nunca mais vai\nencontrar esses arquivos, e um arquivo num bucket público continua sendo servido\npara qualquer um que tenha o link. Se um estranho consegue listar os arquivos de\num bucket seu é uma das verificações do\n",[54,441,443],{"href":442},"\u002Fsecurity-scanner","scan gratuito do Reeve",[10,445,446,447,58],{},"Para tirar esses arquivos, passe pelo próprio Storage, pela página Storage do\npainel ou pela API do Storage. Um delete direto em SQL nas tabelas dele é\nrecusado, e o Storage diz por quê: \"Direct deletion from storage tables is not\nallowed. Use the Storage API instead.\" O que uma cópia do banco guarda desses\narquivos, e o que deixa de fora, está em\n",[54,448,450],{"href":449},"\u002Fblog\u002Fsupabase-storage-backup","como fazer backup do Supabase Storage",[35,452,454],{"id":453},"faça-uma-cópia-antes-de-mudar-uma-foreign-key","Faça uma cópia antes de mudar uma foreign key",[10,456,457],{},"O Postgres não tem lixeira, e uma cascata remove linhas de tabelas que você nem\nestava olhando.",[10,459,460,461,463,464,468,469,473],{},"O que uma cascata ou um ",[21,462,288],{}," muda é definitivo assim que a exclusão dá\ncerto, e o único caminho de volta é uma cópia feita antes. O plano gratuito do\nSupabase não guarda nenhum backup. O Pro guarda 7 dias de cópias diárias, o Team\n14 e o Enterprise até 30, e todas ficam dentro do mesmo projeto Supabase.\n",[54,465,467],{"href":466},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Copiar o seu banco por conta própria","\nleva poucos comandos, e\n",[54,470,472],{"href":471},"\u002Fblog\u002Fsupabase-backup-auth-users","uma cópia que inclua os seus usuários"," precisa\ndo terceiro dos três comandos que o Supabase publica.",[10,475,476],{},"Depois teste as regras novas numa conta de teste antes de uma real. Crie uma\nconta, dê a ela uma linha em cada tabela que a consulta listou, exclua a conta e\nveja o que sobrou em cada tabela.",[10,478,479,480,484],{},"Se você prefere que essa cópia já exista antes de alguém apertar excluir, é para\nisso que servem os ",[54,481,483],{"href":482},"\u002Fsupabase-backups","backups do Supabase"," do Reeve.",[35,486,488],{"id":487},"um-caminho-de-volta-quando-uma-exclusão-leva-mais-do-que-devia","Um caminho de volta quando uma exclusão leva mais do que devia",[10,490,491,494],{},[83,492,493],{},"Uma cascata não avisa nada do que removeu."," Você descobre quando alguém\npergunta onde foram parar os comentários dele.",[10,496,497],{},[83,498,499,502],{},[54,500,501],{"href":482},"O Reeve Care"," guarda uma cópia do seu banco Supabase de\nantes da exclusão:",[102,504,505,508,511,514,517],{},[79,506,507],{},"uma cópia criptografada conforme uma agenda, guardada no armazenamento do próprio Reeve na UE, fora da sua conta Supabase",[79,509,510],{},"cada cópia verificada antes de contar, contando as linhas de cada tabela",[79,512,513],{},"uma restauração em um clique que salva o que está lá agora antes de substituir",[79,515,516],{},"também os seus arquivos enviados, assim que você conectar uma credencial de Storage",[79,518,519,520,524],{},"tudo o que o ",[54,521,523],{"href":522},"\u002Fwebsite-monitoring","Reeve Monitor"," faz: as nove verificações do seu app no ar a cada hora, e uma verificação de disponibilidade a cada 60 segundos",[35,526,528],{"id":527},"o-que-fazer-hoje","O que fazer hoje",[530,531,532],"key-takeaways",{},[102,533,534,537,540,549,552],{},[79,535,536],{},"Tente a exclusão uma vez, anote a hora e leia a linha do log do Postgres desse momento antes de mudar qualquer coisa.",[79,538,539],{},"Se ela citar uma foreign key, rode a consulta acima para listar cada tabela que aponta para os seus usuários e o que cada uma faz numa exclusão.",[79,541,542,543,545,546,548],{},"Decida tabela por tabela: ",[21,544,275],{}," para linhas que só descrevem a pessoa, ",[21,547,288],{}," para linhas de que outros ainda precisam, o padrão para tudo o que você quer tirar à mão.",[79,550,551],{},"Faça uma cópia do banco antes de mudar qualquer uma dessas regras, e teste as regras novas primeiro numa conta de teste.",[79,553,554],{},"Tire também os arquivos da pessoa pelo Storage. Num projeto atual, a conta sai e os arquivos ficam.",[10,556,557,558,562],{},"Se linhas já foram embora além do que você queria,\n",[54,559,561],{"href":560},"\u002Fblog\u002Fai-agent-deleted-my-database","o que dá para recuperar depois de uma exclusão","\nmostra onde olhar, em ordem.",{"title":23,"searchDepth":564,"depth":564,"links":565},3,[566,568,569,570,571,572,573,574,575,576],{"id":37,"depth":567,"text":38},2,{"id":67,"depth":567,"text":68},{"id":122,"depth":567,"text":123},{"id":208,"depth":567,"text":209},{"id":236,"depth":567,"text":237},{"id":355,"depth":567,"text":356},{"id":400,"depth":567,"text":401},{"id":453,"depth":567,"text":454},{"id":487,"depth":567,"text":488},{"id":527,"depth":567,"text":528},"Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcover-1200x630.png","Um livro de sócios com uma linha riscada e, atrás, mais dois livros de onde foram arrancadas as linhas com a mesma ficha.","\"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.",false,"md",[584,586,589,592,595],{"q":38,"a":585},"Quer dizer que o Supabase Auth tentou tirar a linha da pessoa de auth.users, algo no seu banco recusou, e a exclusão inteira foi desfeita. A conta está exatamente como estava. A mensagem não cita nenhuma tabela, e a linha que cita está nos logs do Postgres do seu projeto no mesmo momento.",{"q":587,"a":588},"Devo adicionar on delete cascade para resolver?","Numa tabela que só descreve a pessoa, como uma tabela de perfis, sim, e o próprio guia do Supabase faz exatamente isso. Numa tabela com coisas de que outras pessoas ainda precisam, como comentários ou pedidos, decida antes. O cascade apaga cada linha que aponta para o usuário e cada linha que aponta para essas, em toda exclusão dali em diante, e nada avisa o que foi removido.",{"q":590,"a":591},"Posso excluir um usuário e manter as linhas dele?","Sim, de dois jeitos. Mude a foreign key para on delete set null, e as linhas ficam com a coluna de dono vazia, o que exige que essa coluna aceite valores vazios. Ou chame auth.admin.deleteUser() de um servidor com a opção shouldSoftDelete: o Supabase Auth mantém a linha, marca como excluída, embaralha o email e o telefone e apaga a senha, então nada do que aponta para ela é tocado.",{"q":593,"a":594},"Por que o Supabase diz que não posso excluir um usuário que enviou arquivos?","O guia de gestão de usuários ainda diz isso, e era verdade enquanto storage.objects tinha uma foreign key chamada objects_owner_fkey apontando para auth.users. O Supabase Storage já removeu essa chave nas próprias migrações de schema. Num projeto atual a exclusão passa e os arquivos ficam no bucket, com um owner_id que nenhum usuário tem mais.",{"q":596,"a":597},"Excluir um usuário desconecta ele?","Não na hora. Segundo o guia do Supabase, um token de acesso já emitido continua válido até expirar, mesmo depois de a conta ser excluída. Excluir o usuário remove as sessões dele, então o app não consegue um token novo, mas o que já está em mãos funciona até a hora de expirar.","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",[600,601,602,603,604,605,606],"database error deleting user supabase","database error deleting user","failed to delete user database error deleting user","supabase excluir usuário foreign key","supabase on delete cascade auth users","supabase não consigo excluir usuário storage","update or delete on table users violates foreign key constraint",{},true,"\"Database error deleting user\" no Supabase","\u002Fblog\u002Fdatabase-error-deleting-user","2026-10-30",{"title":5,"description":580},"blog\u002Fdatabase-error-deleting-user",[615,616,617],"\"Database error deleting user\" no Supabase quer dizer que a exclusão chegou ao seu banco e foi recusada, então nada foi removido. A linha que diz a causa está nos seus logs do Postgres, e a própria nota de troubleshooting do Supabase manda você para lá.","Quando essa linha diz que uma foreign key foi violada, uma linha de alguma das suas tabelas ainda guarda o id do usuário. O Postgres não remove uma pessoa enquanto algo ainda aponta para ela, a não ser que você tenha dito o que fazer com essas linhas.","A primeira resposta que você vai achar é on delete cascade. Ela apaga cada linha que aponta para o usuário, e cada linha que aponta para essas, em toda exclusão a partir daí. Decida tabela por tabela, e faça uma cópia antes de mudar uma regra.","vkyTS749K8kTmRnT3v9rF_uRxTNifQlx5CofYM6Mwyc",[620,627,633,638,643,649,655,661,667,673,679,680,686,692,698,704,710,716,722,728,734,740,746,752,758,764,770,775,781,787,793,799,805,811,817,823,829,835,841,847,853,859,865,871,877,883,888,894,900,905,911,917,923,929,935,941,947,953,958,964,970,976,982,988,994,1000,1006,1012,1018,1024,1030,1036,1042,1048,1054,1060,1066,1072,1078,1084,1090,1096,1101,1107,1112,1118,1124,1130,1135,1140],{"path":621,"title":622,"description":623,"published":624,"category":625,"image":626,"draft":581},"\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","Noções de segurança","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":628,"title":629,"description":630,"published":631,"category":625,"image":632,"draft":581},"\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":164,"title":634,"description":635,"published":636,"category":625,"image":637,"draft":581},"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":313,"title":639,"description":640,"published":641,"category":625,"image":642,"draft":581},"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":644,"title":645,"description":646,"published":647,"category":625,"image":648,"draft":581},"\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":650,"title":651,"description":652,"published":653,"category":625,"image":654,"draft":581},"\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":656,"title":657,"description":658,"published":659,"category":625,"image":660,"draft":581},"\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":662,"title":663,"description":664,"published":665,"category":625,"image":666,"draft":581},"\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":668,"title":669,"description":670,"published":671,"category":625,"image":672,"draft":581},"\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":674,"title":675,"description":676,"published":677,"category":625,"image":678,"draft":581},"\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":610,"title":5,"description":580,"published":611,"category":577,"image":598,"draft":581},{"path":681,"title":682,"description":683,"published":684,"category":625,"image":685,"draft":581},"\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":687,"title":688,"description":689,"published":690,"category":625,"image":691,"draft":581},"\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":693,"title":694,"description":695,"published":696,"category":625,"image":697,"draft":581},"\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":699,"title":700,"description":701,"published":702,"category":625,"image":703,"draft":581},"\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":705,"title":706,"description":707,"published":708,"category":625,"image":709,"draft":581},"\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":711,"title":712,"description":713,"published":714,"category":625,"image":715,"draft":581},"\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":717,"title":718,"description":719,"published":720,"category":625,"image":721,"draft":581},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\" e a tabela está lá","Supabase \"relation does not exist\" ou PGRST205: nenhuma tabela tem esse nome nesse schema. Quatro verificações, e o que expor um schema abre.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":723,"title":724,"description":725,"published":726,"category":625,"image":727,"draft":581},"\u002Fblog\u002Fsupabase-function-not-found","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":729,"title":730,"description":731,"published":732,"category":625,"image":733,"draft":581},"\u002Fblog\u002Fsupabase-schema-cache-column-error","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":735,"title":736,"description":737,"published":738,"category":625,"image":739,"draft":581},"\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":741,"title":742,"description":743,"published":744,"category":625,"image":745,"draft":581},"\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":747,"title":748,"description":749,"published":750,"category":625,"image":751,"draft":581},"\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":753,"title":754,"description":755,"published":756,"category":625,"image":757,"draft":581},"\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":759,"title":760,"description":761,"published":762,"category":625,"image":763,"draft":581},"\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":765,"title":766,"description":767,"published":768,"category":625,"image":769,"draft":581},"\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":56,"title":771,"description":772,"published":773,"category":625,"image":774,"draft":581},"\"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":776,"title":777,"description":778,"published":779,"category":625,"image":780,"draft":581},"\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":782,"title":783,"description":784,"published":785,"category":625,"image":786,"draft":581},"\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":788,"title":789,"description":790,"published":791,"category":625,"image":792,"draft":581},"\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":794,"title":795,"description":796,"published":797,"category":625,"image":798,"draft":581},"\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":800,"title":801,"description":802,"published":803,"category":625,"image":804,"draft":581},"\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":806,"title":807,"description":808,"published":809,"category":625,"image":810,"draft":581},"\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":812,"title":813,"description":814,"published":815,"category":625,"image":816,"draft":581},"\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":818,"title":819,"description":820,"published":821,"category":625,"image":822,"draft":581},"\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":824,"title":825,"description":826,"published":827,"category":625,"image":828,"draft":581},"\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":830,"title":831,"description":832,"published":833,"category":625,"image":834,"draft":581},"\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":836,"title":837,"description":838,"published":839,"category":625,"image":840,"draft":581},"\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":842,"title":843,"description":844,"published":845,"category":625,"image":846,"draft":581},"\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":848,"title":849,"description":850,"published":851,"category":625,"image":852,"draft":581},"\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":854,"title":855,"description":856,"published":857,"category":625,"image":858,"draft":581},"\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":860,"title":861,"description":862,"published":863,"category":625,"image":864,"draft":581},"\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":866,"title":867,"description":868,"published":869,"category":577,"image":870,"draft":581},"\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":872,"title":873,"description":874,"published":875,"category":577,"image":876,"draft":581},"\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":878,"title":879,"description":880,"published":881,"category":577,"image":882,"draft":581},"\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":884,"title":885,"description":886,"published":881,"category":625,"image":887,"draft":581},"\u002Fblog\u002Fsupabase-permission-denied-for-table","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":889,"title":890,"description":891,"published":892,"category":625,"image":893,"draft":581},"\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":895,"title":896,"description":897,"published":898,"category":625,"image":899,"draft":581},"\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":471,"title":901,"description":902,"published":903,"category":577,"image":904,"draft":581},"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":906,"title":907,"description":908,"published":909,"category":625,"image":910,"draft":581},"\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":912,"title":913,"description":914,"published":915,"category":625,"image":916,"draft":581},"\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":918,"title":919,"description":920,"published":921,"category":625,"image":922,"draft":581},"\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":924,"title":925,"description":926,"published":927,"category":625,"image":928,"draft":581},"\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":930,"title":931,"description":932,"published":933,"category":625,"image":934,"draft":581},"\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":936,"title":937,"description":938,"published":939,"category":625,"image":940,"draft":581},"\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":942,"title":943,"description":944,"published":945,"category":625,"image":946,"draft":581},"\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":948,"title":949,"description":950,"published":951,"category":625,"image":952,"draft":581},"\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":449,"title":954,"description":955,"published":956,"category":577,"image":957,"draft":581},"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":959,"title":960,"description":961,"published":962,"category":577,"image":963,"draft":581},"\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":965,"title":966,"description":967,"published":968,"category":577,"image":969,"draft":581},"\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":971,"title":972,"description":973,"published":974,"category":625,"image":975,"draft":581},"\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":977,"title":978,"description":979,"published":980,"category":625,"image":981,"draft":581},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","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":983,"title":984,"description":985,"published":986,"category":625,"image":987,"draft":581},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","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":989,"title":990,"description":991,"published":992,"category":625,"image":993,"draft":581},"\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":995,"title":996,"description":997,"published":998,"category":625,"image":999,"draft":581},"\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":1001,"title":1002,"description":1003,"published":1004,"category":625,"image":1005,"draft":581},"\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":1007,"title":1008,"description":1009,"published":1010,"category":625,"image":1011,"draft":581},"\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":1013,"title":1014,"description":1015,"published":1016,"category":625,"image":1017,"draft":581},"\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":1019,"title":1020,"description":1021,"published":1022,"category":625,"image":1023,"draft":581},"\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":1025,"title":1026,"description":1027,"published":1028,"category":625,"image":1029,"draft":581},"\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":1031,"title":1032,"description":1033,"published":1034,"category":577,"image":1035,"draft":581},"\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":1037,"title":1038,"description":1039,"published":1040,"category":625,"image":1041,"draft":581},"\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":1043,"title":1044,"description":1045,"published":1046,"category":577,"image":1047,"draft":581},"\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":1049,"title":1050,"description":1051,"published":1052,"category":625,"image":1053,"draft":581},"\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":1055,"title":1056,"description":1057,"published":1058,"category":625,"image":1059,"draft":581},"\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":1061,"title":1062,"description":1063,"published":1064,"category":625,"image":1065,"draft":581},"\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":1067,"title":1068,"description":1069,"published":1070,"category":625,"image":1071,"draft":581},"\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":1073,"title":1074,"description":1075,"published":1076,"category":577,"image":1077,"draft":581},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","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":1079,"title":1080,"description":1081,"published":1082,"category":577,"image":1083,"draft":581},"\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":1085,"title":1086,"description":1087,"published":1088,"category":625,"image":1089,"draft":581},"\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":1091,"title":1092,"description":1093,"published":1094,"category":625,"image":1095,"draft":581},"\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":560,"title":1097,"description":1098,"published":1099,"category":577,"image":1100,"draft":581},"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":1102,"title":1103,"description":1104,"published":1105,"category":625,"image":1106,"draft":581},"\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":1108,"title":1109,"description":1110,"published":1105,"category":625,"image":1111,"draft":581},"\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":1113,"title":1114,"description":1115,"published":1116,"category":625,"image":1117,"draft":581},"\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":1119,"title":1120,"description":1121,"published":1122,"category":577,"image":1123,"draft":581},"\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":1125,"title":1126,"description":1127,"published":1128,"category":625,"image":1129,"draft":581},"\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":1131,"title":1132,"description":1133,"published":1128,"category":577,"image":1134,"draft":581},"\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":466,"title":1136,"description":1137,"published":1138,"category":577,"image":1139,"draft":581},"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":1141,"title":1142,"description":1143,"published":1138,"category":625,"image":1144,"draft":581},"\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",1794213649029]