[{"data":1,"prerenderedAt":1133},["ShallowReactive",2],{"blog-de-failed-to-send-a-request-to-the-edge-function":3,"blog-index-de":604},{"id":4,"title":5,"body":6,"category":560,"cover":561,"coverAlt":562,"description":563,"draft":564,"extension":565,"faq":566,"image":584,"keywords":585,"meta":592,"navigation":593,"ogTitle":594,"path":595,"published":596,"seo":597,"stem":598,"tldr":599,"updated":596,"__hash__":603},"blog_de\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function.md","\"Failed to send a request to the Edge Function\": der echte Grund",{"type":7,"value":8,"toc":549},"minimark",[9,13,24,27,35,40,43,65,68,83,95,99,102,115,122,128,137,154,160,164,167,255,274,283,289,308,327,331,334,353,362,370,377,380,392,398,403,407,410,420,428,431,446,450,456,465,480,490,507,511,534],[10,11,12],"p",{},"Deine App hat einen Knopf, der eine Supabase Edge Function aufruft, das kleine\nStück Servercode, das eine mit Lovable, Bolt, Cursor oder Claude Code gebaute App\nfür Arbeit benutzt, die nicht im Browser passieren kann, etwa einen Aufruf bei\nOpenAI mit einem Schlüssel. Du drückst ihn, und statt eines Ergebnisses zeigt\ndeine App das hier:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","Failed to send a request to the Edge Function\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"Die Funktion ist deployt. Aus einem Terminal aufgerufen, antwortet sie vielleicht\nsogar tadellos. Aus deiner App scheitert sie jedes Mal, und \"failed to send a\nrequest to the Edge Function\" liest sich, als hätte deine Anfrage die App nie\nverlassen.",[10,28,29,30,34],{},"Gut möglich, dass sie es doch hat. ",[31,32,33],"strong",{},"Deine Funktion ist vielleicht gelaufen, hat\nihre Arbeit getan und geantwortet, und der Browser hat sich geweigert, die\nAntwort an deine App weiterzugeben."," Was von beidem passiert ist, steht an genau\neiner Stelle, und das ist nicht der Fehler, den deine App bekommen hat.",[36,37,39],"h2",{"id":38},"was-bedeutet-failed-to-send-a-request-to-the-edge-function","Was bedeutet \"Failed to send a request to the Edge Function\"?",[10,41,42],{},"Es heißt, dass supabase-js um eine Antwort gebeten und keine bekommen hat, die\nes lesen durfte.",[10,44,45,46,53,54,57,58,64],{},"Der Satz steht als fester Text in\n",[47,48,52],"a",{"href":49,"rel":50},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-js\u002Fblob\u002Fmaster\u002Fpackages\u002Fcore\u002Ffunctions-js\u002Fsrc\u002Ftypes.ts",[51],"nofollow","supabase-js","\nund hängt an einem Fehler namens ",[21,55,56],{},"FunctionsFetchError",". supabase-js wirft ihn,\nwenn die Anfrage selbst scheitert, bevor es überhaupt einen Statuscode zum\nAnsehen gibt. Das trennt ihn von seinem bekannteren Geschwister:\n",[47,59,61],{"href":60},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code",[21,62,63],{},"Edge Function returned a non-2xx status code","\nheißt, dass eine Antwort zurückkam und sie ein Fehler war. Dieser hier heißt,\ndass überhaupt keine lesbare Antwort zurückkam.",[10,66,67],{},"Eine Anfrage scheitert so aus einer Handvoll Gründen. Das Gerät ist offline, die\nProjektadresse in deiner App ist falsch, oder die Regeln des Browsers für fremde\nAdressen haben die Antwort abgelehnt. Diese Regeln heißen CORS, kurz für\nCross-Origin Resource Sharing, und sie verhindern, dass eine Webseite eine\nAntwort von einer anderen Adresse liest, außer die Antwort erlaubt es. Wenn die\nFunktion im Terminal antwortet und nur in deiner App scheitert, ist CORS der\nVerdächtige, und der Browser sagt dir, ob er es war.",[10,69,70,71,74,75,78,79,82],{},"Deine App wohnt unter einer Adresse, sagen wir ",[21,72,73],{},"yourapp.lovable.app",", und deine\nFunktion unter einer anderen, ",[21,76,77],{},"\u003Cproject-ref>.supabase.co",". Stell dir den Browser\nals Portier deiner App vor. Post von einer anderen Adresse bekommt deine App nur,\nwenn sie ein Etikett des Absenders trägt, auf dem steht, dass deine App sie haben\ndarf: einen Antwort-Header namens ",[21,80,81],{},"Access-Control-Allow-Origin",". Bei einem Brief\nwie deinem klopft der Portier vorher beim Absender an und fragt, ob der ihn\nüberhaupt annimmt. Und wenn er etwas ablehnt, sagt er deiner App nur, dass es\nnicht geklappt hat. Den Grund schreibt er in sein eigenes Buch.",[10,84,85,86,89,90,94],{},"Eine dritte Meldung gehört zur selben Familie. ",[21,87,88],{},"Relay Error invoking the Edge Function"," ist supabase-js, das meldet, dass das Relay von Supabase deine Funktion\nnicht erreicht hat, also\n",[47,91,93],{"href":92},"\u002Fblog\u002Fis-supabase-down-or-your-app","prüf, ob Supabase gerade ein Problem hat",",\nbevor du irgendeinen Code änderst.",[36,96,98],{"id":97},"warum-deine-app-nicht-mehr-erfährt","Warum deine App nicht mehr erfährt",[10,100,101],{},"Weil der Browser den Grund mit Absicht vor deinem Code zurückhält.",[10,103,104,105,110,111,114],{},"Die ",[47,106,109],{"href":107,"rel":108},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FGuides\u002FCORS\u002FErrors",[51],"Seite von MDN zu CORS-Fehlern","\nsagt es klar: Aus Sicherheitsgründen bekommt JavaScript-Code keine Einzelheiten\ndarüber, was bei einer CORS-Anfrage schiefgelaufen ist. Deine App erfährt, dass\netwas gescheitert ist, und sonst nichts. In Chrome lautet der Fehler, den\nsupabase-js einpackt, ",[21,112,113],{},"TypeError: Failed to fetch",", und Chromium benutzt diesen\nText für jeden Netzwerkfehler gleich, also bringt es nichts, ihn auszugeben. Laut\nderselben Seite von MDN findest du nur in der Konsole des Browsers heraus, was\ngenau schiefging.",[10,116,117,118,121],{},"Das ist das Buch des Portiers. Öffne deine Live-App in Chrome oder Edge, drück\nF12, wähl ",[31,119,120],{},"Console"," und drück den Knopf in deiner App noch einmal. Die Zeile,\ndie du suchst, ist rot und beginnt so:",[14,123,126],{"className":124,"code":125,"language":19},[17],"Access to fetch at 'https:\u002F\u002F\u003Cproject-ref>.supabase.co\u002Ffunctions\u002Fv1\u002F\u003Cname>' from origin 'https:\u002F\u002Fyourapp.lovable.app' has been blocked by CORS policy:\n",[21,127,125],{"__ignoreMap":23},[10,129,130,131,136],{},"Alles nach dem Doppelpunkt ist der Grund. Firefox und Safari formulieren es\nanders; die Zitate in diesem Beitrag sind die von Chrome, aus dem\n",[47,132,135],{"href":133,"rel":134},"https:\u002F\u002Fgithub.com\u002Fchromium\u002Fchromium\u002Fblob\u002Fmain\u002Fthird_party\u002Fblink\u002Frenderer\u002Fplatform\u002Floader\u002Fcors\u002Fcors_error_string.cc",[51],"Quellcode von Chromium",".",[10,138,139,140,143,144,147,148,153],{},"Das Anklopfen hat einen technischen Namen, Preflight Request. Es ist eine\nAnfrage mit der Methode ",[21,141,142],{},"OPTIONS",", die der Browser vor deiner schickt, und\nsupabase-js löst immer eine aus: Es schickt deinen Schlüssel in einem Header\n",[21,145,146],{},"Authorization"," und deine Daten als JSON, und der\n",[47,149,152],{"href":150,"rel":151},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FGuides\u002FCORS",[51],"CORS-Leitfaden von MDN","\nzählt keins von beiden zu dem, was eine Seite schicken darf, ohne vorher zu\nfragen.",[155,156],"diagram",{"alt":157,"caption":158,"src":159},"Zwei Versuche desselben Aufrufs. Oben kommt die Antwort auf das OPTIONS-Anklopfen des Browsers mit einem leeren Umriss zurück, wo ihr Etikett sein sollte, der Browser lehnt sie ab, und die POST-Anfrage geht nie los. Unten trägt die Antwort auf das Anklopfen ihr Etikett und kommt durch, die POST-Anfrage erreicht die Funktion, die ihre Arbeit tut, und die Antwort kommt ohne Etikett zurück und wird an der Prüfung des Browsers angehalten.","Oben wird das Anklopfen abgelehnt, und deine Anfrage geht nie los. Unten kommt das Anklopfen durch, die Funktion tut die Arbeit, und nur ihre Antwort wird zurückgehalten.","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fthe-knock-first-1600x760.png",[36,161,163],{"id":162},"welche-hälfte-ist-gescheitert-und-lief-deine-funktion","Welche Hälfte ist gescheitert, und lief deine Funktion?",[10,165,166],{},"Die Worte \"preflight request\" in der Konsolenzeile entscheiden es. Stehen sie da,\nhat der Browser beim Anklopfen aufgehört, und deine Anfrage wurde nie\nabgeschickt. Stehen sie nicht da, ist deine Anfrage durchgekommen, deine\nFunktion lief, und ihre Antwort wurde zurückgehalten.",[168,169,170,186],"table",{},[171,172,173],"thead",{},[174,175,176,180,183],"tr",{},[177,178,179],"th",{},"Die Konsolenzeile endet mit",[177,181,182],{},"Was passiert ist",[177,184,185],{},"Hat die Funktion die Arbeit getan?",[187,188,189,203,216,228,244],"tbody",{},[174,190,191,197,200],{},[192,193,194],"td",{},[21,195,196],{},"Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.",[192,198,199],{},"Das Anklopfen wurde ohne Etikett beantwortet",[192,201,202],{},"Nein. Nur das Anklopfen kam an",[174,204,205,210,213],{},[192,206,207],{},[21,208,209],{},"Response to preflight request doesn't pass access control check: It does not have HTTP ok status.",[192,211,212],{},"Das Anklopfen wurde mit einem Fehler beantwortet",[192,214,215],{},"Nein",[174,217,218,223,226],{},[192,219,220],{},[21,221,222],{},"Request header field \u003Cname> is not allowed by Access-Control-Allow-Headers in preflight response.",[192,224,225],{},"Deine App schickt einen Header, den die Liste der Funktion nicht nennt",[192,227,215],{},[174,229,230,236,239],{},[192,231,232,235],{},[21,233,234],{},"No 'Access-Control-Allow-Origin' header is present on the requested resource.",", ohne Erwähnung von preflight",[192,237,238],{},"Das Anklopfen kam durch, deine Anfrage kam an, die Antwort hatte kein Etikett",[192,240,241],{},[31,242,243],{},"Ja",[174,245,246,249,252],{},[192,247,248],{},"Gar keine CORS-Zeile",[192,250,251],{},"Nicht CORS: die Verbindung, die Adresse oder ein Timeout aus deinem Code",[192,253,254],{},"Sieh im Tab Invocations nach",[10,256,257,263,264,269,270,273],{},[31,258,259,260,262],{},"Die erste Zeile ist das, was eine Funktion ohne Handler für ",[21,261,142],{},"\nerzeugt."," Die\n",[47,265,268],{"href":266,"rel":267},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ftroubleshooting\u002Fedge-function-500-error-response",[51],"Seite von Supabase zum 500-Fehler","\nbeschreibt es von der Seite der Funktion: Das Anklopfen erreicht deinen Code wie\njede andere Anfrage, und die Funktion schreibt ",[21,271,272],{},"SyntaxError: Unexpected end of JSON input"," ins Log, weil ein Anklopfen keinen Inhalt hat und der Code einen\nlesen wollte. Ihre Antwort ist ein Fehler ohne Header, und Chrome meldet den\nfehlenden Header, bevor es auf den Status schaut. Steht diese Zeile im Tab Logs\nder Funktion, hast du es gefunden.",[10,275,276,279,280,282],{},[31,277,278],{},"Die zweite Zeile heißt, dass das Anklopfen die Header bekam und einen Fehler\ndazu."," Ein Weg dorthin ist eine Prüfung oberhalb des Zweigs für ",[21,281,142],{},", die\ndas Anklopfen nicht bestehen kann, etwa eine Prüfung, wer da aufruft. Das\nAnklopfen trägt keinen deiner Header, auch nicht deinen Schlüssel, also fällt es\njedes Mal durch.",[10,284,285,288],{},[31,286,287],{},"Bei der vierten Zeile lohnt es sich, langsamer zu werden, denn die Arbeit ist\npassiert."," Speichert die Funktion eine Zeile, verschickt eine E-Mail oder\nbelastet eine Karte, dann ist das geschehen, und ein zweiter Druck auf den Knopf\ntut es noch einmal. Gescheitert ist die Antwort, die ohne Etikett hinausging.\nSuch zuerst nach einem Fehler: einem Absturz, dessen Antwort dein Code gar nicht\nmehr schreiben konnte, oder einem Fehlerzweig, der ohne die Header zurückgibt.\nDieselbe Seite von Supabase warnt, dass der Browser dann CORS für ein Scheitern\nverantwortlich macht, dessen echter Grund ein anderer ist.",[10,290,291,292,295,296,299,300,303,304,307],{},"Lies also das eigene Protokoll der Funktion, bevor du irgendwelche Header\nanfasst. Öffne im Supabase-Dashboard ",[31,293,294],{},"Edge Functions",", wähl die Funktion und\nlies ihre Tabs ",[31,297,298],{},"Invocations"," und ",[31,301,302],{},"Logs"," zu der Minute, in der du den Knopf\ngedrückt hast.\n",[47,305,306],{"href":60},"Den echten Fehler lesen","\ngeht beide durch, und dazu, was jede Statusnummer bedeutet.",[10,309,310,313,314,317,318,321,322,326],{},[31,311,312],{},"Die letzte Zeile heißt, dass der Portier nichts abgelehnt hat."," Die Anfrage\nist unterwegs gescheitert: Das Gerät hat die Verbindung verloren, oder die\nProjektadresse, die deine App aufruft, existiert nicht. Ein Fall kommt aus\ndeinem eigenen Code. Übergibt er ein ",[21,315,316],{},"timeout"," an ",[21,319,320],{},"supabase.functions.invoke",",\nbricht\n",[47,323,52],{"href":324,"rel":325},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-js\u002Fblob\u002Fmaster\u002Fpackages\u002Fcore\u002Ffunctions-js\u002Fsrc\u002FFunctionsClient.ts",[51],"\ndie Anfrage ab, wenn die Zeit um ist, und meldet denselben Satz, auch wenn die\nFunktion vielleicht noch arbeitet.",[36,328,330],{"id":329},"so-behebst-du-es-das-anklopfen-beantworten-und-jede-antwort-etikettieren","So behebst du es: das Anklopfen beantworten und jede Antwort etikettieren",[10,332,333],{},"Zwei Änderungen in der Funktion, und sie gehören ins selbe Deploy.",[335,336,337,347],"ol",{},[338,339,340,346],"li",{},[31,341,342,343,345],{},"Ein Zweig für ",[21,344,142],{}," als allererstes",", vor jeder Zeile, die den Inhalt\nliest oder prüft, wer da aufruft. Er beantwortet das Anklopfen mit den\nCORS-Headern und mit nichts sonst.",[338,348,349,352],{},[31,350,351],{},"Die CORS-Header an jeder Antwort, die die Funktion zurückgibt",", den\nerfolgreichen und den Fehlern. Eine Antwort ohne sie wird zurückgehalten,\negal, was darin steht.",[10,354,355,356,361],{},"Der ",[47,357,360],{"href":358,"rel":359},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ffunctions\u002Fcors",[51],"CORS-Leitfaden von Supabase","\nbaut eine Funktion ungefähr so auf:",[14,363,368],{"className":364,"code":366,"language":367,"meta":23},[365],"language-ts","import { corsHeaders } from 'npm:@supabase\u002Fsupabase-js@^2\u002Fcors'\n\nDeno.serve(async (req) => {\n  if (req.method === 'OPTIONS') {\n    return Response.json({ ok: true }, { headers: corsHeaders })\n  }\n  try {\n    const body = await req.json()\n    \u002F\u002F the function's own work goes here\n    return Response.json({ done: true }, { headers: corsHeaders })\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error)\n    return Response.json({ error: message }, { status: 400, headers: corsHeaders })\n  }\n})\n","ts",[21,369,366],{"__ignoreMap":23},[10,371,372,373,376],{},"Die Header kommen aus supabase-js selbst statt aus einer Liste, die in die\nFunktion kopiert wurde. Der Leitfaden importiert sie so ab supabase-js Version\n2.95.0, damit die Liste zu dem passt, was die Client-Bibliotheken schicken, und\nsagt, dass man nach einem Upgrade neu deployen soll. Ältere Funktionen tragen eine\nvon Hand geschriebene Kopie derselben Liste in einer Datei namens\n",[21,374,375],{},"_shared\u002Fcors.ts",". Aus dieser Kopie stammt die dritte Zeile der Tabelle: ein\nHeader, den deine App schickt und den die Liste nicht nennt.",[10,378,379],{},"Wenn du Lovable, Bolt, Cursor oder Claude Code bittest, das zu beheben, sind\ndiese zwei nummerierten Punkte der Prompt. Nenn beide. Der zweite wird leicht\nvergessen, und eine Funktion, die nur den ersten hat, rutscht beim nächsten\nAbsturz von der ersten Zeile der Tabelle in die vierte.",[10,381,382,383,386,387,391],{},"Die neueren Beispiele von Supabase packen die ganze Funktion in ",[21,384,385],{},"withSupabase",",\ndas das Anklopfen für dich beantwortet.\n",[47,388,390],{"href":389},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Ein Secret in eine Edge Function verlegen","\nzeigt diese Hülle zusammen mit einer Prüfung, wer da aufruft, und um diese\nPrüfung geht es im nächsten Abschnitt.",[10,393,394,395,397],{},"Sobald die Header an jeder Antwort hängen, zeigt eine Funktion, die abstürzt,\nnicht mehr diese Meldung, sondern ",[21,396,63],{},".\nDie Antwort erreicht jetzt deine App, mit dem Grund darin.",[155,399],{"alt":400,"caption":401,"src":402},"Eine Funktion schickt drei Antworten zurück zur Prüfung des Browsers. Eine 200-Antwort mit Etikett kommt durch und erreicht die App. Eine 500-Antwort ohne Etikett wird an der Prüfung angehalten. Eine 400-Antwort mit Etikett kommt durch, also bekommt die App den Fehler und kann ihn lesen.","Der Browser sucht das Etikett und schaut nie darauf, was in der Antwort steht. Ein Fehler mit den Headern erreicht deine App; einer ohne sie wird zurückgehalten und als gescheiterte Anfrage gemeldet.","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Ftag-every-reply-1600x720.png",[36,404,406],{"id":405},"entscheidet-der-cors-header-wer-deine-funktion-aufrufen-darf","Entscheidet der CORS-Header, wer deine Funktion aufrufen darf?",[10,408,409],{},"Nein. Er entscheidet, welche Webseiten die Antwort lesen dürfen, und nur Browser\nschauen ihn überhaupt an.",[10,411,412,413,415,416,419],{},"Die eigene Liste von Supabase setzt ",[21,414,81],{}," auf ",[21,417,418],{},"*",", was\njeden Ursprung erlaubt, sowohl in der Kopie, die supabase-js exportiert, als auch\nin der älteren von Hand geschriebenen. Bei einer Funktion, die das Token des\nAufrufers prüft, ist das in Ordnung. Bei einer Funktion, die nichts prüft, kann\ndamit jede Seite auf jeder Website deine Funktion aus den Browsern ihrer eigenen\nBesucher aufrufen und lesen, was zurückkommt.",[10,421,422,423,427],{},"Den Header auf deine eigene Domain zu beschränken, verschließt die Funktion auch\nnicht. Ein Skript, ein Terminal oder ein anderer Server schickt dieselbe Anfrage\nohne Browser, liest den Header nie und bekommt die ganze Antwort.\n",[47,424,426],{"href":425},"\u002Fblog\u002Fcors-wildcard-security-risk","Was eine CORS-Wildcard öffnet und was nicht","\ngeht das im Detail durch.",[10,429,430],{},"Das Schloss an einer Edge Function ist eine Prüfung, wer da aufruft, in die\nFunktion hineingeschrieben. Am meisten zählt sie bei den Funktionen, die hinter\ndiesem Fehler landen, denn das sind die, die einen OpenAI-Schlüssel oder den\ngeheimen Schlüssel deines Projekts halten, und der geheime Schlüssel kommt an\njeder Row-Level-Security-Regel vorbei, die du geschrieben hast.",[10,432,433,434,437,438,441,442,136],{},"Der andere Ausweg aus einem CORS-Fehler ist, die Funktion nicht mehr zu benutzen:\nden Schlüssel in eine Variable mit ",[21,435,436],{},"VITE_"," legen und OpenAI direkt aus der Seite\naufrufen. Das klappt sofort, und es legt den Schlüssel in die Datei, die jeder\nBesucher herunterlädt. Es ist die erste der\n",[47,439,440],{"href":60},"zwei Lösungen, nach denen du schlechter dastehst",".\nDiesen Fehler sieht man von außen. Unser kostenloser Scan liest das JavaScript\ndeiner Live-App so, wie ein Fremder es täte, und nennt jeden Schlüssel, den er\nfindet, samt der Frage, ob er dorthin gehört. Das dauert etwa 20 Sekunden und\nbraucht kein Konto: ",[47,443,445],{"href":444},"\u002Fsecurity-scanner","scanne deine App",[36,447,449],{"id":448},"damit-der-schlüssel-nach-der-nächsten-änderung-nicht-in-der-seite-landet","Damit der Schlüssel nach der nächsten Änderung nicht in der Seite landet",[10,451,452,455],{},[31,453,454],{},"Eine Funktion, die du heute repariert hast, kann beim nächsten Feature, um das\ndu deinen Builder bittest, neu geschrieben werden",", und der schnellste Weg an\neinem CORS-Fehler vorbei ist der, der deinen Schlüssel in die Seite legt.",[10,457,458],{},[31,459,460,464],{},[47,461,463],{"href":462},"\u002Fwebsite-monitoring","Reeve Monitor"," scannt deine Live-App jede Stunde neu:",[466,467,468,471,474,477],"ul",{},[338,469,470],{},"alle neun Checks jede Stunde, für bis zu drei Apps",[338,472,473],{},"eine E-Mail an dem Tag, an dem ein erneuter Scan deine App schlechter benotet als der vorige; ein geheimer Schlüssel in deinem JavaScript deckelt die Note allein schon bei D",[338,475,476],{},"ob die App erreichbar ist, alle 60 Sekunden",[338,478,479],{},"ein monatlicher Bericht darüber, was gesehen wurde",[10,481,482],{},[31,483,484,485,489],{},"Eine Funktion, die den geheimen Schlüssel deines Projekts hält, kann für jeden,\nder sie aufruft, jede Zeile deiner Datenbank ändern. ",[47,486,488],{"href":487},"\u002Fsupabase-backups","Reeve Care","\nhält eine Kopie deiner Supabase-Datenbank dort, wo nichts in deinem Projekt sie\nerreicht.",[466,491,492,495,498,501,504],{},[338,493,494],{},"eine verschlüsselte Kopie nach Zeitplan, auf Reeves eigenem Speicher in der EU, außerhalb deines Supabase-Kontos",[338,496,497],{},"jede Kopie wird geprüft, bevor sie zählt, durch Zählen der Zeilen in jeder Tabelle",[338,499,500],{},"eine Wiederherstellung per Klick, die sichert, was jetzt da ist, bevor sie es ersetzt",[338,502,503],{},"deine hochgeladenen Dateien ebenfalls, sobald du eine Storage-Zugangsberechtigung verbindest",[338,505,506],{},"alles, was Monitor tut",[36,508,510],{"id":509},"was-jetzt-zu-tun-ist","Was jetzt zu tun ist",[512,513,514],"key-takeaways",{},[466,515,516,519,525,528,531],{},[338,517,518],{},"Öffne die Konsole des Browsers auf deiner Live-App, drück den Knopf noch einmal und lies das Ende der roten CORS-Zeile.",[338,520,521,522,524],{},"Erwähnt die Zeile den Preflight Request, füg ganz oben in der Funktion einen Zweig für ",[21,523,142],{}," ein, der die CORS-Header zurückgibt.",[338,526,527],{},"Erwähnt sie ihn nicht, ist deine Funktion gelaufen. Lies ihre Tabs Invocations und Logs und prüf, was sie schon getan hat, bevor irgendwer den Knopf noch einmal drückt.",[338,529,530],{},"Gib die CORS-Header bei jeder Antwort zurück, auch bei Fehlern, und importiere sie aus supabase-js 2.95.0 oder neuer, damit die Liste aktuell bleibt.",[338,532,533],{},"Behalte eine Prüfung, wer da aufruft, in der Funktion. Der CORS-Header sagt Browsern nur, wer die Antwort lesen darf.",[10,535,536,537,539,540,543,544,548],{},"Wenn der Fehler in deiner App zu ",[21,538,63],{},"\nwechselt, funktionieren die Header, und die Antwort kommt durch;\n",[47,541,542],{"href":60},"dieser Beitrag"," liest sie\nvon dort aus weiter. Die ",[47,545,547],{"href":546},"\u002Fchecklist","10-Minuten-Sicherheitscheckliste"," deckt ab,\nwas in einer frisch gestarteten App sonst gern offen bleibt.",{"title":23,"searchDepth":550,"depth":550,"links":551},3,[552,554,555,556,557,558,559],{"id":38,"depth":553,"text":39},2,{"id":97,"depth":553,"text":98},{"id":162,"depth":553,"text":163},{"id":329,"depth":553,"text":330},{"id":405,"depth":553,"text":406},{"id":448,"depth":553,"text":449},{"id":509,"depth":553,"text":510},"Sicherheitsgrundlagen","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcover-1200x630.png","Eine heruntergelassene Schranke, dahinter ein festgehaltener Umschlag mit einem leeren gelben Umriss, wo sein Etikett hängen sollte.","\"Failed to send a request to the Edge Function\" heißt: Der Browser hat keine lesbare Antwort bekommen. Seine Konsole sagt, warum, und ob deine Funktion lief.",false,"md",[567,569,572,575,578,581],{"q":39,"a":568},"Es heißt, dass supabase-js deine Supabase Edge Function um eine Antwort gebeten und keine bekommen hat, die es lesen durfte. Entweder ist die Anfrage unterwegs gescheitert, etwa weil das Gerät offline war, oder der Browser hat sich geweigert, die Antwort an deine App zu geben, nach seinen Regeln für Anfragen an fremde Adressen, kurz CORS. Den Grund hält der Browser mit Absicht vor deinem Code zurück und schreibt ihn stattdessen in seine Konsole.",{"q":570,"a":571},"Warum funktioniert meine Edge Function im Terminal, aber nicht in meiner App?","Weil nur Browser CORS anwenden. Ein Terminal, ein Skript oder ein anderer Server schickt die Anfrage ab und liest die ganze Antwort. Ein Browser prüft vorher, ob die Antwort sagt, dass deine App sie lesen darf, und vor einer Anfrage wie der von supabase-js fragt er die Funktion zusätzlich mit einer eigenen OPTIONS-Anfrage um Erlaubnis. Scheitert einer der beiden Schritte, bekommt deine App diesen Fehler, während derselbe Aufruf überall sonst klappt.",{"q":573,"a":574},"Ist meine Edge Function gelaufen, wenn ich diesen Fehler bekomme?","Lies die rote Zeile in der Konsole des Browsers. Erwähnt sie den Preflight Request, hat der Browser bei der Erlaubnisfrage aufgehört, und deine Anfrage wurde nie abgeschickt. Erwähnt sie ihn nicht, ist die Anfrage durchgekommen, die Funktion hat ihre Arbeit getan, und nur die Antwort wurde zurückgehalten. Dann lies die Tabs Invocations und Logs der Funktion, bevor du den Knopf noch einmal drückst, denn ein zweiter Druck wiederholt die Arbeit.",{"q":576,"a":577},"Wie behebe ich einen CORS-Fehler bei einer Supabase Edge Function?","Lass die Funktion zuerst die OPTIONS-Anfrage beantworten, vor jedem Code, der den Inhalt liest oder den Aufrufer prüft, und gib die CORS-Header bei jeder Antwort mit, auch bei Fehlern. Der CORS-Leitfaden von Supabase importiert diese Header aus supabase-js, ab Version 2.95.0, damit die Liste zu dem passt, was der Client schickt. Deploye die Funktion nach der Änderung neu.",{"q":579,"a":580},"Was ist \"Relay Error invoking the Edge Function\"?","Das ist eine dritte Meldung von supabase-js, die kommt, wenn das Relay von Supabase deine Funktion nicht erreichen konnte. Sie ist weder eine Ablehnung durch CORS noch eine Antwort deines eigenen Codes, also prüf zuerst, ob Supabase selbst gerade ein Problem hat, bevor du irgendetwas änderst.",{"q":582,"a":583},"Ist es sicher, in den CORS-Headern meiner Edge Function jeden Ursprung zu erlauben?","Nur wenn die Funktion prüft, wer sie aufruft. Der CORS-Header sagt Browsern, welche Webseiten die Antwort lesen dürfen; er hält niemanden davon ab, die Funktion aufzurufen. Die eigenen Header von Supabase erlauben jeden Ursprung. Das ist in Ordnung für eine Funktion, die das Token des Aufrufers prüft, und lässt jede Website eine Funktion benutzen, die das nicht tut. Den Header auf deine Domain zu beschränken, verschließt die Funktion auch nicht vor Skripten.","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",[586,56,587,588,589,590,591],"failed to send a request to the edge function","supabase edge function cors fehler","supabase edge function blocked by cors policy","response to preflight request doesn't pass access control check","relay error invoking the edge function","lovable edge function cors",{},true,"\"Failed to send a request to the Edge Function\" in Supabase","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","2026-11-03",{"title":5,"description":563},"blog\u002Ffailed-to-send-a-request-to-the-edge-function",[600,601,602],"\"Failed to send a request to the Edge Function\" heißt, dass supabase-js keine Antwort bekommen hat, die es lesen durfte. Entweder ist die Anfrage unterwegs gescheitert, oder der Browser hat die Antwort zurückgehalten, und deine App erfährt mit Absicht nicht mehr.","Die Konsole des Browsers kennt den Grund. Eine Zeile, die den Preflight Request erwähnt, heißt: Deine Anfrage wurde nie abgeschickt. Eine Zeile ohne ihn heißt: Deine Funktion lief, und nur ihre Antwort wurde zurückgehalten.","Die Lösung ist ein Zweig für OPTIONS ganz oben in der Funktion und CORS-Header an jeder Antwort, auch an Fehlern. Diese Header sagen Browsern nur, wer die Antwort lesen darf; wer aufrufen darf, entscheidet eine Prüfung in deinem Code.","naTfNYFGTkRZZXY92ICqcXrMDl8Bt3adUJszlk1jWDA",[605,611,617,623,629,635,641,642,648,654,660,667,673,679,684,690,696,702,708,714,720,726,732,738,744,750,756,762,768,774,780,786,792,798,804,810,815,821,827,833,838,844,850,856,862,868,873,879,885,891,897,903,909,915,921,927,933,939,945,951,957,963,969,975,981,987,993,999,1005,1011,1017,1023,1029,1035,1041,1047,1053,1058,1064,1070,1076,1082,1088,1094,1099,1105,1111,1117,1122,1128],{"path":606,"title":607,"description":608,"published":609,"category":560,"image":610,"draft":564},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\" erklärt","Supabase \"max client connections reached\": Der Pooler hat keinen Platz für noch einen Client. Der Port in deinem Connection String setzt das Limit.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":612,"title":613,"description":614,"published":615,"category":560,"image":616,"draft":564},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Supabase-Fehler: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\" heißt: Google-Login ist in deinem Supabase-Projekt aus. Die Lösung, und was bei redirect_uri_mismatch hilft.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":618,"title":619,"description":620,"published":621,"category":560,"image":622,"draft":564},"\u002Fblog\u002Fviolates-foreign-key-constraint","Supabase-Fehler \"violates foreign key constraint\" beim Einfügen","Supabase \"insert or update on table violates foreign key constraint\": Deine Zeile zeigt auf eine, die es nicht gibt. Welche, warum, und die Lösung.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":624,"title":625,"description":626,"published":627,"category":560,"image":628,"draft":564},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Supabase-Fehler \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": Eine Pflichtspalte kam leer an. Woher die Null kommt, und die Lösung.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":630,"title":631,"description":632,"published":633,"category":560,"image":634,"draft":564},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": wo die Sitzung geblieben ist","\"Auth session missing!\" heißt: supabase-js fand keine angemeldete Sitzung und fragte Supabase gar nicht erst. Wo die Sitzung blieb, und die Lösung je Fall.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":636,"title":637,"description":638,"published":639,"category":560,"image":640,"draft":564},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": niemand ist angemeldet","\"invalid claim: missing sub claim\" heißt: Supabase Auth bekam ein echtes Token ohne Nutzer darin, deinen Projektschlüssel statt einer Sitzung.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":595,"title":5,"description":563,"published":596,"category":560,"image":584,"draft":564},{"path":643,"title":644,"description":645,"published":646,"category":560,"image":647,"draft":564},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Warum Supabase-E-Mail-Links auf localhost:3000 weiterleiten","Leitet Supabase auf localhost:3000 um, ist die Site URL unverändert, oder deine Adresse fehlt in Redirect URLs. Die Lösung und der Platzhalter, den du meidest.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":649,"title":650,"description":651,"published":652,"category":560,"image":653,"draft":564},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" bei einem neuen Link","Bei einem Link von vor einer Minute heißt Supabases \"Email link is invalid or has expired\" meist: Ein Mailfilter hat ihn zuerst benutzt. Prüfen und beheben.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":655,"title":656,"description":657,"published":658,"category":560,"image":659,"draft":564},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\" erklärt","Supabase \"canceling statement due to statement timeout\": Eine Abfrage lief länger als ihre Rolle darf, 3 Sekunden für Besucher. Prüf zuerst die RLS-Regel.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":661,"title":662,"description":663,"published":664,"category":665,"image":666,"draft":564},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" in Supabase und was mitgelöscht wird","\"Database error deleting user\" in Supabase heißt: Deine Datenbank hat das Löschen abgelehnt. Der Grund steht im Log, die Lösung entscheidet, was mitgeht.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":668,"title":669,"description":670,"published":671,"category":560,"image":672,"draft":564},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" bei Supabase","Ein Stripe-Webhook in einer Supabase Edge Function meldet \"No signatures found matching the expected signature\"? Zwei Ursachen. Prüfe weiter.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":674,"title":675,"description":676,"published":677,"category":560,"image":678,"draft":564},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" in Supabase: die drei Ursachen","Supabase sagt \"Invalid login credentials\" bei falschem Passwort, unbekannter E-Mail und Google-Konto. So erkennst du, welcher Fall es ist.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":60,"title":680,"description":681,"published":682,"category":560,"image":683,"draft":564},"\"Edge Function returned a non-2xx status code\": der echte Fehler","\"Edge Function returned a non-2xx status code\" heißt: Deine Supabase-Funktion hat mit einem Fehler geantwortet. So liest du den echten.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":685,"title":686,"description":687,"published":688,"category":560,"image":689,"draft":564},"\u002Fblog\u002Fcertificate-not-trusted","Zertifikat nicht vertrauenswürdig: drei Ursachen außer Ablauf","Zertifikat nicht vertrauenswürdig, obwohl das Datum stimmt? Es nennt eine andere Adresse, hat sich selbst signiert oder seiner Kette fehlt ein Glied.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":691,"title":692,"description":693,"published":694,"category":560,"image":695,"draft":564},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": was im Zitat steht","Supabase \"invalid input syntax for type uuid\" heißt: Deine App hat etwas geschickt, das keine ID ist. Zitat lesen, Abfrage zurückhalten, Spalte behalten.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":697,"title":698,"description":699,"published":700,"category":560,"image":701,"draft":564},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\" erklärt","Supabase \"duplicate key value violates unique constraint\" heißt: Der Wert ist schon vergeben. Spalte finden, Lösung wählen, Wert vom Bildschirm fernhalten.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":703,"title":704,"description":705,"published":706,"category":560,"image":707,"draft":564},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\", obwohl die Tabelle da ist","Supabase \"relation does not exist\" oder PGRST205: Keine Tabelle passt zu Name und Schema deiner Abfrage. Vier Prüfungen, und was eine Freigabe öffnet.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":709,"title":710,"description":711,"published":712,"category":560,"image":713,"draft":564},"\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\" nennt die Argumente, die deine App geschickt hat. Vergleich sie mit der Funktion.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":715,"title":716,"description":717,"published":718,"category":560,"image":719,"draft":564},"\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\" heißt meist: Der Name passt nicht. Vier Prüfungen und der Einzeiler zum Neuladen.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":721,"title":722,"description":723,"published":724,"category":560,"image":725,"draft":564},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": zwei Limits, ein Fehlercode","Supabase \"Email Rate Limit Exceeded\" begrenzt jede E-Mail deines Projekts: 2 pro Stunde beim eingebauten Absender. Was zählt und wie du es anhebst.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":727,"title":728,"description":729,"published":730,"category":560,"image":731,"draft":564},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 Ursachen","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" meldet deine Nutzer ab. Drei Ursachen, und wie das Auth-Log sie trennt.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":733,"title":734,"description":735,"published":736,"category":560,"image":737,"draft":564},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": drei Ursachen","Supabase \"permission denied for schema public\" heißt: Ein Grant auf das Schema fehlt. Was ihn entfernt hat und welche Zeile ihn zurückbringt.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":739,"title":740,"description":741,"published":742,"category":560,"image":743,"draft":564},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": die drei Dinge, die es bedeutet","Supabase \"Bucket not found\" ist eins von drei Dingen: ein öffentlicher Link zu einem privaten Bucket, ein ungenauer Name oder das falsche Projekt.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":745,"title":746,"description":747,"published":748,"category":560,"image":749,"draft":564},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: Welcher Schlüssel streikt hier?","Ein Supabase invalid JWT ist PGRST301: ein signiertes Token hat die Prüfung nicht bestanden. In neueren Projekten ist das die Sitzung, nicht der API-Schlüssel.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":751,"title":752,"description":753,"published":754,"category":560,"image":755,"draft":564},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" heißt meist: keine Zeilen","Supabase gibt PGRST116 zurück, \"JSON object requested, multiple (or no) rows returned\", wenn die Abfrage nichts fand. Versteckte Zeilen wirken fehlend.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":757,"title":758,"description":759,"published":760,"category":560,"image":761,"draft":564},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" in Supabase: wo du nachsiehst","\"Database error saving new user\" heißt: etwas an deiner Supabase-Registrierung ist fehlgeschlagen. Der echte Fehler steht in deinen Logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":763,"title":764,"description":765,"published":766,"category":560,"image":767,"draft":564},"\u002Fblog\u002Fwhat-is-supabase","Was ist Supabase? Die Datenbank, die dein Builder ausgesucht hat","Was ist Supabase: die Datenbank, der Login und der Dateispeicher hinter deiner App. Supabase betreibt die Server, die Regeln zu deinen Zeilen gehören dir.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":769,"title":770,"description":771,"published":772,"category":560,"image":773,"draft":564},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Ein offengelegter AWS-Schlüssel im Frontend ist kein OpenAI-Key","Ein im Frontend offengelegter AWS-Zugriffsschlüssel liest und schreibt deinen Speicher. Die Lösung ist meist eine presigned URL, kein neuer Schlüssel.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":775,"title":776,"description":777,"published":778,"category":560,"image":779,"draft":564},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" beim Upload","\"New row violates row-level security policy for table objects\" heißt: Deinem Upload fehlt eine insert-Regel. Ein öffentlicher Bucket fügt keine hinzu.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":781,"title":782,"description":783,"published":784,"category":560,"image":785,"draft":564},"\u002Fblog\u002Fbase44-security-scan","Base44 Security Scan: das, was nur er sehen kann","Der Base44 Security Scan prüft sieben Arten von Problemen von innen. Hier ist die Hälfte, die er liest und sonst niemand, und die Hälfte, die er nie ansieht.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":787,"title":788,"description":789,"published":790,"category":560,"image":791,"draft":564},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Dein API-Key wurde geleakt. Die richtige Reihenfolge","Ein API-Key wurde geleakt und du weißt nicht, was zuerst zu tun ist. Nicht jeder Key im Frontend ist ein Leck, und die Reihenfolge zählt mehr als das Tempo.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":793,"title":794,"description":795,"published":796,"category":560,"image":797,"draft":564},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" ohne RLS abzuschalten","\"Infinite recursion detected in policy for relation\" heißt: Deine Policy hat die Tabelle gefragt, die sie schützt. So brichst du den Kreis.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":799,"title":800,"description":801,"published":802,"category":560,"image":803,"draft":564},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" in Supabase, und die falsche Lösung","\"No API key found in request\" heißt, deine Supabase-Anfrage kam ohne Schlüssel an. Die meisten Antworten zeigen stattdessen auf deine Datenbankregeln.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":805,"title":806,"description":807,"published":808,"category":560,"image":809,"draft":564},"\u002Fblog\u002Fis-base44-safe","Ist Base44 sicher? Was 5.442 echte Base44-Apps zeigten","Ist Base44 sicher? Wir haben 5.442 laufende Base44-Apps mit neun Checks geprüft. Fast alle bekamen ein B, aus Gründen, die der Inhaber nie gewählt hat.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":389,"title":811,"description":812,"published":813,"category":560,"image":814,"draft":564},"API-Schlüssel verstecken: ab in eine Supabase Edge Function","Einen API-Schlüssel verstecken heißt, ihn aus dem Browser zu nehmen. Eine Supabase Edge Function ist der kleinste Ort dafür, und zwei Schritte zählen mehr.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":816,"title":817,"description":818,"published":819,"category":560,"image":820,"draft":564},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Ist deine .env-Datei öffentlich? Zwölf Pfade zum Prüfen","Ist deine .env-Datei auf deinem eigenen Webserver öffentlich? Zwölf Adressen sagen es dir, und ein Treffer heißt: alles darin ist längst öffentlich.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":822,"title":823,"description":824,"published":825,"category":560,"image":826,"draft":564},"\u002Fblog\u002Fis-v0-safe","v0-Sicherheit: alle 1.790 gescannten v0-Apps bekamen ein A","v0-Sicherheit, gemessen an 1.790 laufenden v0-Apps: Jede bekam ein A. Nur 17 nannten eine Datenbank, und genau das misst das A vor allem.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":828,"title":829,"description":830,"published":831,"category":560,"image":832,"draft":564},"\u002Fblog\u002Fis-bolt-safe","Ist Bolt sicher? Was 1.123 echte Bolt-Apps zeigten","Ist Bolt sicher? Wir haben 1.123 laufende Bolt-Apps mit neun Checks geprüft. Das Hosting war sauber. Die Funde waren Schlüssel und offene Tabellen in den Apps.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":92,"title":834,"description":835,"published":836,"category":560,"image":837,"draft":564},"Ist Supabase down oder liegt es an deiner App? So erkennst du es","Ist Supabase down oder liegt es an deiner App? Ein pausiertes Projekt, eine volle Datenbank und ein eigener Fehler sehen gleich aus. Vier Prüfungen helfen.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":839,"title":840,"description":841,"published":842,"category":560,"image":843,"draft":564},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","Verschlüsselt Supabase meine Daten? Ja. Wovor das schützt","Verschlüsselt Supabase Daten? Ja: AES-256 im Ruhezustand, TLS bei der Übertragung, SOC 2 und ISO 27001. Was jedes abdeckt und welches Leck keines stoppt.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":845,"title":846,"description":847,"published":848,"category":560,"image":849,"draft":564},"\u002Fblog\u002Fsupabase-free-plan-limits","Supabase Gratis-Tarif: die Limits und was an jedem passiert","Die Limits des Supabase-Gratis-Tarifs: 500 MB Datenbank, 5 GB Egress und keine Backups. Was an jeder Grenze passiert und was $25 für Pro ändern.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":851,"title":852,"description":853,"published":854,"category":665,"image":855,"draft":564},"\u002Fblog\u002Ftest-your-supabase-backup","Teste dein Supabase-Backup, bevor du es brauchst","So testest du dein Supabase-Backup: in ein Übungsprojekt einspielen, Zeilen zählen, anmelden und die Zeile suchen, die einer abgeschnittenen Datei fehlt.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":857,"title":858,"description":859,"published":860,"category":665,"image":861,"draft":564},"\u002Fblog\u002Fsupabase-backup-github-action","Kostenloses Supabase-Backup per GitHub Action, mit Haken","Eine Supabase-Backup-GitHub-Action kostet nichts und passt für viele Apps. Der Workflow, der richtige Connection String und das Egress pro Lauf.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":863,"title":864,"description":865,"published":866,"category":665,"image":867,"draft":564},"\u002Fblog\u002Fdownload-your-supabase-backup","Warum du dein Supabase-Backup nicht herunterladen kannst","Dein Supabase-Backup kannst du auf aktuellen Projekten nicht herunterladen, weil die Tageskopie physisch ist. Wie du es prüfst und selbst eine Kopie hältst.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":869,"title":870,"description":871,"published":866,"category":560,"image":872,"draft":564},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": der fehlende Grant","Ab 30. Oktober antwortet eine neue Supabase-Tabelle mit \"permission denied for table\", bis du Zugriff erteilst. Der Grant aus der E-Mail ist die halbe Lösung.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":874,"title":875,"description":876,"published":877,"category":560,"image":878,"draft":564},"\u002Fblog\u002Fopen-api-endpoint-exposed","Ist ein offener API-Endpunkt ein Sicherheitsproblem? Sieh ins JSON","Dein Scan hat einen offenen API-Endpunkt gemeldet. Ob das zählt, hängt davon ab, was zurückkam, und die meisten hier gehörten der Plattform.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":880,"title":881,"description":882,"published":883,"category":560,"image":884,"draft":564},"\u002Fblog\u002Flovable-security-scan","Lovable Security Scan: das Eine, was er nicht beweist","Lovable Security Scan: was Quick Scan und Deep Scan prüfen, wann welcher läuft, und das Eine, was kein Scan von innen beweisen kann.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":886,"title":887,"description":888,"published":889,"category":665,"image":890,"draft":564},"\u002Fblog\u002Fsupabase-backup-auth-users","Warum in deinem Supabase-Dump keine Nutzer stehen","Führe supabase db dump allein aus und du bekommst die Form deiner Datenbank und keine einzige Zeile, und das auth-Schema mit deinen Nutzern fehlt ganz.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":892,"title":893,"description":894,"published":895,"category":560,"image":896,"draft":564},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domain abgelaufen, Website offline: was jetzt passiert","Deine Domain ist abgelaufen und deine Website ist offline. Welche Frist jetzt läuft, warum das Zertifikat das kleinere Problem ist, und wie du beides prüfst.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":898,"title":899,"description":900,"published":901,"category":560,"image":902,"draft":564},"\u002Fblog\u002Fis-lovable-safe","Ist Lovable sicher? Was 18.554 echte Lovable-Apps zeigten","Ist Lovable sicher? Wir haben 18.554 laufende Lovable-Apps mit neun Checks geprüft. Die Plattform war die sauberste von fünf. Die Funde saßen in den Apps.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":904,"title":905,"description":906,"published":907,"category":560,"image":908,"draft":564},"\u002Fblog\u002Fvibe-coded-app-security-checklist","Die Sicherheits-Checkliste für Vibe-Coding, in neun Prüfungen","Eine Sicherheits-Checkliste für Vibe-Coding mit neun Punkten, die jeder von außen an deiner Live-App nachprüfen kann, jeder mit einem Test in einer Zeile.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":910,"title":911,"description":912,"published":913,"category":560,"image":914,"draft":564},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Ein geheimer Stripe-Schlüssel im Frontend kann Geld bewegen","Ein geheimer Stripe-Schlüssel im Frontend kann erstatten, abbuchen und jeden Kundendatensatz lesen, den du hast. Dein pk_live_-Schlüssel gehört dorthin.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":916,"title":917,"description":918,"published":919,"category":560,"image":920,"draft":564},"\u002Fblog\u002Fvite-and-next-public-env-vars","Vite-Env-Variablen offengelegt: der Präfix heißt veröffentlichen","Vite-Env-Variablen offengelegt: Deine App hat getan, was der Präfix verlangt. VITE_ und NEXT_PUBLIC_ heißen veröffentlichen, und die KI kannte den Preis nie.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":922,"title":923,"description":924,"published":925,"category":560,"image":926,"draft":564},"\u002Fblog\u002Fbase44-source-maps","Base44-Sicherheit: was ein Scan meldet und was du ändern kannst","Base44-Sicherheit auf 5.438 gescannten Apps: Drei Befunde auf fast jeder gehören der Plattform, die Source Map ist das Base44-Badge, und deine Liste ist kurz.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":928,"title":929,"description":930,"published":931,"category":560,"image":932,"draft":564},"\u002Fblog\u002Fis-cursor-ai-safe","Ist Cursor AI sicher? Editor, Code und die App, die du veröffentlichst","Ist Cursor AI sicher? Drei Fragen in einer Suche: was Cursor behält, was sein Code falsch macht und ob deine veröffentlichte App offen steht.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":934,"title":935,"description":936,"published":937,"category":560,"image":938,"draft":564},"\u002Fblog\u002Fis-replit-safe","Ist Replit sicher? Was wir in 3.042 Replit-Apps gefunden haben","Ist Replit sicher? Wir haben 3.042 laufende Replit-Apps mit neun externen Checks geprüft. Die Funde saßen in der veröffentlichten App, nicht im Hosting.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":940,"title":941,"description":942,"published":943,"category":665,"image":944,"draft":564},"\u002Fblog\u002Fsupabase-storage-backup","Supabase Storage Backup: deine Datenbankkopie hat keine Dateien","Ein Supabase Storage Backup ist eine eigene Aufgabe. Datenbank-Backups enthalten die Liste deiner Dateien und keine davon, also bleibt jeder Upload kaputt.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":946,"title":947,"description":948,"published":949,"category":665,"image":950,"draft":564},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Supabase Point-in-Time Recovery: Kosten und Grenzen","Supabase Point-in-Time Recovery spult deine Datenbank auf jede Sekunde der letzten Woche zurück. $100 im Monat zusätzlich zu Pro, und nur die Datenbank.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":952,"title":953,"description":954,"published":955,"category":665,"image":956,"draft":564},"\u002Fblog\u002Fsupabase-project-paused-recover","Supabase-Projekt pausiert? Deine Daten sind noch da","Supabase hat dein Projekt nach einer Woche ohne Aktivität pausiert. Gelöscht ist nichts, Wiederherstellen steht neben dem Namen, und du hast ein Jahr.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":958,"title":959,"description":960,"published":961,"category":560,"image":962,"draft":564},"\u002Fblog\u002Fsafest-ai-app-builder","Welcher KI-App-Builder ist am sichersten? 30.998 Apps im Test","Welcher KI-App-Builder ist am sichersten? Wir haben 30.998 aktive Apps von Lovable, Base44, Replit, v0 und Bolt gescannt. Der Builder entscheidet das nicht.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":964,"title":965,"description":966,"published":967,"category":560,"image":968,"draft":564},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Row Level Security für jede Supabase-Tabelle aktivieren und prüfen","Row Level Security in Supabase ohne Policy sperrt eine Tabelle komplett. Eine Policy ohne den Schalter bringt gar nichts. Hier ist das SQL, und der Test.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":970,"title":971,"description":972,"published":973,"category":560,"image":974,"draft":564},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": was die Warnung übersieht","Supabase meldet \"RLS disabled in public\" als Fehler. Zur Lese-Policy, die deine Tabelle genauso offen lässt, sagt der Advisor gar nichts.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":976,"title":977,"description":978,"published":979,"category":560,"image":980,"draft":564},"\u002Fblog\u002Frotate-supabase-service-role-key","Geleakten Supabase-service_role-Schlüssel richtig tauschen","Supabase sagt: erst das Leck schließen. Andere Anleitungen: sofort tauschen. Was richtig ist, hängt davon ab, wohin dein service_role-Schlüssel gelangt ist.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":982,"title":983,"description":984,"published":985,"category":560,"image":986,"draft":564},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Vibe-Coding-Security-Scanner im Vergleich, unserer eingeschlossen","Der beste Vibe-Coding-Security-Scanner hängt an drei Fragen, die keine Funktionsliste beantwortet. Acht Tools im Vergleich, mit Preisen und unseren Lücken.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":988,"title":989,"description":990,"published":991,"category":560,"image":992,"draft":564},"\u002Fblog\u002Fsupabase-security-checker","Supabase Security Checker: die fünf Prüfungen selbst machen","Ein Supabase Security Checker liest deine veröffentlichte App statt deiner Projekteinstellungen. Hier sind die fünf Prüfungen und wie du jede selbst ausführst.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":994,"title":995,"description":996,"published":997,"category":560,"image":998,"draft":564},"\u002Fblog\u002Fvibe-coding-security-scanner","Vibe-Coding-Security-Scanner: was ein URL-Scan übersieht","Ein Vibe-Coding-Security-Scanner liest deine laufende App von außen. Was das abdeckt, die vier Dinge, die er nicht sehen kann, und wie du das Ergebnis liest.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1000,"title":1001,"description":1002,"published":1003,"category":560,"image":1004,"draft":564},"\u002Fblog\u002Fmissing-security-headers","Fehlende Sicherheitsheader: wann sie wirklich zählen","Fehlende Sicherheitsheader ist unser häufigster Befund. Wogegen sie schützen, und wann sie die unwichtigste Zeile in deinem Bericht sind.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1006,"title":1007,"description":1008,"published":1009,"category":560,"image":1010,"draft":564},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Dein OpenAI-API-Schlüssel liegt im Frontend. Tausch ihn aus.","Ein OpenAI-API-Schlüssel im Frontend lässt sich an keine Domain binden. Tausch ihn heute, leg den Aufruf hinter deinen Server und begrenze das Budget.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1012,"title":1013,"description":1014,"published":1015,"category":560,"image":1016,"draft":564},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","API-Schlüssel im Frontend: was 30.998 Apps wirklich ausliefern","Ein API-Schlüssel im Frontend ist meistens ein Google-Maps-Schlüssel. Wir haben 30.998 aktive Vibe-Coding-Apps gescannt und gezählt, was wirklich austritt.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1018,"title":1019,"description":1020,"published":1021,"category":665,"image":1022,"draft":564},"\u002Fblog\u002Fsupabase-backup-tools-compared","Supabase-Backup-Tools im Vergleich, unseres eingeschlossen","Vier Arten von Supabase-Backup-Tool, was jedes wirklich kopiert und wann eine kostenlose GitHub Action jeden Anbieter schlägt, uns eingeschlossen.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1024,"title":1025,"description":1026,"published":1027,"category":560,"image":1028,"draft":564},"\u002Fblog\u002Freplit-secrets-explained","Secrets in Replit nutzen, und was trotzdem veröffentlicht wird","Secrets in Replit nutzen: anlegen, auslesen und die zwei Gründe beheben, warum undefined zurückkommt. Dazu die Schlüssel, die das Werkzeug nicht schützt.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1030,"title":1031,"description":1032,"published":1033,"category":665,"image":1034,"draft":564},"\u002Fblog\u002Fback-up-supabase-free-tier","Supabase Gratis-Tarif: Backup ohne Terminal selbst machen","Im Supabase Gratis-Tarif gibt es keine Backups, die Kopie musst du selbst machen. Wie das im Dashboard geht und was der CSV-Weg auslässt.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1036,"title":1037,"description":1038,"published":1039,"category":560,"image":1040,"draft":564},"\u002Fblog\u002Fis-supabase-secure","Ist Supabase sicher? Ja. Dein Projekt ist eine eigene Frage","Ist Supabase sicher? Die Plattform ist auditiert, verschlüsselt und pentestet. Supabase schreibt selbst auf, wo das aufhört und deine Einstellungen anfangen.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1042,"title":1043,"description":1044,"published":1045,"category":560,"image":1046,"draft":564},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Wo du deine Supabase API-Keys findest: anon, service_role, URL","Projekt-URL, anon-Schlüssel und service_role-Schlüssel liegen auf einer Seite im Dashboard. Wo sie ist, und welcher der vier Werte in deine App gehört.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1048,"title":1049,"description":1050,"published":1051,"category":560,"image":1052,"draft":564},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy in Supabase: was jetzt?","\"New row violates row-level security policy\" heißt, Supabase hat einen Schreibvorgang abgelehnt. Die schnelle Lösung öffnet die Tabelle wieder für alle.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":425,"title":1054,"description":1055,"published":1056,"category":560,"image":1057,"draft":564},"Ist eine CORS-Wildcard ein Sicherheitsrisiko? Meist nicht.","Ist eine CORS-Wildcard ein Sicherheitsrisiko? Meist ist sie die Voreinstellung deines Builders und gibt nichts preis, was dein Server nicht ohnehin herausgab.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1059,"title":1060,"description":1061,"published":1062,"category":665,"image":1063,"draft":564},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase Branching ist kein Backup. Es geht nur vorwärts.","Warum Supabase Branching kein Backup ist: Ein Branch startet ohne deine Daten, und ein Merge bringt nur das Schema. Wofür es gut ist und was stattdessen hilft.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1065,"title":1066,"description":1067,"published":1068,"category":665,"image":1069,"draft":564},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Supabase-Backup wiederherstellen, und was danach kaputt ist","Wie du ein Supabase-Backup aus dem Dashboard oder aus einer Dump-Datei wiederherstellst, was ersetzt wird und warum die App danach kaputt sein kann.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1071,"title":1072,"description":1073,"published":1074,"category":560,"image":1075,"draft":564},"\u002Fblog\u002Fsupabase-storage-bucket-public","Dein Supabase-Storage-Bucket ist öffentlich. Ist das ein Problem?","Ein öffentlicher Supabase-Storage-Bucket heißt: Wer die URL einer Datei hat, kann sie öffnen. Er heißt nicht, dass jemand den Inhalt auflisten darf.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1077,"title":1078,"description":1079,"published":1080,"category":560,"image":1081,"draft":564},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Ist ein Google-API-Schlüssel im Frontend ein Problem?","Ein Google-API-Schlüssel im Frontend ist der Fund unseres Scanners Nummer eins, und meistens unbedenklich. Eine kostenlose Einstellung entscheidet darüber.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1083,"title":1084,"description":1085,"published":1086,"category":665,"image":1087,"draft":564},"\u002Fblog\u002Fai-agent-deleted-my-database","Ein KI-Agent hat meine Supabase-Daten gelöscht. Was hole ich zurück?","Ein KI-Agent hat Daten aus deiner Datenbank gelöscht. Was du zurückholst, stand schon vorher fest, und die nächsten Minuten entscheiden über den Rest.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1089,"title":1090,"description":1091,"published":1092,"category":560,"image":1093,"draft":564},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Kann jeder deine Supabase-Datenbank lesen? 3.680 Apps im Test","Kann jeder deine Supabase-Datenbank ohne Login lesen? Wir haben 30.998 aktive Apps aus KI-Buildern gescannt und gemessen, wie oft die Antwort ja lautet.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1095,"title":1096,"description":1097,"published":1092,"category":560,"image":1098,"draft":564},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source-Maps öffentlich: deine App veröffentlicht ihren Quellcode","Eine öffentliche Source-Map lässt jeden den Originalcode deiner App lesen, Kommentare inklusive. Der 30-Sekunden-Check, und was wirklich zählt.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1100,"title":1101,"description":1102,"published":1103,"category":560,"image":1104,"draft":564},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: ist er derselbe wie der anon key?","Supabase hat anon und service_role durch öffentliche und geheime Schlüssel ersetzt. Welcher gehört in deine App, und welcher nie?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1106,"title":1107,"description":1108,"published":1109,"category":665,"image":1110,"draft":564},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Sichert Supabase meine Datenbank? Das hängt von deinem Tarif ab.","Sichert Supabase deine Datenbank? Auf bezahlten Tarifen täglich, im Gratis-Tarif gar nicht. So findest du heraus, was du hast und was es nicht abdeckt.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1112,"title":1113,"description":1114,"published":1115,"category":560,"image":1116,"draft":564},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security ist an. Die Tabelle ist trotzdem offen.","Supabase Row Level Security anzuschalten schützt keine Tabelle. Erst deine Policies tun das, und die, die deine App repariert hat, lässt oft alle herein.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1118,"title":1119,"description":1120,"published":1115,"category":665,"image":1121,"draft":564},"\u002Fblog\u002Fversion-history-is-not-a-backup","Der Versionsverlauf ist kein Backup. Er holt keine Tabelle zurück.","Lovable und Bolt führen einen Versionsverlauf für deinen Code. Deine Datenbank ist ein eigener Dienst, und ein Rücksprung holt deine Daten nicht zurück.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1123,"title":1124,"description":1125,"published":1126,"category":665,"image":1127,"draft":564},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Drei Wege, eine Supabase-Datenbank zu sichern, und was fehlt","Das Dashboard, pg_dump und ein verwalteter Dienst. Was jeder Weg wirklich sichert, was er stillschweigend auslässt und welcher den Kontoverlust übersteht.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1129,"title":1130,"description":1131,"published":1126,"category":560,"image":1132,"draft":564},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Welche API-Schlüssel im Frontend sicher sind, und welche nicht","Dein Supabase-anon-Schlüssel darf öffentlich sein. Der service_role-Schlüssel nicht. Er ignoriert jede Regel, die du setzt. So erkennst du den Unterschied.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213638658]