[{"data":1,"prerenderedAt":1367},["ShallowReactive",2],{"blog-uk-canceling-statement-due-to-statement-timeout":3,"blog-index-uk":838},{"id":4,"title":5,"body":6,"category":796,"cover":797,"coverAlt":798,"description":799,"draft":800,"extension":801,"faq":802,"image":817,"keywords":818,"meta":826,"navigation":827,"ogTitle":828,"path":829,"published":830,"seo":831,"stem":832,"tldr":833,"updated":830,"__hash__":837},"blog_uk\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout.md","Supabase \"canceling statement due to statement timeout\": пояснення",{"type":7,"value":8,"toc":782},"minimark",[9,13,24,27,30,35,38,57,60,64,67,70,148,158,161,167,171,178,194,202,222,225,234,238,245,260,266,277,284,287,291,294,297,403,406,413,423,427,430,438,444,464,469,475,493,510,524,530,536,539,545,557,562,566,569,575,582,588,599,603,606,634,656,664,668,674,683,703,712,729,733,775],[10,11,12],"p",{},"Сторінка вашого застосунку завантажує список, індикатор крутиться кілька\nсекунд, а потім нічого. У консолі браузера, або в червоному повідомленні, яке\nдодав ваш білдер, є один рядок:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","canceling statement due to statement timeout\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"Ви відкриваєте ту саму таблицю в Supabase, і всі рядки на місці. Питаєте\nбілдер, у якому зробили застосунок (Lovable, Bolt, v0, Cursor, Claude Code чи\nReplit), який запит надсилає ця сторінка, вставляєте його в SQL Editor, і він\nповертається за мить.",[10,28,29],{},"Перша порада, яку ви знайдете для \"canceling statement due to statement\ntimeout\" у Supabase, звучить так: підніміть ліміт. Цей ліміт робить свою\nроботу, і його ділить кожен відвідувач вашого застосунку. Перш ніж щось\nпіднімати, подивіться на політику Row Level Security цієї таблиці, тобто на\nправило, яке Postgres перевіряє, перш ніж віддати кожен рядок. У вимірюваннях\nсамого Supabase саме там запит, який мав би тривати 7 мілісекунд, витрачає 11\nсекунд.",[31,32,34],"h2",{"id":33},"що-означає-canceling-statement-due-to-statement-timeout-у-supabase","Що означає \"canceling statement due to statement timeout\" у Supabase?",[10,36,37],{},"Postgres, база даних усередині вашого проєкту Supabase, зупинив запит, бо той\nтривав довше, ніж дозволено ролі, яка його надіслала, і скасував те, що запит\nустиг зробити.",[10,39,40,41,44,45,48,49,52,53,56],{},"Речення походить від самого Postgres, з кодом помилки ",[21,42,43],{},"57014",", який Postgres\nназиває ",[21,46,47],{},"query_canceled",". Supabase передає його вашому застосунку без змін,\nтож помилка, яку отримує ваш код, містить ",[21,50,51],{},"code: '57014'"," і це речення як\nповідомлення. Postgres використовує той самий код для ",[21,54,55],{},"canceling statement due to user request",", тобто скасування, про яке хтось попросив, тому речення\nкаже вам більше, ніж число.",[10,58,59],{},"Уявіть свою базу як бібліотеку зі стійкою видачі та кухонним таймером. Щоразу,\nколи хтось просить книжки, бібліотекарка заводить таймер, перш ніж іти до\nполиць, і скільки він триває, залежить від того, хто питає. Коли він дзвенить,\nкожна книжка повертається на полицю, а відвідувач отримує папірець із цим\nреченням. Якщо запит мав щось змінити, зміну теж повертають назад.",[31,61,63],{"id":62},"чому-запит-працює-в-sql-editor-і-падає-в-моєму-застосунку","Чому запит працює в SQL Editor і падає в моєму застосунку?",[10,65,66],{},"Бо SQL Editor питає як інший відвідувач, у якого немає власного таймера і\nнемає правил для перевірки.",[10,68,69],{},"Кожен запит доходить до Postgres під певною роллю, тобто іменем, яке вирішує,\nщо цьому запиту можна. Посібник Supabase про тайм-аути наводить ліміт, з яким\nстартує кожна роль:",[71,72,73,89],"table",{},[74,75,76],"thead",{},[77,78,79,83,86],"tr",{},[80,81,82],"th",{},"Хто питає",[80,84,85],{},"Роль",[80,87,88],{},"Дозволений час",[90,91,92,106,119,135],"tbody",{},[77,93,94,98,103],{},[95,96,97],"td",{},"Відвідувач вашого застосунку без входу",[95,99,100],{},[21,101,102],{},"anon",[95,104,105],{},"3 секунди",[77,107,108,111,116],{},[95,109,110],{},"Користувач вашого застосунку, який увійшов",[95,112,113],{},[21,114,115],{},"authenticated",[95,117,118],{},"8 секунд",[77,120,121,124,129],{},[95,122,123],{},"Ваш сервер із секретним ключем",[95,125,126],{},[21,127,128],{},"service_role",[95,130,131,132],{},"власного немає, тож діють 8 секунд ролі ",[21,133,134],{},"authenticator",[77,136,137,140,145],{},[95,138,139],{},"Ви, у дашборді та в SQL Editor",[95,141,142],{},[21,143,144],{},"postgres",[95,146,147],{},"власного немає, обмежено типовим значенням у 2 хвилини",[10,149,150,151,153,154,157],{},"Роль редактора має й другу перевагу. Посібник Supabase про Row Level Security\nкаже, що в Supabase ",[21,152,144],{}," має ",[21,155,156],{},"bypassrls",", атрибут Postgres, який оминає\nкожну політику. Тож редактор відповідає, не прочитавши жодного правила. Запит\nвашого застосунку читає кожну політику таблиці на кожному рядку, який\nпереглядає, з таймером, що дзвенить через три секунди для відвідувача без\nвходу. Редактор заміряв інший запит, ніж той, що надсилає ваш застосунок.",[10,159,160],{},"У бібліотеці ви належите до персоналу. Ви заходите до сховища без таймера, і\nніхто не питає вашого читацького квитка. Відвідувач має три секунди, а\nбібліотекарка дорогою перевіряє правила на кожній книжці.",[162,163],"diagram",{"alt":164,"caption":165,"src":166},"Той самий запит, намальований як три смуги на одній шкалі часу. Для postgres смуга йде до кінця без позначок і закінчується галочкою. Для authenticated і anon смуга має позначку на кожному кроці; смуга authenticated закінчується галочкою до своєї лінії на 8 секундах, а смугу anon обрізано червоним на її лінії на 3 секундах.","Один запит, три ролі. Роль редактора оминає політику і не має лінії, яку можна перетнути; відвідувач без входу проходить кожну перевірку і зупиняється на трьох секундах.","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fthree-clocks-1600x720.png",[31,168,170],{"id":169},"знайдіть-скасований-запит","Знайдіть скасований запит",[10,172,173,174,177],{},"Пошукайте в логах Postgres свого проєкту слова ",[21,175,176],{},"statement timeout"," і запишіть,\nяка роль надіслала запит.",[10,179,180,181,185,186,189,190,193],{},"Посібник Supabase про тайм-аути має для цього запит. У дашборді відкрийте\n",[182,183,184],"strong",{},"Explorer",", оберіть ",[182,187,188],{},"Run SQL",", поставте джерелом ",[182,191,192],{},"Logs",", оберіть проміжок\nчасу, що охоплює збій, і запустіть цю скорочену версію:",[14,195,200],{"className":196,"code":198,"language":199,"meta":23},[197],"language-sql","select timestamp,\n       log_attributes['parsed.user_name'] as user_name,\n       log_attributes['parsed.query'] as query\nfrom logs\nwhere source = 'postgres_logs'\n  and match(event_message, 'statement timeout')\norder by timestamp desc\nlimit 100;\n","sql",[21,201,198],{"__ignoreMap":23},[10,203,204,207,208,210,211,214,215,217,218,221],{},[21,205,206],{},"user_name",", що дорівнює ",[21,209,134],{},", означає, що запит прийшов через Data\nAPI, сервер, через який проходить кожен виклик ",[21,212,213],{},"supabase.from(…)"," вашого\nзастосунку. Таблиця ролей у посібнику вказує ",[21,216,134],{}," як PostgREST, а\nце і є той сервер. Колонка ",[21,219,220],{},"query"," показує SQL, на який перетворився запит\nвашого застосунку, і назва таблиці в ньому вказує, яку таблицю дивитися.",[10,223,224],{},"Сторінка Query Performance у дашборді є іншим місцем, куди зазвичай дивляться,\nі посібник попереджає, що вона показує лише повільні запити, які завершилися.\nСкасований запит є в логах.",[10,226,227,228,233],{},"Якщо логи показують скасування на всіх таблицях одночасно, повільна частина не\nв одній політиці, і\n",[229,230,232],"a",{"href":231},"\u002Fblog\u002Fis-supabase-down-or-your-app","відрізнити збій Supabase від проблеми у вашому застосунку","\nдопоможе почати.",[31,235,237],{"id":236},"заміряйте-його-так-як-виконує-ваш-застосунок","Заміряйте його так, як виконує ваш застосунок",[10,239,240,241,244],{},"Запустіть запит від ролі свого застосунку з ",[21,242,243],{},"explain analyze"," попереду, і\nPostgres виведе, скільки часу він зайняв і скільки рядків відкинула політика.",[10,246,247,248,251,252,255,256,259],{},"Це метод із посібника Supabase про продуктивність Row Level Security, загорнутий\nу ",[21,249,250],{},"begin"," і ",[21,253,254],{},"rollback",", щоб зміна ролі закінчилася разом із блоком. Скопіюйте\nid справжнього користувача з ",[182,257,258],{},"Authentication → Users"," замість нулів:",[14,261,264],{"className":262,"code":263,"language":199,"meta":23},[197],"begin;\nset local role authenticated;\nset local request.jwt.claims to '{\"role\":\"authenticated\", \"sub\":\"00000000-0000-0000-0000-000000000000\"}';\nexplain analyze select * from public.orders;\nrollback;\n",[21,265,263],{"__ignoreMap":23},[10,267,268,269,272,273,276],{},"Важать два рядки виводу. ",[21,270,271],{},"Execution Time"," є числом, яке ви порівнюєте з 3 і 8\nсекундами. ",[21,274,275],{},"Rows Removed by Filter"," рахує рядки, які Postgres прочитав, а\nполітика відкинула, і посібник Supabase називає його сигналом, за яким варто\nстежити: політика, що на кожному читанні відсіює більшу частину таблиці, є\nполітикою, чия колонка фільтра потребує індексу.",[10,278,279,280,283],{},"Щоб заміряти, що отримує відвідувач без входу, напишіть ",[21,281,282],{},"set local role anon;","\nі приберіть рядок із claims.",[10,285,286],{},"Той самий посібник пропонує запустити запит раз з увімкненим Row Level\nSecurity і раз із вимкненим, щоб побачити, чи вартість у політиці. Він також\nкаже робити це лише поза продакшеном, бо вимкнення відкриває кожен рядок. На\nробочому застосунку порівнюйте натомість політику з її переписаною версією.",[31,288,290],{"id":289},"як-політика-може-коштувати-секунд","Як політика може коштувати секунд?",[10,292,293],{},"Postgres перевіряє політику на кожному рядку, який читає запит, і виклик\nфункції в політиці виконується знову для кожного з цих рядків.",[10,295,296],{},"Supabase опублікував вимірювання цього на таблиці зі 100 000 рядків. Ось\nчотири з них, повільний і швидкий спосіб:",[71,298,299,317],{},[74,300,301],{},[77,302,303,306,309,312,315],{},[80,304,305],{},"Що перевіряє політика",[80,307,308],{},"Записано як",[80,310,311],{},"Тривало",[80,313,314],{},"Переписано як",[80,316,311],{},[90,318,319,340,361,382],{},[77,320,321,324,329,332,337],{},[95,322,323],{},"Рядки, що належать користувачеві, який увійшов",[95,325,326],{},[21,327,328],{},"auth.uid() = user_id",[95,330,331],{},"179 мс",[95,333,334],{},[21,335,336],{},"(select auth.uid()) = user_id",[95,338,339],{},"9 мс",[77,341,342,345,349,352,358],{},[95,343,344],{},"Те саме правило, без індексу на колонці",[95,346,347],{},[21,348,328],{},[95,350,351],{},"171 мс",[95,353,354,355],{},"те саме, з індексом на ",[21,356,357],{},"user_id",[95,359,360],{},"менше 0,1 мс",[77,362,363,366,371,374,379],{},[95,364,365],{},"Перевірка адміна, яка читає іншу таблицю",[95,367,368],{},[21,369,370],{},"is_admin()",[95,372,373],{},"11 000 мс",[95,375,376],{},[21,377,378],{},"(select is_admin())",[95,380,381],{},"7 мс",[77,383,384,387,392,395,400],{},[95,385,386],{},"Роль, яку шукають в іншій таблиці",[95,388,389],{},[21,390,391],{},"has_role() = role",[95,393,394],{},"178 000 мс",[95,396,397],{},[21,398,399],{},"(select has_role()) = role",[95,401,402],{},"12 мс",[10,404,405],{},"Перші два повільні, і все ж на цій таблиці вкладаються в три секунди. Останні\nдва виходять за будь-який ліміт, що є в запиту застосунку. Допоміжна функція,\nяка читає другу таблицю, з тих, що пишуть, аби перевірити, чи хтось адмін,\nвикликається раз на кожен рядок першої, тож на цій таблиці вона прочитала\nдругу 100 000 разів.",[10,407,408,409,412],{},"У бібліотеці така функція схожа на бібліотекарку, яка ходить до офісу біля\nвходу спитати, чи ви з персоналу, раз на кожну книжку на полиці. Обгорнути її в\n",[21,410,411],{},"(select …)"," означає спитати один раз і записати відповідь на папірці.",[10,414,415,416],{},"Performance Advisor у Supabase ловить частину цього. Його правило з назвою\nAuth RLS Initialization Plan позначає політику, яка \"re-evaluates\ncurrent_setting() or auth.",[417,418,419,420,422],"function",{},"() for each row\". Ваша власна допоміжна\nфункція, як-от ",[21,421,370],{},", під цей опис не підпадає, тож сторінка advisor\nбез попереджень не перевіряла ваших функцій. Перегляньте політики таблиці самі\nй пошукайте будь-який виклик функції, який не обгорнуто.",[31,424,426],{"id":425},"виправляйте-в-такому-порядку","Виправляйте в такому порядку",[10,428,429],{},"Обгорніть виклики функцій, додайте індекс на колонку, яку порівнює політика,\nпотім назвіть роль. Кожен крок є коротким шматком SQL, який можна запустити в\nредакторі або передати своєму білдеру.",[10,431,432],{},[182,433,434,435,437],{},"1. Обгорніть кожен виклик функції в ",[21,436,411],{},".",[14,439,442],{"className":440,"code":441,"language":199,"meta":23},[197],"alter policy \"read own orders\" on public.orders\n  using ( (select auth.uid()) = user_id );\n",[21,443,441],{"__ignoreMap":23},[10,445,446,449,450,453,454,458,459,463],{},[21,447,448],{},"alter policy"," зберігає назву і роль політики та замінює умову. Візьміть назву\nсвоєї політики і колонку своєї таблиці, і зробіть те саме з допоміжною\nфункцією: ",[21,451,452],{},"(select private.is_admin())",". Supabase ставить одну умову: це працює\nлише для значення, яке не змінюється від рядка до рядка. Чому дужки мають\nзначення, пояснює\n",[229,455,457],{"href":456},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","посібник з увімкнення Row Level Security",",\nа допоміжна функція, написана, щоб\n",[229,460,462],{"href":461},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","позбутися помилки нескінченної рекурсії",",\nсаме з тих, яким вони потрібні.",[10,465,466],{},[182,467,468],{},"2. Додайте індекс на колонку, яку порівнює політика.",[14,470,473],{"className":471,"code":472,"language":199,"meta":23},[197],"create index orders_user_id_idx on public.orders (user_id);\n",[21,474,472],{"__ignoreMap":23},[10,476,477,478,481,482,484,485,488,489,492],{},"Посібник Supabase додає застереження. Колонка вважається проіндексованою лише\nтоді, коли стоїть в індексі першою, тож таблиця з первинним ключем\n",[21,479,480],{},"(team_id, user_id)"," не має індексу на ",[21,483,357],{},". На великій таблиці, у яку\nпишуть, поки ви працюєте, документація Postgres каже, що звичайний\n",[21,486,487],{},"create index"," блокує запис у таблицю, доки індекс не збудовано.\n",[21,490,491],{},"create index concurrently"," будує його без цього блокування, і його треба\nзапускати окремою командою, поза транзакцією.",[10,494,495,498,499,502,503,506,507,509],{},[182,496,497],{},"3. Назвіть роль, для якої політика."," Політика, записана з ",[21,500,501],{},"to authenticated",",\nніколи не виконується для відвідувача без входу. У вимірюваннях Supabase запит\nбез входу до політики без ",[21,504,505],{},"to"," тривав 170 мс, а з ",[21,508,501],{}," менше 0,1\nмс.",[10,511,512,515,516,519,520,523],{},[182,513,514],{},"4. Фільтруйте і в самому запиті."," Політика працює як невидимий ",[21,517,518],{},"where"," у\nкожному запиті, і посібник Supabase радить повторити його в запиті вашого\nзастосунку, ",[21,521,522],{},".eq('user_id', userId)",", бо так Postgres може спланувати швидший\nзапит. У їхніх вимірюваннях це скоротило запит із 171 мс до 9.",[10,525,526,529],{},[182,527,528],{},"5. Приберіть join із командної політики."," Політика, що звіряє кожен рядок\nіз таблицею учасників, робить цей пошук для кожного рядка:",[14,531,534],{"className":532,"code":533,"language":199,"meta":23},[197],"using ( (select auth.uid()) in (\n  select user_id from team_user where team_user.team_id = projects.team_id\n) )\n",[21,535,533],{"__ignoreMap":23},[10,537,538],{},"Посібник Supabase переписує її так, щоб вона прочитала команди один раз і\nпорівнювала з цим списком:",[14,540,543],{"className":541,"code":542,"language":199,"meta":23},[197],"using ( team_id in (\n  select team_id from team_user where user_id = (select auth.uid())\n) )\n",[21,544,542],{"__ignoreMap":23},[10,546,547,548,550,551,553,554,556],{},"Потім знову запустіть ",[21,549,243],{}," з початку і порівняйте\n",[21,552,271],{}," та ",[21,555,275],{}," із тим, що було раніше.",[162,558],{"alt":559,"caption":560,"src":561},"Дві полиці з тими самими дванадцятьма рядками. Ліворуч лінія пошуку проходить повз кожен рядок, біля кожного стоїть галочка, і три з них підсвічено. Праворуч картка індексу з трьома закладками вказує просто на ті самі три підсвічені рядки, а решта не має жодної позначки.","Без індексу політика читає кожен рядок, щоб знайти ті кілька, що належать вам. З індексом Postgres іде просто до них.","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fevery-row-or-the-few-1600x700.png",[31,563,565],{"id":564},"чи-варто-збільшувати-statement-timeout","Чи варто збільшувати statement timeout?",[10,567,568],{},"Лише для запиту, який ви заміряли, переписали і який досі потрібен, і тоді для\nцієї однієї функції, а не для цілої ролі.",[10,570,571,572,574],{},"Ліміти задумані навмисно. Посібник Supabase з імпорту даних каже, що вони\nіснують, щоб чесно розподіляти ресурси й не давати довгим запитам впливати на\nвсю систему. Ліміт ",[21,573,102],{}," спільний для всіх відвідувачів без входу, і будь-хто\nможе надіслати цей запит із публічним ключем, що йде всередині вашого\nзастосунку. Підняти його з трьох секунд до тридцяти означає дати кожному з цих\nзапитів тридцять секунд вашої бази.",[10,576,577,578,581],{},"Коли задача справді триває довше, дайте ліміт функції, яка її виконує.\nПосібник Supabase описує це для регулярних функцій, яким потрібен виняток щодо\nчасу виконання, і це працює для функції, яку ваш застосунок викликає через\n",[21,579,580],{},"supabase.rpc(…)",":",[14,583,586],{"className":584,"code":585,"language":199,"meta":23},[197],"alter function public.monthly_totals() set statement_timeout to '20s';\n",[21,587,585],{"__ignoreMap":23},[10,589,590,591,594,595,598],{},"Якщо ви все ж змінюєте роль, команди з посібника такі:\n",[21,592,593],{},"alter role authenticated set statement_timeout = '15s';",", а потім\n",[21,596,597],{},"notify pgrst, 'reload config';",", щоб Data API підхопив нове значення.\nSupabase обмежує запити зі своїх клієнтських бібліотек 60 секундами, хоч би що\nви задали.",[31,600,602],{"id":601},"два-рішення-які-прибирають-повідомлення-і-відкривають-таблицю","Два рішення, які прибирають повідомлення і відкривають таблицю",[10,604,605],{},"Вимкнути Row Level Security на таблиці, і надіслати запит із секретним ключем.\nОбидва роблять запит швидким, бо обидва оминають політику, і обидва віддають\nрядки людям, яким ви їх ніколи не призначали.",[10,607,608,611,612,615,616,619,620,619,623,626,627,630,631,633],{},[182,609,610],{},"Вимкнути."," Без політики нічого не перевіряється для кожного рядка, і\nтайм-аут зникає. Supabase друкує власне застереження поруч із тестом, який це\nпропонує: вимкнення Row Level Security відкриває кожен рядок таблиці для\nбудь-якої ролі з відповідним правом. Його посібник також каже, що в наявних\nпроєктах нова таблиця в ",[21,613,614],{},"public"," одразу має ",[21,617,618],{},"select",", ",[21,621,622],{},"insert",[21,624,625],{},"update"," і\n",[21,628,629],{},"delete",", надані ",[21,632,102],{},", ролі відвідувача без входу. Коли політики немає, ці\nправа і є всім, що стоїть між таким відвідувачем і таблицею.",[10,635,636,639,640,642,643,645,646,650,651,653,654,437],{},[182,637,638],{},"Секретний ключ."," Посібник Supabase каже, що роль ",[21,641,128],{},", яка стоїть\nза ним, теж має ",[21,644,156],{},", тож жодна політика не виконується. Цьому ключу\nмісце на сервері, а ключ, надісланий із браузера, може прочитати з вашого\nсайту будь-хто;\n",[229,647,649],{"href":648},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","які ключі безпечні у фронтенді","\nрозбирає цю пару. Часу він теж майже не додає, бо посібник дає ",[21,652,128],{},"\nті самі 8 секунд, що й ",[21,655,134],{},[10,657,658,659,663],{},"Чи відповідає якась ваша таблиця на запит зовсім без входу, перевіряє одна з\nдев’яти перевірок ",[229,660,662],{"href":661},"\u002Fsecurity-scanner","безкоштовного сканування Reeve",". Воно\nчитає ваш робочий сайт так, як його бачить відвідувач, триває близько 20\nсекунд і не потребує облікового запису.",[31,665,667],{"id":666},"щоб-політика-лишалася-швидкою-а-таблиця-закритою","Щоб політика лишалася швидкою, а таблиця закритою",[10,669,670,673],{},[182,671,672],{},"Політика, яку ви виправили сьогодні, матиме наступну версію."," Ваш білдер\nпише політики щоразу, коли вони потрібні новій функції, тож наступна може\nзнову викликати функцію для кожного рядка або відкрити таблицю, щоб\nзавантажився екран.",[10,675,676],{},[182,677,678,682],{},[229,679,681],{"href":680},"\u002Fwebsite-monitoring","Reeve Monitor"," перевіряє ваш застосунок ззовні, щогодини:",[684,685,686,690,693,700],"ul",{},[687,688,689],"li",{},"усі дев’ять перевірок щогодини, зокрема чи відповідає якась таблиця на запит без входу",[687,691,692],{},"чи працює застосунок, кожні 60 секунд",[687,694,695,696,699],{},"повідомлення, коли результат ",[182,697,698],{},"змінюється",", щоб таблиця, яка почала відповідати незнайомцям, не чекала, поки ви глянете",[687,701,702],{},"місячний звіт про те, що він побачив",[10,704,705],{},[182,706,707,711],{},[229,708,710],{"href":709},"\u002Fsupabase-backups","Reeve Care"," тримає копію вашої бази Supabase з часу до\nвашої зміни:",[684,713,714,717,720,723,726],{},[687,715,716],{},"зашифрована копія за розкладом, у власному сховищі Reeve в ЄС, поза вашим обліковим записом Supabase",[687,718,719],{},"кожна копія перевірена, перш ніж її зарахують, підрахунком рядків у кожній таблиці",[687,721,722],{},"відновлення в один клік, яке зберігає те, що є зараз, перш ніж замінити",[687,724,725],{},"ваші завантажені файли теж, щойно ви приєднаєте доступ до Storage",[687,727,728],{},"усе, що робить Monitor",[31,730,732],{"id":731},"що-зробити-сьогодні","Що зробити сьогодні",[734,735,736],"key-takeaways",{},[684,737,738,744,760,766,772],{},[687,739,740,741,743],{},"Пошукайте ",[21,742,176],{}," у логах Postgres і запишіть запит та роль, яка його надіслала.",[687,745,746,747,749,750,752,753,755,756,553,758,437],{},"Заміряйте цей запит через ",[21,748,243],{}," від ",[21,751,102],{}," або ",[21,754,115],{},", ролей, які використовує ваш застосунок, і прочитайте ",[21,757,271],{},[21,759,275],{},[687,761,762,763,765],{},"Обгорніть у ",[21,764,411],{}," кожен виклик функції в політиках цієї таблиці, зокрема власні допоміжні функції, яких Performance Advisor не позначає.",[687,767,768,769,771],{},"Додайте індекс на колонку, яку порівнює кожна політика, і допишіть ",[21,770,501],{}," до кожної політики, призначеної лише для користувачів, які увійшли.",[687,773,774],{},"Піднімайте ліміт останнім, на тій одній функції, якій він потрібен, і лишайте Row Level Security увімкненим.",[10,776,777,778,781],{},"Почніть із таблиці за сторінкою, яка не завантажилася. Якщо в неї ще немає\nвласних політик,\n",[229,779,780],{"href":456},"увімкнення Row Level Security на кожній таблиці","\nдає три форми, яких потребує більшість таблиць.",{"title":23,"searchDepth":783,"depth":783,"links":784},3,[785,787,788,789,790,791,792,793,794,795],{"id":33,"depth":786,"text":34},2,{"id":62,"depth":786,"text":63},{"id":169,"depth":786,"text":170},{"id":236,"depth":786,"text":237},{"id":289,"depth":786,"text":290},{"id":425,"depth":786,"text":426},{"id":564,"depth":786,"text":565},{"id":601,"depth":786,"text":602},{"id":666,"depth":786,"text":667},{"id":731,"depth":786,"text":732},"Основи безпеки","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcover-1200x630.png","Секундомір, стрілка якого вже пройшла позначку, перед довгою полицею рядків, де галочку мають лише перші кілька.","Supabase \"canceling statement due to statement timeout\": запит перевищив ліміт своєї ролі, 3 секунди для відвідувача. Спершу перевірте політику RLS.",false,"md",[803,805,808,811,814],{"q":34,"a":804},"Postgres зупинив ваш запит, бо той тривав довше, ніж дозволено ролі, яка його надіслала, і скасував те, що запит устиг зробити. Supabase дає 3 секунди відвідувачеві без входу і 8 користувачеві, який увійшов. Помилка має код 57014, який Postgres використовує і для запиту, скасованого на прохання, тож читайте речення, а не лише число.",{"q":806,"a":807},"Чому мій запит працює в SQL Editor, а в застосунку падає з тайм-аутом?","Бо SQL Editor працює від ролі postgres, а ваш застосунок ні. Supabase не дає postgres власного ліміту, і ця роль має bypassrls, тож редактор ніколи не виконує ваших політик Row Level Security. Ваш застосунок працює як anon або authenticated, з лімітом 3 або 8 секунд, і кожна політика перевіряється на кожному рядку, який читає запит.",{"q":809,"a":810},"Чи може Row Level Security спричинити statement timeout?","Так. Postgres перевіряє політику на кожному рядку, який читає запит, і виклик функції в політиці виконується знову для кожного з них. У вимірюваннях, які Supabase опублікував для таблиці на 100 000 рядків, політика з викликом допоміжної функції is_admin() виконувалася 11 000 мілісекунд, а та сама політика з викликом, обгорнутим як (select is_admin()), 7.",{"q":812,"a":813},"Як збільшити statement timeout у Supabase?","Для однієї повільної задачі задайте його на функції, яка її виконує, через alter function … set statement_timeout. Для цілої ролі виконайте alter role з новим statement_timeout, а потім notify pgrst, 'reload config', щоб Data API підхопив значення. Supabase обмежує запити зі своїх клієнтських бібліотек 60 секундами. Спершу виправте політику, бо ліміт anon спільний для всіх відвідувачів без входу.",{"q":815,"a":816},"Чи вимкнути RLS, щоб запит працював швидше?","Ні. Запит стає швидшим, бо жодна політика не виконується, і таблиця тоді відкрита для будь-якої ролі з правом на неї. Посібник Supabase каже, що в наявних проєктах нова таблиця в public одразу має select, insert, update і delete, надані anon, ролі відвідувача без входу. Замість цього обгорніть виклики функцій і додайте індекс.","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",[819,820,821,822,823,824,825],"canceling statement due to statement timeout supabase","canceling statement due to statement timeout","supabase statement timeout","57014 supabase","supabase тайм-аут запиту anon","supabase rls повільно","supabase збільшити statement timeout",{},true,"Supabase \"canceling statement due to statement timeout\"","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","2026-10-31",{"title":5,"description":799},"blog\u002Fcanceling-statement-due-to-statement-timeout",[834,835,836],"\"canceling statement due to statement timeout\" у Supabase означає, що Postgres зупинив запит, бо той тривав довше, ніж дозволено ролі, яка його надіслала: 3 секунди для відвідувача без входу, 8 для того, хто увійшов. Нічого з того, що робив запит, не зберігається.","Той самий запит працює в SQL Editor, бо редактор працює від ролі postgres, яка не має власного ліміту й повністю оминає ваші політики Row Level Security. Ваш застосунок перевіряє кожну політику на кожному рядку, який читає.","Виправте політику, перш ніж чіпати ліміт: обгорніть виклики функцій у (select …), додайте індекс на колонку, яку порівнює політика, і назвіть роль. Вищий ліміт для відвідувачів дає кожному незнайомцеві більше часу з вашою базою.","qErjOkXlUuYLky1sjGOBKWW-xkru7vFvSY2ovayOU3c",[839,845,851,857,863,869,875,881,887,893,894,901,907,913,919,925,931,937,943,949,955,961,967,973,979,985,991,997,1003,1009,1015,1021,1027,1032,1038,1044,1050,1056,1062,1068,1073,1079,1085,1091,1097,1103,1108,1114,1120,1126,1132,1138,1144,1150,1156,1162,1168,1174,1180,1186,1192,1198,1203,1209,1215,1221,1227,1233,1239,1245,1251,1257,1263,1269,1275,1281,1287,1293,1299,1305,1311,1317,1323,1329,1334,1340,1346,1352,1357,1363],{"path":840,"title":841,"description":842,"published":843,"category":796,"image":844,"draft":800},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\": пояснення","Supabase \"max client connections reached\": у пулера немає місця ще для одного клієнта. Ліміт визначає порт у вашому рядку підключення.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":846,"title":847,"description":848,"published":849,"category":796,"image":850,"draft":800},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Помилка Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": вхід через Google вимкнено у вашому проєкті Supabase. Як увімкнути та виправити redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":852,"title":853,"description":854,"published":855,"category":796,"image":856,"draft":800},"\u002Fblog\u002Fviolates-foreign-key-constraint","Помилка Supabase \"violates foreign key constraint\" під час вставки","Supabase \"insert or update on table violates foreign key constraint\": ваш рядок посилається на рядок, якого немає. Який, чому і як це виправити.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":858,"title":859,"description":860,"published":861,"category":796,"image":862,"draft":800},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Помилка Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": обовʼязковий стовпець прийшов порожнім. Звідки взявся null і як це виправити.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":864,"title":865,"description":866,"published":867,"category":796,"image":868,"draft":800},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": куди поділася сесія","\"Auth session missing!\" означає, що supabase-js не знайшла жодної сесії й навіть не спитала Supabase. Куди поділася сесія і як це виправити.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":870,"title":871,"description":872,"published":873,"category":796,"image":874,"draft":800},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": ніхто не ввійшов","\"invalid claim: missing sub claim\": Supabase Auth отримав справжній токен без жодного користувача, ключ проєкту замість сесії.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":876,"title":877,"description":878,"published":879,"category":796,"image":880,"draft":800},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": справжня причина","\"Failed to send a request to the Edge Function\": браузер не отримав відповіді, яку можна прочитати. Його консоль каже, чому, і чи ваша функція запускалася.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":882,"title":883,"description":884,"published":885,"category":796,"image":886,"draft":800},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Чому Supabase перенаправляє посилання з листів на localhost:3000","Якщо Supabase перенаправляє на localhost:3000, Site URL так і не змінили або вашої адреси немає в Redirect URLs. Як виправити і якої маски уникати.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":888,"title":889,"description":890,"published":891,"category":796,"image":892,"draft":800},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" на новому посиланні","На посиланні, надісланому хвилину тому, \"Email link is invalid or has expired\" у Supabase зазвичай означає, що поштовий фільтр використав його першим.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":829,"title":5,"description":799,"published":830,"category":796,"image":817,"draft":800},{"path":895,"title":896,"description":897,"published":898,"category":899,"image":900,"draft":800},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" у Supabase і що зникає разом","\"Database error deleting user\" у Supabase: ваша база відмовилася видаляти. Причина в логах, а виправлення вирішує, що ще буде видалено.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":902,"title":903,"description":904,"published":905,"category":796,"image":906,"draft":800},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" у Supabase","Вебхук Stripe в Edge Function Supabase пише \"No signatures found matching the expected signature\"? Причин дві. Не вимикайте перевірку.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":908,"title":909,"description":910,"published":911,"category":796,"image":912,"draft":800},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" у Supabase: три причини","Supabase відповідає \"Invalid login credentials\" на неправильний пароль, невідому пошту й акаунт Google. Як зрозуміти, що саме.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":914,"title":915,"description":916,"published":917,"category":796,"image":918,"draft":800},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": справжня помилка","\"Edge Function returned a non-2xx status code\" означає, що ваша функція Supabase відповіла помилкою. Ось де прочитати справжню.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":920,"title":921,"description":922,"published":923,"category":796,"image":924,"draft":800},"\u002Fblog\u002Fcertificate-not-trusted","Сертифікат не довірений: три причини, крім закінчення строку","Сертифікат не довірений, хоча дата в порядку? Він називає іншу адресу, підписав сам себе або в його ланцюжку бракує ланки. Як зрозуміти, що саме.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":926,"title":927,"description":928,"published":929,"category":796,"image":930,"draft":800},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": що в лапках","Supabase \"invalid input syntax for type uuid\" означає, що застосунок надіслав щось, що не є id. Прочитайте лапки, притримайте запит, залиште колонку.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":932,"title":933,"description":934,"published":935,"category":796,"image":936,"draft":800},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\": пояснення","Supabase \"duplicate key value violates unique constraint\": значення вже зайняте. Знайдіть стовпець, оберіть виправлення й сховайте значення від очей.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":938,"title":939,"description":940,"published":941,"category":796,"image":942,"draft":800},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\", хоча таблиця на місці","Supabase \"relation does not exist\" або PGRST205: жодна таблиця не має такої назви в цій схемі. Чотири перевірки, і на що зважити, відкриваючи схему.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":944,"title":945,"description":946,"published":947,"category":796,"image":948,"draft":800},"\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\" показує назви аргументів, які надіслав ваш застосунок. Порівняйте їх із функцією.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":950,"title":951,"description":952,"published":953,"category":796,"image":954,"draft":800},"\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\" зазвичай означає, що назва не збігається. Чотири перевірки і рядок для перезавантаження.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":956,"title":957,"description":958,"published":959,"category":796,"image":960,"draft":800},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": два ліміти, один код помилки","Supabase \"Email Rate Limit Exceeded\" обмежує кожен лист вашого проєкту: 2 на годину з вбудованим відправником. Що враховується і як підняти ліміт.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":962,"title":963,"description":964,"published":965,"category":796,"image":966,"draft":800},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 причини","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" виводить ваших користувачів із системи. Три причини і як лог Auth їх розрізняє.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":968,"title":969,"description":970,"published":971,"category":796,"image":972,"draft":800},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": три причини","Supabase \"permission denied for schema public\" означає, що бракує GRANT на схему. Що його прибрало і який рядок його повертає.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":974,"title":975,"description":976,"published":977,"category":796,"image":978,"draft":800},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": три речі, які це може означати","Supabase \"Bucket not found\" означає одне з трьох: публічне посилання на приватний бакет, неточну назву або не той проєкт.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":980,"title":981,"description":982,"published":983,"category":796,"image":984,"draft":800},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: який ключ перестав працювати?","Помилка Supabase invalid JWT — це PGRST301: підписаний токен не пройшов перевірку. У новому проєкті йдеться про сесію, а не про ключ API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":986,"title":987,"description":988,"published":989,"category":796,"image":990,"draft":800},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" майже завжди означає нуль","Supabase повертає PGRST116, \"JSON object requested, multiple (or no) rows returned\", коли запит нічого не знайшов. Прихований рядок має вигляд відсутнього.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":992,"title":993,"description":994,"published":995,"category":796,"image":996,"draft":800},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" у Supabase: де шукати","\"Database error saving new user\" означає, що щось причеплене до вашої реєстрації в Supabase впало. Справжня помилка лежить у ваших логах.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":998,"title":999,"description":1000,"published":1001,"category":796,"image":1002,"draft":800},"\u002Fblog\u002Fwhat-is-supabase","Що таке Supabase? База даних, яку обрав ваш білдер","Що таке Supabase: база даних, вхід і сховище файлів за вашим застосунком. Supabase тримає сервери, а правила про те, хто читає ваші рядки, ваші.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":1004,"title":1005,"description":1006,"published":1007,"category":796,"image":1008,"draft":800},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Відкритий у фронтенді ключ AWS це не те саме, що ключ OpenAI","Ключ доступу AWS, відкритий у вашому фронтенді, читає і пише ваше сховище. Рішення зазвичай presigned URL, а не новий ключ.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1010,"title":1011,"description":1012,"published":1013,"category":796,"image":1014,"draft":800},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" при вивантаженні","\"New row violates row-level security policy for table objects\" означає, що вашому вивантаженню бракує правила insert. Публічний бакет його не додає.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":1016,"title":1017,"description":1018,"published":1019,"category":796,"image":1020,"draft":800},"\u002Fblog\u002Fbase44-security-scan","Сканування безпеки Base44: те, що бачить лише воно","Сканування безпеки Base44 перевіряє сім видів проблем зсередини. Ось половина, яку читає тільки воно, і половина, на яку воно ніколи не дивиться.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":1022,"title":1023,"description":1024,"published":1025,"category":796,"image":1026,"draft":800},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Ваш API-ключ витік. Порядок дій","API-ключ витік, і ви не знаєте, що робити першим. Не кожен ключ у вашому фронтенді є витоком, а порядок важить більше за швидкість.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":461,"title":1028,"description":1029,"published":1030,"category":796,"image":1031,"draft":800},"\"Infinite recursion detected in policy\" без вимкнення RLS","\"Infinite recursion detected in policy for relation\" означає, що ваша policy запитала таблицю, яку вона захищає. Ось як розірвати коло.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":1033,"title":1034,"description":1035,"published":1036,"category":796,"image":1037,"draft":800},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" у Supabase, і хибне виправлення","\"No API key found in request\" означає, що запит дійшов до Supabase без ключа. Більшість відповідей натомість вказують на правила вашої бази.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":1039,"title":1040,"description":1041,"published":1042,"category":796,"image":1043,"draft":800},"\u002Fblog\u002Fis-base44-safe","Чи безпечний Base44? Дані 5 442 застосунків","Чи безпечний Base44? Ми прогнали дев’ять перевірок на 5 442 робочих застосунках Base44. Майже всі отримали B з причин, яких власник ніколи не обирав.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":1045,"title":1046,"description":1047,"published":1048,"category":796,"image":1049,"draft":800},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Сховати ключ API: перенесіть його в Supabase Edge Function","Сховати ключ API означає прибрати його з браузера, а Supabase Edge Function це найменше місце, куди його покласти. Два кроки поруч важать більше.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":1051,"title":1052,"description":1053,"published":1054,"category":796,"image":1055,"draft":800},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Чи відкритий ваш файл .env? Дванадцять шляхів для перевірки","Чи відкритий ваш файл .env на вашому власному вебсервері? Дванадцять адрес скажуть це за хвилину, а влучання означає, що все в ньому вже публічне.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":1057,"title":1058,"description":1059,"published":1060,"category":796,"image":1061,"draft":800},"\u002Fblog\u002Fis-v0-safe","Безпека v0: усі 1 790 просканованих застосунків v0 отримали A","Безпека v0 на 1 790 живих застосунках v0: усі отримали A. Лише 17 згадували базу даних, і саме це здебільшого вимірює оцінка A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":1063,"title":1064,"description":1065,"published":1066,"category":796,"image":1067,"draft":800},"\u002Fblog\u002Fis-bolt-safe","Чи безпечний Bolt? Що показали 1 123 застосунки Bolt","Чи безпечний Bolt? Ми прогнали 1 123 живі застосунки Bolt через дев’ять перевірок. Хостинг був чистим. Знахідки: ключі й відкриті таблиці в самих застосунках.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":231,"title":1069,"description":1070,"published":1071,"category":796,"image":1072,"draft":800},"Supabase не працює чи проблема у вашому застосунку? Як розрізнити","Supabase не працює чи зламався ваш застосунок? Пауза, повна база й ваша власна помилка виглядають однаково. Чотири перевірки їх розрізняють.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":1074,"title":1075,"description":1076,"published":1077,"category":796,"image":1078,"draft":800},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","Чи шифрує Supabase мої дані? Так. Ось від чого це захищає","Чи шифрує Supabase дані? Так: AES-256 у стані спокою, TLS під час передавання, SOC 2 та ISO 27001. Що покриває кожне і який витік не зупиняє жодне.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":1080,"title":1081,"description":1082,"published":1083,"category":796,"image":1084,"draft":800},"\u002Fblog\u002Fsupabase-free-plan-limits","Ліміти безкоштовного тарифу Supabase і що стається на кожному","Ліміти безкоштовного тарифу Supabase: 500 МБ бази, 5 ГБ egress і жодних резервних копій. Що стається на кожній межі і що змінює Pro за $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":1086,"title":1087,"description":1088,"published":1089,"category":899,"image":1090,"draft":800},"\u002Fblog\u002Ftest-your-supabase-backup","Перевірте резервну копію Supabase до того, як вона знадобиться","Як перевірити резервну копію Supabase: відновити в тестовий проєкт, порахувати рядки, увійти й знайти рядок, якого бракує обрізаному файлу.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":1092,"title":1093,"description":1094,"published":1095,"category":899,"image":1096,"draft":800},"\u002Fblog\u002Fsupabase-backup-github-action","Безкоштовна резервна копія Supabase через GitHub Action і підступ","Резервна копія Supabase через GitHub Action безкоштовна й годиться багатьом застосункам. Робочий процес, потрібний рядок підключення та egress.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":1098,"title":1099,"description":1100,"published":1101,"category":899,"image":1102,"draft":800},"\u002Fblog\u002Fdownload-your-supabase-backup","Чому ви не можете завантажити резервну копію Supabase","Завантажити резервну копію Supabase на сучасному проєкті не вийде: щоденна копія там фізична. Як це перевірити і як тримати власну копію.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":1104,"title":1105,"description":1106,"published":1101,"category":796,"image":1107,"draft":800},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": бракує GRANT","З 30 жовтня нова таблиця в Supabase відповідає \"permission denied for table\", доки ви не дасте доступ. Лист показує лише половину виправлення.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":1109,"title":1110,"description":1111,"published":1112,"category":796,"image":1113,"draft":800},"\u002Fblog\u002Fopen-api-endpoint-exposed","Чи є відкритий API-ендпоінт проблемою безпеки? Читайте JSON","Ваше сканування позначило відкритий API-ендпоінт. Чи це важливо, залежить від того, що повернулося, і більшість знайдених належали платформі.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":1115,"title":1116,"description":1117,"published":1118,"category":796,"image":1119,"draft":800},"\u002Fblog\u002Flovable-security-scan","Сканування безпеки Lovable: чого воно не доведе","Сканування безпеки Lovable: що перевіряють Quick scan і Deep scan, коли запускається кожне, і єдине, чого не доведе жодне сканування зсередини.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":1121,"title":1122,"description":1123,"published":1124,"category":899,"image":1125,"draft":800},"\u002Fblog\u002Fsupabase-backup-auth-users","Чому у вашому дампі Supabase немає користувачів","Запустіть supabase db dump окремо і отримаєте форму вашої бази та жодного її рядка, без схеми auth, у якій живуть ваші користувачі.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":1127,"title":1128,"description":1129,"published":1130,"category":796,"image":1131,"draft":800},"\u002Fblog\u002Fdomain-and-certificate-expiry","Домен закінчився, сайт лежить: що буде далі","Ваш домен закінчився і сайт лежить. Ось який годинник уже пішов, чому прострочений сертифікат це менша з двох бід, і як перевірити обидва.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":1133,"title":1134,"description":1135,"published":1136,"category":796,"image":1137,"draft":800},"\u002Fblog\u002Fis-lovable-safe","Чи безпечний Lovable? Що показали 18 554 застосунки Lovable","Чи безпечний Lovable? Ми прогнали 18 554 живі застосунки Lovable через дев’ять перевірок. Платформа виявилася найчистішою з п’яти. Знахідки були в застосунках.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":1139,"title":1140,"description":1141,"published":1142,"category":796,"image":1143,"draft":800},"\u002Fblog\u002Fvibe-coded-app-security-checklist","Чек-лист безпеки для vibe coding, у девʼяти перевірках","Чек-лист безпеки для vibe coding із девʼяти пунктів, кожен з яких будь-хто може перевірити у вашому живому застосунку ззовні, і кожен має тест на один рядок.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":1145,"title":1146,"description":1147,"published":1148,"category":796,"image":1149,"draft":800},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Секретний ключ Stripe у фронтенді може рухати гроші","Секретний ключ Stripe, відкритий у вашому фронтенді, може повертати кошти, списувати й читати кожну картку клієнта. А ключ pk_live_ там і має бути.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":1151,"title":1152,"description":1153,"published":1154,"category":796,"image":1155,"draft":800},"\u002Fblog\u002Fvite-and-next-public-env-vars","Змінні оточення Vite відкриті: префікс означає опублікувати це","Змінні оточення Vite відкриті у вашому застосунку, бо так просив префікс. VITE_ і NEXT_PUBLIC_ означають опублікувати це, а ШІ, який їх додав, не знав ціни.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":1157,"title":1158,"description":1159,"published":1160,"category":796,"image":1161,"draft":800},"\u002Fblog\u002Fbase44-source-maps","Безпека Base44: що позначає скан і що з цього виправляти вам","Безпека Base44 на 5 438 просканованих застосунках: три знахідки майже на кожному належать платформі, source map є бейджем Base44, а ваша частина коротка.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":1163,"title":1164,"description":1165,"published":1166,"category":796,"image":1167,"draft":800},"\u002Fblog\u002Fis-cursor-ai-safe","Чи безпечний Cursor AI? Редактор, код і опублікований застосунок","Чи безпечний Cursor AI? Три запитання в одному пошуку: що Cursor зберігає, у чому помиляється його код і чи відкритий застосунок, який ви опублікували.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":1169,"title":1170,"description":1171,"published":1172,"category":796,"image":1173,"draft":800},"\u002Fblog\u002Fis-replit-safe","Чи безпечний Replit? Що ми знайшли в 3 042 живих застосунках Replit","Чи безпечний Replit? Ми прогнали 3 042 живі застосунки Replit через дев’ять зовнішніх перевірок. Знахідки були в опублікованому застосунку, а не в хостингу.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":1175,"title":1176,"description":1177,"published":1178,"category":899,"image":1179,"draft":800},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: у копії бази даних немає жодного файлу","Supabase storage backup це окрема робота. Копії бази даних зберігають список ваших файлів і жодного з них, тож після відновлення кожне завантаження зламане.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":1181,"title":1182,"description":1183,"published":1184,"category":899,"image":1185,"draft":800},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery у Supabase: ціна та межі","Point-in-time recovery у Supabase відмотує базу на будь-яку секунду за останній тиждень. Коштує $100 на місяць понад Pro і покриває лише базу даних.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":1187,"title":1188,"description":1189,"published":1190,"category":899,"image":1191,"draft":800},"\u002Fblog\u002Fsupabase-project-paused-recover","Проєкт Supabase на паузі? Ваші дані нікуди не зникли","Supabase поставив ваш проєкт на паузу після тижня без активності. Нічого не видалено, кнопка Restore стоїть поруч із назвою, і у вас є рік, щоб натиснути.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":1193,"title":1194,"description":1195,"published":1196,"category":796,"image":1197,"draft":800},"\u002Fblog\u002Fsafest-ai-app-builder","Який білдер застосунків з ШІ найбезпечніший? 30 998 тестів","Який білдер застосунків з ШІ найбезпечніший? Ми просканували 30 998 живих застосунків з Lovable, Base44, Replit, v0 і Bolt. Оцінку вирішує не білдер.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":456,"title":1199,"description":1200,"published":1201,"category":796,"image":1202,"draft":800},"Увімкніть Row Level Security на кожній таблиці Supabase і перевірте","Row Level Security у Supabase без політики закриває таблицю повністю. Політика без увімкненого перемикача не робить нічого. Ось SQL, і ось перевірка.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":1204,"title":1205,"description":1206,"published":1207,"category":796,"image":1208,"draft":800},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": чого не бачить попередження","Supabase позначає \"RLS disabled in public\" як помилку. Про політику читання, яка лишає вашу таблицю так само відкритою, він не каже нічого.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":1210,"title":1211,"description":1212,"published":1213,"category":796,"image":1214,"draft":800},"\u002Fblog\u002Frotate-supabase-service-role-key","Як замінити злитий ключ service_role у Supabase","Supabase каже спершу закрити витік. Інші посібники кажуть міняти негайно. Що правильно, залежить від того, куди саме потрапив ваш ключ service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1216,"title":1217,"description":1218,"published":1219,"category":796,"image":1220,"draft":800},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Сканери безпеки для vibe coding у порівнянні, наш теж","Найкращий сканер безпеки для vibe coding залежить від трьох питань, на які не відповідає жоден перелік функцій. Вісім інструментів і ціни.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1222,"title":1223,"description":1224,"published":1225,"category":796,"image":1226,"draft":800},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: п’ять перевірок, які зробите самі","Supabase security checker читає ваш опублікований застосунок, а не налаштування проєкту. Ось п’ять перевірок і як виконати кожну самостійно.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1228,"title":1229,"description":1230,"published":1231,"category":796,"image":1232,"draft":800},"\u002Fblog\u002Fvibe-coding-security-scanner","Сканер безпеки для vibe coding: чого не бачить скан URL","Сканер безпеки для vibe coding читає ваш робочий застосунок ззовні. Що це охоплює, чотири речі, яких він не бачить, і як читати результат.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1234,"title":1235,"description":1236,"published":1237,"category":796,"image":1238,"draft":800},"\u002Fblog\u002Fmissing-security-headers","Відсутні заголовки безпеки: коли це справді важливо","Відсутні заголовки безпеки трапляються в наших звітах найчастіше. Від чого вони захищають і коли це найменш терміновий рядок вашого звіту.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1240,"title":1241,"description":1242,"published":1243,"category":796,"image":1244,"draft":800},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Ваш ключ API OpenAI відкритий у фронтенді. Замініть його.","Ключ API OpenAI, відкритий у фронтенді, не можна прив'язати до домену. Замініть його сьогодні, перенесіть виклик на свій сервер і обмежте витрати.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1246,"title":1247,"description":1248,"published":1249,"category":796,"image":1250,"draft":800},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Ключ API у фронтенді: що насправді віддають 30 998 застосунків","Ключ API, відкритий у вашому фронтенді, зазвичай є ключем Google Maps. Ми просканували 30 998 vibe-coded застосунків і порахували, що витікає насправді.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1252,"title":1253,"description":1254,"published":1255,"category":899,"image":1256,"draft":800},"\u002Fblog\u002Fsupabase-backup-tools-compared","Інструменти резервного копіювання Supabase, і наш серед них","Чотири види інструментів резервного копіювання Supabase, що копіює кожен і коли безкоштовна GitHub Action виграє в будь-якої оплати, нашої теж.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1258,"title":1259,"description":1260,"published":1261,"category":796,"image":1262,"draft":800},"\u002Fblog\u002Freplit-secrets-explained","Як користуватися секретами в Replit і що все одно публікується","Як користуватися секретами в Replit: додати, прочитати і усунути дві причини undefined. А ще ключі, які цей інструмент не здатен зберегти в таємниці.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1264,"title":1265,"description":1266,"published":1267,"category":899,"image":1268,"draft":800},"\u002Fblog\u002Fback-up-supabase-free-tier","Резервні копії на безкоштовному тарифі Supabase без терміналу","На безкоштовному тарифі Supabase резервних копій немає: копію робите ви. Як зробити її з панелі та що втрачає шлях через CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1270,"title":1271,"description":1272,"published":1273,"category":796,"image":1274,"draft":800},"\u002Fblog\u002Fis-supabase-secure","Чи безпечний Supabase? Так. Ваш проєкт це інше питання","Чи безпечний Supabase? Платформа проходить аудити, шифрує дані й тримає пентести. Їхня документація каже, де це закінчується і починаються ваші налаштування.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1276,"title":1277,"description":1278,"published":1279,"category":796,"image":1280,"draft":800},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Де знайти API-ключі Supabase: anon, service_role і URL","URL проєкту, ключ anon і ключ service_role лежать на одній сторінці панелі. Ось де вона, і яке з чотирьох значень має бути у вашому застосунку.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1282,"title":1283,"description":1284,"published":1285,"category":796,"image":1286,"draft":800},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy в Supabase. Що далі?","\"New row violates row-level security policy\" означає, що Supabase відмовив у записі. Швидке виправлення знову відкриває таблицю для всіх.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1288,"title":1289,"description":1290,"published":1291,"category":796,"image":1292,"draft":800},"\u002Fblog\u002Fcors-wildcard-security-risk","Чи є вайлдкард CORS ризиком для безпеки? Майже ніколи.","Чи є вайлдкард CORS ризиком для безпеки? Зазвичай це типове налаштування вашого білдера, і воно не видає нічого, що ваш сервер і так віддавав кожному.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1294,"title":1295,"description":1296,"published":1297,"category":899,"image":1298,"draft":800},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Branching у Supabase це не бекап. Він іде тільки вперед.","Чому branching у Supabase це не бекап: гілка стартує без ваших даних, а мердж переносить саму лише схему. Для чого він потрібен і що брати замість нього.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1300,"title":1301,"description":1302,"published":1303,"category":899,"image":1304,"draft":800},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Як відновити резервну копію Supabase, і що ламається потім","Як відновити резервну копію Supabase з панелі або з файлу дампа, що саме замінює відновлення і чому ваш застосунок може лишитися зламаним після нього.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1306,"title":1307,"description":1308,"published":1309,"category":796,"image":1310,"draft":800},"\u002Fblog\u002Fsupabase-storage-bucket-public","Ваш бакет Supabase Storage публічний. Чи це проблема?","Публічний бакет Supabase Storage означає, що той, хто має URL файлу, може його відкрити. Він не означає, що хтось може переглянути список вмісту.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1312,"title":1313,"description":1314,"published":1315,"category":796,"image":1316,"draft":800},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Чи є проблемою ключ API Google у вашому браузері?","Ключ API Google у відкритому коді сторінки наш сканер знаходить найчастіше, і зазвичай усе гаразд. Вирішує це одне безкоштовне налаштування.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1318,"title":1319,"description":1320,"published":1321,"category":899,"image":1322,"draft":800},"\u002Fblog\u002Fai-agent-deleted-my-database","ШІ-агент видалив мої дані в Supabase. Що можна відновити?","ШІ-агент видалив дані з вашої бази. Те, що ви зможете відновити, вирішилося раніше, а наступні хвилини вирішують, скільки з цього вціліє.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1324,"title":1325,"description":1326,"published":1327,"category":796,"image":1328,"draft":800},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Чи може будь-хто прочитати вашу базу Supabase? 3 680 застосунків","Чи може будь-хто прочитати вашу базу даних Supabase без входу? Ми просканували 30 998 живих застосунків, зроблених ШІ-білдерами, і виміряли, як часто так.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1330,"title":1331,"description":1332,"published":1327,"category":796,"image":1333,"draft":800},"\u002Fblog\u002Fsource-maps-exposed-in-production","Відкриті source maps: ваш застосунок публікує свій вихідний код","Відкрита source map дає будь-кому прочитати оригінальний код вашого застосунку, разом із коментарями. Перевірка за 30 секунд, і що важить насправді.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1335,"title":1336,"description":1337,"published":1338,"category":796,"image":1339,"draft":800},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: це той самий anon key?","Supabase замінив anon і service_role публічними та секретними ключами. Який із них має бути у вашому застосунку, а який не має бути ніколи?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1341,"title":1342,"description":1343,"published":1344,"category":899,"image":1345,"draft":800},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Чи робить Supabase резервні копії моєї бази? Залежить від тарифу.","Чи робить Supabase резервні копії вашої бази даних? На платних тарифах щодня, на безкоштовному жодної. Як дізнатися, що у вас насправді є.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1347,"title":1348,"description":1349,"published":1350,"category":796,"image":1351,"draft":800},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security увімкнено. Таблиця досі публічна.","Увімкнути Supabase Row Level Security не означає захистити таблицю. Захищають політики, а та, що полагодила застосунок, часто впускає всіх.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1353,"title":1354,"description":1355,"published":1350,"category":899,"image":1356,"draft":800},"\u002Fblog\u002Fversion-history-is-not-a-backup","Історія версій не є резервною копією. Вона не поверне таблицю.","Lovable і Bolt ведуть історію версій вашого коду. Ваша база даних працює як окремий сервіс, тож відкат назад не поверне ваші дані.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1358,"title":1359,"description":1360,"published":1361,"category":899,"image":1362,"draft":800},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Три способи зробити резервну копію бази Supabase, і чого бракує","Панель, pg_dump і керований сервіс. Що насправді зберігає кожен спосіб, що тихо лишає осторонь і який із них переживе втрату акаунта.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":648,"title":1364,"description":1365,"published":1361,"category":796,"image":1366,"draft":800},"Які API-ключі безпечні у браузері, а які ні","Ваш ключ anon у Supabase створений, щоб бути публічним. Ключ service_role для цього не створений, і він ігнорує всі правила, які ви задали. Як їх розрізнити.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213654269]