{"id":3797,"date":"2025-01-25T12:40:47","date_gmt":"2025-01-25T11:40:47","guid":{"rendered":"https:\/\/informatik.htwk-leipzig.de\/seminar\/?p=3797"},"modified":"2025-01-25T12:40:47","modified_gmt":"2025-01-25T11:40:47","slug":"supabase","status":"publish","type":"post","link":"https:\/\/informatik.htwk-leipzig.de\/seminar\/lehrveranstaltungen\/betriebliche-informationssysteme\/2025\/supabase\/","title":{"rendered":"Supabase"},"content":{"rendered":"<h1 dir=\"auto\">Supabase: Die Open-Source Firebase-Alternative<\/h1>\n<ul dir=\"auto\" data-sourcepos=\"3:1-28:0\">\n<li data-sourcepos=\"3:1-3:34\"><a href=\"#1-allgemeines\" data-sourcepos=\"3:3-3:34\">1. Allgemeines<\/a><\/li>\n<li data-sourcepos=\"4:1-4:42\"><a href=\"#2-preisgestaltung\" data-sourcepos=\"4:3-4:42\">2. Preisgestaltung<\/a><\/li>\n<li data-sourcepos=\"5:1-10:40\"><a href=\"#3-funktionen-und-features\" data-sourcepos=\"5:3-5:58\">3. Funktionen und Features<\/a>\n<ul data-sourcepos=\"6:3-10:40\">\n<li data-sourcepos=\"6:3-6:34\"><a href=\"#31-datenbank\" data-sourcepos=\"6:5-6:34\">3.1 Datenbank<\/a><\/li>\n<li data-sourcepos=\"7:3-7:54\"><a href=\"#32-echtzeit-funktionen\" data-sourcepos=\"7:5-7:54\">3.2 Echtzeit-Funktionen<\/a><\/li>\n<li data-sourcepos=\"8:3-8:50\"><a href=\"#33-authentifizierung\" data-sourcepos=\"8:5-8:50\">3.3 Authentifizierung<\/a><\/li>\n<li data-sourcepos=\"9:3-9:42\"><a href=\"#34-analyse-tools\" data-sourcepos=\"9:5-9:42\">3.4 Analyse-Tools<\/a><\/li>\n<li data-sourcepos=\"10:3-10:40\"><a href=\"#35-self-hosting\" data-sourcepos=\"10:5-10:40\">3.5 Self Hosting<\/a><\/li>\n<\/ul>\n<\/li>\n<li data-sourcepos=\"11:1-16:46\"><a href=\"#4-vergleich-mit-anderen-anbietern\" data-sourcepos=\"11:3-11:74\">4. Vergleich mit anderen Anbietern<\/a>\n<ul data-sourcepos=\"12:3-16:46\">\n<li data-sourcepos=\"12:3-12:34\"><a href=\"#41-datenbank\" data-sourcepos=\"12:5-12:34\">4.1 Datenbank<\/a><\/li>\n<li data-sourcepos=\"13:3-13:52\"><a href=\"#42-echtzeitfunktionen\" data-sourcepos=\"13:5-13:52\">4.2 Echtzeitfunktionen<\/a><\/li>\n<li data-sourcepos=\"14:3-14:50\"><a href=\"#43-authentifizierung\" data-sourcepos=\"14:5-14:50\">4.3 Authentifizierung<\/a><\/li>\n<li data-sourcepos=\"15:3-15:40\"><a href=\"#44-analysetools\" data-sourcepos=\"15:5-15:40\">4.4 Analysetools<\/a><\/li>\n<li data-sourcepos=\"16:3-16:46\"><a href=\"#45-preisgestaltung\" data-sourcepos=\"16:5-16:46\">4.5 Preisgestaltung<\/a><\/li>\n<\/ul>\n<\/li>\n<li data-sourcepos=\"17:1-25:46\"><a href=\"#5-supabase-in-der-praxis-eine-einf%C3%BChrung-mit-beispiel\" data-sourcepos=\"17:3-17:116\">5 Supabase in der Praxis: Eine Einf\u00fchrung mit Beispiel<\/a>\n<ul data-sourcepos=\"18:3-25:46\">\n<li data-sourcepos=\"18:3-18:108\"><a href=\"#51-supabase-self-hosting-oder-gehostete-variante\" data-sourcepos=\"18:5-18:108\">5.1 Supabase: Self-Hosting oder gehostete Variante?<\/a><\/li>\n<li data-sourcepos=\"19:3-24:81\"><a href=\"#52-ein-beispiel-eine-todo-app-mit-supabase\" data-sourcepos=\"19:5-19:95\">5.2 Ein Beispiel: Eine Todo-App mit Supabase<\/a>\n<ul data-sourcepos=\"20:5-24:81\">\n<li data-sourcepos=\"20:5-20:75\"><a href=\"#521-supabase-projekt-einrichten\" data-sourcepos=\"20:7-20:75\">5.2.1 Supabase-Projekt einrichten<\/a><\/li>\n<li data-sourcepos=\"21:5-21:69\"><a href=\"#522-frontend-implementierung\" data-sourcepos=\"21:7-21:69\">5.2.2 Frontend Implementierung<\/a><\/li>\n<li data-sourcepos=\"22:5-22:73\"><a href=\"#523-supabase-client-einrichten\" data-sourcepos=\"22:7-22:73\">5.2.3 Supabase Client einrichten<\/a><\/li>\n<li data-sourcepos=\"23:5-23:47\"><a href=\"#524-html-struktur\" data-sourcepos=\"23:7-23:47\">5.2.4 HTML-Struktur<\/a><\/li>\n<li data-sourcepos=\"24:5-24:81\"><a href=\"#525-hauptfunktionen-implementieren\" data-sourcepos=\"24:7-24:81\">5.2.5 Hauptfunktionen implementieren<\/a><\/li>\n<\/ul>\n<\/li>\n<li data-sourcepos=\"25:3-25:46\"><a href=\"#53-zusammenfassung\" data-sourcepos=\"25:5-25:46\">5.3 Zusammenfassung<\/a><\/li>\n<\/ul>\n<\/li>\n<li data-sourcepos=\"26:1-28:0\"><a href=\"#literatur\" data-sourcepos=\"26:3-26:25\">Literatur<\/a><\/li>\n<\/ul>\n<h2 dir=\"auto\" data-sourcepos=\"29:1-29:17\"><a id=\"user-content-1-allgemeines\" class=\"anchor\" href=\"#1-allgemeines\" aria-hidden=\"true\"><\/a>1. Allgemeines<\/h2>\n<p dir=\"auto\" data-sourcepos=\"31:1-31:405\">Supabase ist eine Open-Source-Platform, welche Entwicklern die einfache Erstellung von skalierbaren Echtzeit-Anwendungen mit einer Vielzahl von bereitgestellten Backend-Services und Tools erm\u00f6glicht. Dies beinhaltet zum Beispiel eine PostgreSQL Datenbank, einfache Authentifizierungsm\u00f6glichkeiten sowie Analytics und APIs, welche eine einfache Abfrage der Datenbank aus der Anwendung heraus erm\u00f6glicht.<\/p>\n<p dir=\"auto\" data-sourcepos=\"33:1-33:272\">Seit seiner Gr\u00fcndung 2020 ist Supabase stetig gewachsen und hat in der Entwicklercommunity als Open-Source Firebase-Alternative hohes Ansehen erlangen k\u00f6nnen und wird mittlerweile in zahlreichen Unternehmen wie Audi, facebook, salesforce und Google genutzt (vgl. [8]).<\/p>\n<h2 dir=\"auto\" data-sourcepos=\"35:1-35:21\"><a id=\"user-content-2-preisgestaltung\" class=\"anchor\" href=\"#2-preisgestaltung\" aria-hidden=\"true\"><\/a>2. Preisgestaltung<\/h2>\n<p dir=\"auto\" data-sourcepos=\"37:1-42:346\">Das Bezahlmodell bei Supabase ist in 4 bzw. 5 Kategorien unterteilt: Free, Pro, Team, Enterprise und Self-host. Im Free Modell erh\u00e4lt man nur begrenzte Funktionalit\u00e4ten und Rechenkapizit\u00e4ten, muss daf\u00fcr aber nichts bezahlen. Im Pro Modell bezahlt man 25 $ pro Monat und erh\u00e4lt daf\u00fcr eine Erweiterung der Features und Leistungen aus dem Free Modell. \u00c4hnlich zu Firebase wird hier bei \u00dcberschreitung der Rechenkapazit\u00e4ten (z.B. Speicherplatz, Bandbreite, Lesevorg\u00e4nge usw.) ein Pay-As-You-Go Ansatz verfolgt, bei dem man nur so viel bezahlt, wie man tats\u00e4chlich verbraucht\/ben\u00f6tigt hat, was eine einfache und vorhersehbare Preiskalkulation erm\u00f6glicht. Im Team Modell gibt es f\u00fcr 599 $ pro Monat erneut ein Upgrade der Leistungen, wobei hier noch zus\u00e4tzliche Features hinzukommen, welche f\u00fcr gro\u00dfe Projekte und Teams n\u00fctzlich sind. Das Enterprise Modell wird individuell mit dem Kunden vereinbart, sodass Preis, Leistung und Funktionen von den getroffenen Vereinbarungen abh\u00e4ngig sind (vgl. [7]). Supabase kann auch auf eigener Hardware gehostet werden, wobei keine Entgelte an Supabase entrichtet werden m\u00fcssen. Mehr dazu in <a href=\"#35-self-hosting\" data-sourcepos=\"42:131-42:161\">Kapitel 3.5<\/a>. In allen Modellen kann eine Preisgrenze festgelegt werden, sodass bei Fehlern im Programm oder pl\u00f6tzlichem Anstieg der Nutzerzahl keine unerwartet hohen Rechnungen entstehen k\u00f6nnen.<\/p>\n<p dir=\"auto\" data-sourcepos=\"44:1-44:60\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3805 size-full\" src=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/supabase-pricing.png\" alt=\"\" width=\"1534\" height=\"941\" srcset=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/supabase-pricing.png 1534w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/supabase-pricing-300x184.png 300w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/supabase-pricing-1024x628.png 1024w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/supabase-pricing-768x471.png 768w\" sizes=\"auto, (max-width: 1534px) 100vw, 1534px\" \/><\/p>\n<h2 dir=\"auto\" data-sourcepos=\"46:1-46:29\"><a id=\"user-content-3-funktionen-und-features\" class=\"anchor\" href=\"#3-funktionen-und-features\" aria-hidden=\"true\"><\/a>3. Funktionen und Features<\/h2>\n<p dir=\"auto\" data-sourcepos=\"48:1-48:260\">Supabase bietet eine breite Palette an Funktionen, die auch Entwicklern ohne tiefgehende Kenntnisse in Serverarchitektur erm\u00f6glicht, eine vollst\u00e4ndige Backend-L\u00f6sung f\u00fcr ihren Anwendungsfall zu erstellen. Hier ein \u00dcberblick \u00fcber die wichtigsten Features:<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"50:1-50:17\"><a id=\"user-content-31-datenbank\" class=\"anchor\" href=\"#31-datenbank\" aria-hidden=\"true\"><\/a>3.1 Datenbank<\/h3>\n<p dir=\"auto\" data-sourcepos=\"52:1-52:557\">Die zentrale Funktion von Supabase ist dessen Datenbank. Hierbei kommt die Open-Source Datenbank PostgreSQL zum Einsatz, welche eine hohe Performance und Skalierbarkeit bietet; trotz relationalem Datenbankmodell. Entwickler k\u00f6nnen die Datenbank \u00fcber die Web-Oberfl\u00e4che oder \u00fcber die API mithilfe von normalen SQL Abfragen einsehen und manipulieren. Da die Daten somit in einer zu Supabase abgekoppelten Datenbank liegen, ist eine sp\u00e4tere Entfernung von Supabase aus dem Techstack problemlos m\u00f6glich, da alle Daten behalten werden k\u00f6nnen (vgl. [1]).<\/p>\n<p dir=\"auto\" data-sourcepos=\"54:1-54:450\">Auch Dateien k\u00f6nnen in Supabase gespeichert werden. Neben der PostgreSQL Datenbank gibt es auch einen Open-Source S3 kompatiblen Object-Store. Die darin gespeicherten Assets k\u00f6nnen \u00fcber die gleiche REST-API angefragt werden wie normale Datenbank Querys. Ein global aufgespanntes Content-Delivery-Network (CDN) kann aus \u00fcber 285 St\u00e4dten die gespeicherten Dateien an die Nutzer verteilen, wodurch die Latenz erheblich verringert wird (vgl. [3]).<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"56:1-56:27\"><a id=\"user-content-32-echtzeit-funktionen\" class=\"anchor\" href=\"#32-echtzeit-funktionen\" aria-hidden=\"true\"><\/a>3.2 Echtzeit-Funktionen<\/h3>\n<p dir=\"auto\" data-sourcepos=\"58:1-58:436\">Ebenfalls werden Echtzeit-Updates unterst\u00fctzt, sodass \u00c4nderungen der Daten in Echtzeit verfolgt und von verbundenen Clients entsprechend dargestellt werden k\u00f6nnen. Auch die Synchronisierung verschiedener Client-States ist m\u00f6glich. Diese Funktion ist besonders n\u00fctzlich f\u00fcr Anwendungen, die auf zeitnahe Aktualisierungen der Daten angewiesen sind, wie z.B. Chat-Anwendungen, kollaborative Whiteboards oder Live-Ticker. (vgl. [4])<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"60:1-60:25\"><a id=\"user-content-33-authentifizierung\" class=\"anchor\" href=\"#33-authentifizierung\" aria-hidden=\"true\"><\/a>3.3 Authentifizierung<\/h3>\n<p dir=\"auto\" data-sourcepos=\"62:1-62:675\">Supabase erm\u00f6glicht die einfache Implementierung von diversen Authentifizierungsl\u00f6sungen. Unterst\u00fctzte Dienste sind grob in E-Mail und OAuth unterteilt. Bei E-Mail Authentifizierung m\u00fcssen sich die Nutzer mit der bei der Registrierung angegebenen E-Mail-Adresse und Passwort anmelden. Diese Form muss gr\u00f6\u00dftenteils selber gemanagt werden, z.B. wenn es um Mail-Server f\u00fcr Registrierungsbest\u00e4tigungen geht. Bei OAuth werden die meisten gro\u00dfen Dienste bereitgestellt, dazu geh\u00f6ren unter anderem Google, Facebook und GitHub. Zus\u00e4tzlich sind erweiterte Sicherheitsmechanismen wie 2-Faktor-Authentifizierung oder rollenbasierte Zugriffskontrollen verf\u00fcgbar (vgl. [2]).<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"64:1-64:21\"><a id=\"user-content-34-analyse-tools\" class=\"anchor\" href=\"#34-analyse-tools\" aria-hidden=\"true\"><\/a>3.4 Analyse-Tools<\/h3>\n<p dir=\"auto\" data-sourcepos=\"66:1-66:528\">Mithilfe diverser Analysewerkzeuge k\u00f6nnen Anwendungsentwickler Statistiken \u00fcber die Nutzung ihrer Anwendung einsehen. \u00dcber Echtzeit-Statistiken lassen sich Daten und Zugriffsmuster der Nutzer nachvollziehen, was eine bessere Anpassung an Nutzerbed\u00fcrfnisse erm\u00f6glicht und die Skalierung f\u00fcr die Zukunft vereinfacht. Auch die Logs der Anfragen auf die REST-APIs ist m\u00f6glich, sodass eventuell sehr h\u00e4ufig auftretende Anfragen erkannt werden k\u00f6nnen um das Nutzererlebnis und die Serverauslastung zu optimieren (vgl. [6]).<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"68:1-68:20\"><a id=\"user-content-35-self-hosting\" class=\"anchor\" href=\"#35-self-hosting\" aria-hidden=\"true\"><\/a>3.5 Self Hosting<\/h3>\n<p dir=\"auto\" data-sourcepos=\"70:1-70:552\">Das Team hinter Supabase stellt diverse Docker-Images zur Verf\u00fcgung, mit denen man eine eigene Supabase-Instanz auf eigener Hardware betreiben kann. Eine in einem GitHub Repository liegende Docker-Compose Datei erm\u00f6glicht das einfache Starten und Kombinieren der einzelnen Services. Nach dem Start kann dann \u00fcber den Browser auf Supabase-Studio zugegriffen werden. Diese Variante der Nutzung von Supabase ist, ausgenommen der Betriebskosten f\u00fcr die Hardware, v\u00f6llig kostenfrei und es m\u00fcssen keine Abgaben an Supabase geleistet werden (vgl [5]).<\/p>\n<h2 dir=\"auto\" data-sourcepos=\"72:1-72:37\"><a id=\"user-content-4-vergleich-mit-anderen-anbietern\" class=\"anchor\" href=\"#4-vergleich-mit-anderen-anbietern\" aria-hidden=\"true\"><\/a>4. Vergleich mit anderen Anbietern<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-3803\" src=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-amplify-300x43.png\" alt=\"\" width=\"300\" height=\"43\" srcset=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-amplify-300x43.png 300w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-amplify-1024x145.png 1024w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-amplify-768x109.png 768w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-amplify-1536x218.png 1536w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-amplify-2048x290.png 2048w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-3804\" src=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-supabase-300x58.png\" alt=\"\" width=\"300\" height=\"58\" srcset=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-supabase-300x58.png 300w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-supabase-1024x197.png 1024w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-supabase-768x148.png 768w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-supabase-1536x296.png 1536w, https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2025\/01\/logo-supabase-2048x395.png 2048w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone \" src=\"https:\/\/encrypted-tbn0.gstatic.com\/images?q=tbn:ANd9GcR7XMRuuZ_tPh8Aw_rAXL44wBwCM-plDvWaeg&amp;s\" width=\"285\" height=\"80\" \/><\/p>\n<p dir=\"auto\" data-sourcepos=\"81:1-81:684\">Supabase bezeichnet sich selbst als <em data-sourcepos=\"81:37-81:70\">open source Firebase alternative<\/em> (vgl. [8]) und teilt daher viele Eigenschaften mit seinem selbst ernannten Konkurrenten. Der Hauptunterschied ist die Verf\u00fcgbarkeit des Quellcodes, welcher bei <strong data-sourcepos=\"81:235-81:246\">Supabase<\/strong> auf <a href=\"https:\/\/github.com\/supabase\/supabase\" target=\"_blank\" rel=\"nofollow noreferrer noopener\" data-sourcepos=\"81:252-81:297\">GitHub<\/a> \u00f6ffentlich einsehbar ist, w\u00e4hrend es sich bei den Konkurrenzprodukten wie Googles <strong data-sourcepos=\"81:383-81:394\">Firebase<\/strong> oder Amazons <strong data-sourcepos=\"81:409-81:423\">AWS Amplify<\/strong> um propriet\u00e4re Software handelt, deren Quellcode nicht \u00f6ffentlich zug\u00e4nglich ist. Die Zug\u00e4nglichkeit des Quellcodes erm\u00f6glicht es Nutzern au\u00dferdem, eine eigene Instanz des Programms selber zu hosten, wie in <a href=\"#2-preisgestaltung\" data-sourcepos=\"81:638-81:668\">Kapitel 2<\/a> erkl\u00e4rt wurde.<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"83:1-83:17\"><a id=\"user-content-41-datenbank\" class=\"anchor\" href=\"#41-datenbank\" aria-hidden=\"true\"><\/a>4.1 Datenbank<\/h3>\n<p dir=\"auto\" data-sourcepos=\"85:1-85:486\">Ein weiterer Unterschied besteht auf der technischen Ebene, und zwar benutzt Supabase ein relationales Datenbankmodell mit dem SQL-Dialekt PostgreSQL als Abfragesprache (siehe <a href=\"#31-datenbank\" data-sourcepos=\"85:177-85:204\">Kapitel 3.1<\/a>), w\u00e4hrend Firebase auf ein eigenes, cloudbasiertes und dokumentenorientiertes NoSQL-Datenbankmanagementsystem namens Firestore zur\u00fcckgreift. Amplify verwendet ebenfalls ein klassisches RDBMS, welches Aurora hei\u00dft und mit dem verbreiteten SQL-Dialekt MySQL verwaltet werden kann.<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"87:1-87:26\"><a id=\"user-content-42-echtzeitfunktionen\" class=\"anchor\" href=\"#42-echtzeitfunktionen\" aria-hidden=\"true\"><\/a>4.2 Echtzeitfunktionen<\/h3>\n<p dir=\"auto\" data-sourcepos=\"89:1-89:383\">Firebase erm\u00f6glicht es, einzelne Dokumente mit einem Listener auszustatten, welcher \u00c4nderungen am jeweiligen Dokument registriert und die gew\u00fcnschte Callbackfunktion ausf\u00fchrt. Amplify bietet die M\u00f6glichkeit, \u00c4nderungen an den Daten in der Cloud mittels eines Subscription-Prinzips automatisch vom Server an diejenigen Clients zu schicken, die auf der Subscription-Liste stehen.<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"91:1-91:25\"><a id=\"user-content-43-authentifizierung\" class=\"anchor\" href=\"#43-authentifizierung\" aria-hidden=\"true\"><\/a>4.3 Authentifizierung<\/h3>\n<p dir=\"auto\" data-sourcepos=\"93:1-93:236\">Die Authentifizierungsm\u00f6glichkeiten von Supabase, Firebase und Amplify unterscheiden sich in ihrer Vielfalt kaum. E-Mail, OAuth \u00fcber verschiedene Services sowie Multifaktorautorisierung k\u00f6nnen bei allen Anbietern eingerichtet werden.<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"95:1-95:20\"><a id=\"user-content-44-analysetools\" class=\"anchor\" href=\"#44-analysetools\" aria-hidden=\"true\"><\/a>4.4 Analysetools<\/h3>\n<p dir=\"auto\" data-sourcepos=\"97:1-97:301\">Firebase bietet durch die Integration von Google Analytics ein m\u00e4chtiges Analysetool zur \u00dcberwachung der Nutzeraktivit\u00e4ten. \u00c4hnlich verh\u00e4lt es sich mit Amplify und Amazon Pinpoint. Supabase hingegen hat kein eigenes Analysetool, erm\u00f6glicht jedoch die Integration von Drittanbietern (vgl. [9]).<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"99:1-99:23\"><a id=\"user-content-45-preisgestaltung\" class=\"anchor\" href=\"#45-preisgestaltung\" aria-hidden=\"true\"><\/a>4.5 Preisgestaltung<\/h3>\n<p dir=\"auto\" data-sourcepos=\"101:1-101:296\">\u00c4hnlich wie Supabase bietet Firebase eine kostenlose Nutzung seiner Dienste bis zu einer bestimmten Grenze. Wird diese Grenze \u00fcberschritten, zahlt man proportional zur Nutzung des jeweiligen Dienstes. Im Unterschied zu Supabase sind die Bezahlmodelle hier jedoch nicht gestaffelt (vgl. [10]).<\/p>\n<p dir=\"auto\" data-sourcepos=\"103:1-103:475\">Auch Amazon Web Services wirbt mit einem kostenlosen Kontingent f\u00fcr sein Produkt Amplify. Dieses beinhaltet unter einer zw\u00f6lfmonatigen Bereitstellung der Anwendung, 1.000 Build-Minuten pro Monat und f\u00fcnf Gigabyte Datenspeicher. Ist dieses Kontingent verbraucht, bezahlt man f\u00fcr alles, was dar\u00fcber hinausgeht. Die Kosten orientieren sich dabei an der tats\u00e4chlichen Nutzung und sind nicht pauschal. Man zahlt also pro Gigabyte, pro Zugriff, pro Stunde etc. (vgl. [11]).<\/p>\n<p dir=\"auto\" data-sourcepos=\"105:1-105:94\">Sowohl Firebase als auch Amplify stellen auf ihrer Website einen Kostenrechner zur Verf\u00fcgung.<\/p>\n<h2 dir=\"auto\" data-sourcepos=\"107:1-107:58\"><a id=\"user-content-5-supabase-in-der-praxis-eine-einf\u00fchrung-mit-beispiel\" class=\"anchor\" href=\"#5-supabase-in-der-praxis-eine-einf%C3%BChrung-mit-beispiel\" target=\"_blank\" rel=\"nofollow noreferrer noopener\" aria-hidden=\"true\"><\/a>5 Supabase in der Praxis: Eine Einf\u00fchrung mit Beispiel<\/h2>\n<h3 dir=\"auto\" data-sourcepos=\"109:1-109:55\"><a id=\"user-content-51-supabase-self-hosting-oder-gehostete-variante\" class=\"anchor\" href=\"#51-supabase-self-hosting-oder-gehostete-variante\" aria-hidden=\"true\"><\/a>5.1 Supabase: Self-Hosting oder gehostete Variante?<\/h3>\n<p dir=\"auto\" data-sourcepos=\"111:1-111:48\">Supabase bietet zwei M\u00f6glichkeiten zur Nutzung:<\/p>\n<ul dir=\"auto\" data-sourcepos=\"113:1-115:0\">\n<li data-sourcepos=\"113:1-113:151\"><strong data-sourcepos=\"113:3-113:29\">Self-Hosting mit Docker<\/strong>: F\u00fcr maximale Kontrolle \u00fcber Daten und Infrastruktur. Ideal f\u00fcr Unternehmen mit spezifischen Compliance-Anforderungen.<\/li>\n<li data-sourcepos=\"114:1-115:0\"><strong data-sourcepos=\"114:3-114:24\">Gehostete Variante<\/strong>: Eine einfache und schnelle M\u00f6glichkeit, Supabase ohne Aufwand einzurichten. Perfekt f\u00fcr Entwickler, die schnell starten m\u00f6chten.<\/li>\n<\/ul>\n<p dir=\"auto\" data-sourcepos=\"116:1-116:175\">In diesem Artikel nutzen wir die <strong data-sourcepos=\"116:34-116:55\">gehostete Variante<\/strong>, um eine Todo-App zu erstellen. So kannst du die Funktionen von Supabase ohne komplexe Einrichtung direkt ausprobieren.<\/p>\n<h3 dir=\"auto\" data-sourcepos=\"118:1-118:48\"><a id=\"user-content-52-ein-beispiel-eine-todo-app-mit-supabase\" class=\"anchor\" href=\"#52-ein-beispiel-eine-todo-app-mit-supabase\" aria-hidden=\"true\"><\/a>5.2 Ein Beispiel: Eine Todo-App mit Supabase<\/h3>\n<p dir=\"auto\" data-sourcepos=\"120:1-120:61\">Wir entwickeln eine einfache Todo-App mit folgenden Features:<\/p>\n<ul dir=\"auto\" data-sourcepos=\"122:1-125:0\">\n<li data-sourcepos=\"122:1-122:54\">Nutzer k\u00f6nnen sich mit E-Mail und Passwort anmelden<\/li>\n<li data-sourcepos=\"123:1-123:57\">Aufgaben werden in einer Supabase-Datenbank gespeichert<\/li>\n<li data-sourcepos=\"124:1-125:0\">Sicherheitsregeln sorgen f\u00fcr den Schutz der Daten<\/li>\n<\/ul>\n<h4 dir=\"auto\" data-sourcepos=\"126:1-126:38\"><a id=\"user-content-521-supabase-projekt-einrichten\" class=\"anchor\" href=\"#521-supabase-projekt-einrichten\" aria-hidden=\"true\"><\/a>5.2.1 Supabase-Projekt einrichten<\/h4>\n<ol dir=\"auto\" data-sourcepos=\"128:1-132:0\">\n<li data-sourcepos=\"128:1-128:60\">Melde dich bei Supabase an und erstelle ein neues Projekt<\/li>\n<li data-sourcepos=\"129:1-129:73\">Notiere dir die API-URL und den API-Key unter <code data-sourcepos=\"129:51-129:72\">Project Settings &gt; API<\/code><\/li>\n<li data-sourcepos=\"130:1-130:66\">Aktiviere Email Auth unter <code data-sourcepos=\"130:32-130:65\">Authentication &gt; Providers &gt; Email<\/code><\/li>\n<li data-sourcepos=\"131:1-132:0\">Erstelle die Datenbanktabelle f\u00fcr Todos im SQL-Editor:<\/li>\n<\/ol>\n<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre id=\"code-106\" class=\"code highlight js-syntax-highlight language-sql dark\" data-canonical-lang=\"sql\" data-sourcepos=\"133:1-141:3\"><code><span id=\"LC1\" class=\"line\" lang=\"sql\"><span class=\"k\">create<\/span> <span class=\"k\">table<\/span> <span class=\"n\">todos<\/span> <span class=\"p\">(<\/span><\/span>\r\n<span id=\"LC2\" class=\"line\" lang=\"sql\">    <span class=\"n\">id<\/span> <span class=\"nb\">serial<\/span> <span class=\"k\">primary<\/span> <span class=\"k\">key<\/span><span class=\"p\">,<\/span><\/span>\r\n<span id=\"LC3\" class=\"line\" lang=\"sql\">    <span class=\"n\">user_id<\/span> <span class=\"n\">uuid<\/span> <span class=\"k\">references<\/span> <span class=\"n\">auth<\/span><span class=\"p\">.<\/span><span class=\"n\">users<\/span><span class=\"p\">(<\/span><span class=\"n\">id<\/span><span class=\"p\">)<\/span> <span class=\"k\">default<\/span> <span class=\"n\">auth<\/span><span class=\"p\">.<\/span><span class=\"n\">uid<\/span><span class=\"p\">(),<\/span><\/span>\r\n<span id=\"LC4\" class=\"line\" lang=\"sql\">    <span class=\"n\">title<\/span> <span class=\"nb\">text<\/span> <span class=\"k\">not<\/span> <span class=\"k\">null<\/span><span class=\"p\">,<\/span><\/span>\r\n<span id=\"LC5\" class=\"line\" lang=\"sql\">    <span class=\"n\">completed<\/span> <span class=\"nb\">boolean<\/span> <span class=\"k\">default<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span><\/span>\r\n<span id=\"LC6\" class=\"line\" lang=\"sql\">    <span class=\"n\">created_at<\/span> <span class=\"nb\">timestamp<\/span> <span class=\"k\">default<\/span> <span class=\"n\">now<\/span><span class=\"p\">()<\/span><\/span>\r\n<span id=\"LC7\" class=\"line\" lang=\"sql\"><span class=\"p\">);<\/span><\/span><\/code><\/pre>\n<\/div>\n<ol dir=\"auto\" start=\"5\" data-sourcepos=\"143:1-144:0\">\n<li data-sourcepos=\"143:1-144:0\">Setze die Sicherheitsregel f\u00fcr die Tabelle:<\/li>\n<\/ol>\n<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre id=\"code-107\" class=\"code highlight js-syntax-highlight language-sql dark\" data-canonical-lang=\"sql\" data-sourcepos=\"145:1-151:3\"><code><span id=\"LC1\" class=\"line\" lang=\"sql\"><span class=\"k\">create<\/span> <span class=\"n\">policy<\/span> <span class=\"nv\">\"Todos sind privat\"<\/span><\/span>\r\n<span id=\"LC2\" class=\"line\" lang=\"sql\"><span class=\"k\">on<\/span> <span class=\"n\">todos<\/span><\/span>\r\n<span id=\"LC3\" class=\"line\" lang=\"sql\"><span class=\"k\">for<\/span> <span class=\"k\">all<\/span><\/span>\r\n<span id=\"LC4\" class=\"line\" lang=\"sql\"><span class=\"k\">using<\/span> <span class=\"p\">(<\/span><span class=\"n\">auth<\/span><span class=\"p\">.<\/span><span class=\"n\">uid<\/span><span class=\"p\">()<\/span> <span class=\"o\">=<\/span> <span class=\"n\">user_id<\/span><span class=\"p\">)<\/span><\/span>\r\n<span id=\"LC5\" class=\"line\" lang=\"sql\"><span class=\"k\">with<\/span> <span class=\"k\">check<\/span> <span class=\"p\">(<\/span><span class=\"n\">auth<\/span><span class=\"p\">.<\/span><span class=\"n\">uid<\/span><span class=\"p\">()<\/span> <span class=\"o\">=<\/span> <span class=\"n\">user_id<\/span><span class=\"p\">);<\/span><\/span><\/code><\/pre>\n<\/div>\n<p dir=\"auto\" data-sourcepos=\"153:1-153:91\">Diese Regel stellt sicher, dass Nutzer nur ihre eigenen Todos sehen und bearbeiten k\u00f6nnen.<\/p>\n<ol dir=\"auto\" start=\"6\" data-sourcepos=\"155:1-156:0\">\n<li data-sourcepos=\"155:1-156:0\">Aktiviere die Row-Level-Security f\u00fcr die Tabelle:<\/li>\n<\/ol>\n<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre id=\"code-108\" class=\"code highlight js-syntax-highlight language-sql dark\" data-canonical-lang=\"sql\" data-sourcepos=\"157:1-159:3\"><code><span id=\"LC1\" class=\"line\" lang=\"sql\"><span class=\"k\">alter<\/span> <span class=\"k\">table<\/span> <span class=\"n\">todos<\/span> <span class=\"n\">enable<\/span> <span class=\"k\">row<\/span> <span class=\"k\">level<\/span> <span class=\"k\">security<\/span><span class=\"p\">;<\/span><\/span><\/code><\/pre>\n<\/div>\n<p dir=\"auto\" data-sourcepos=\"161:1-161:50\">Nun ist die Regel aktiv und die Tabelle gesichert.<\/p>\n<h4 dir=\"auto\" data-sourcepos=\"163:1-163:35\"><a id=\"user-content-522-frontend-implementierung\" class=\"anchor\" href=\"#522-frontend-implementierung\" aria-hidden=\"true\"><\/a>5.2.2 Frontend Implementierung<\/h4>\n<p dir=\"auto\" data-sourcepos=\"165:1-165:124\">F\u00fcr jede Tabelle stellt Supabase automatisch eine REST-API bereit, welche die Datenbankoperationen erm\u00f6glicht (vgl. [12]).<\/p>\n<p dir=\"auto\" data-sourcepos=\"167:1-168:141\">Es steht eine Vielzahl an SDKs zur Verf\u00fcgung, um alle g\u00e4ngigen Programmiersprachen und Plattformen f\u00fcr REST Anfragen an Supabase zu unterst\u00fctzen. In diesem Beispiel verwenden wir die offizielle Supabase JavaScript SDK, um die Authentifizierung und Datenbankoperationen zu implementieren.<\/p>\n<h4 dir=\"auto\" data-sourcepos=\"170:1-170:37\"><a id=\"user-content-523-supabase-client-einrichten\" class=\"anchor\" href=\"#523-supabase-client-einrichten\" aria-hidden=\"true\"><\/a>5.2.3 Supabase Client einrichten<\/h4>\n<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre id=\"code-109\" class=\"code highlight js-syntax-highlight language-html dark\" data-canonical-lang=\"html\" data-sourcepos=\"172:1-181:3\"><code><span id=\"LC1\" class=\"line\" lang=\"html\"><span class=\"nt\">&lt;script <\/span><span class=\"na\">src=<\/span><span class=\"s\">\"https:\/\/cdn.jsdelivr.net\/npm\/@supabase\/supabase-js@2\"<\/span><span class=\"nt\">&gt;&lt;\/script&gt;<\/span><\/span>\r\n<span id=\"LC2\" class=\"line\" lang=\"html\"><span class=\"nt\">&lt;script&gt;<\/span><\/span>\r\n<span id=\"LC3\" class=\"line\" lang=\"html\">  <span class=\"kd\">const<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">createClient<\/span> <span class=\"p\">}<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">supabase<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC4\" class=\"line\" lang=\"html\">  <span class=\"kd\">const<\/span> <span class=\"nx\">supabaseClient<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">createClient<\/span><span class=\"p\">(<\/span><\/span>\r\n<span id=\"LC5\" class=\"line\" lang=\"html\">    <span class=\"dl\">\"<\/span><span class=\"s2\">YOUR_SUPABASE_URL<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span><\/span>\r\n<span id=\"LC6\" class=\"line\" lang=\"html\">    <span class=\"dl\">\"<\/span><span class=\"s2\">YOUR_SUPABASE_ANON_KEY<\/span><span class=\"dl\">\"<\/span><\/span>\r\n<span id=\"LC7\" class=\"line\" lang=\"html\">  <span class=\"p\">);<\/span><\/span>\r\n<span id=\"LC8\" class=\"line\" lang=\"html\"><span class=\"nt\">&lt;\/script&gt;<\/span><\/span><\/code><\/pre>\n<\/div>\n<h4 dir=\"auto\" data-sourcepos=\"183:1-183:24\"><a id=\"user-content-524-html-struktur\" class=\"anchor\" href=\"#524-html-struktur\" aria-hidden=\"true\"><\/a>5.2.4 HTML-Struktur<\/h4>\n<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre id=\"code-110\" class=\"code highlight js-syntax-highlight language-html dark\" data-canonical-lang=\"html\" data-sourcepos=\"185:1-206:3\"><code><span id=\"LC1\" class=\"line\" lang=\"html\"><span class=\"c\">&lt;!-- Login Formular --&gt;<\/span><\/span>\r\n<span id=\"LC2\" class=\"line\" lang=\"html\"><span class=\"nt\">&lt;form<\/span> <span class=\"na\">id=<\/span><span class=\"s\">\"sign-in-form\"<\/span> <span class=\"na\">class=<\/span><span class=\"s\">\"auth-form\"<\/span><span class=\"nt\">&gt;<\/span><\/span>\r\n<span id=\"LC3\" class=\"line\" lang=\"html\">  <span class=\"nt\">&lt;h2&gt;<\/span>Anmelden<span class=\"nt\">&lt;\/h2&gt;<\/span><\/span>\r\n<span id=\"LC4\" class=\"line\" lang=\"html\">  <span class=\"nt\">&lt;input<\/span> <span class=\"na\">type=<\/span><span class=\"s\">\"email\"<\/span> <span class=\"na\">id=<\/span><span class=\"s\">\"login-email\"<\/span> <span class=\"na\">placeholder=<\/span><span class=\"s\">\"E-Mail\"<\/span> <span class=\"na\">required<\/span> <span class=\"nt\">\/&gt;<\/span><\/span>\r\n<span id=\"LC5\" class=\"line\" lang=\"html\">  <span class=\"nt\">&lt;input<\/span> <span class=\"na\">type=<\/span><span class=\"s\">\"password\"<\/span> <span class=\"na\">id=<\/span><span class=\"s\">\"login-password\"<\/span> <span class=\"na\">placeholder=<\/span><span class=\"s\">\"Passwort\"<\/span> <span class=\"na\">required<\/span> <span class=\"nt\">\/&gt;<\/span><\/span>\r\n<span id=\"LC6\" class=\"line\" lang=\"html\">  <span class=\"nt\">&lt;button<\/span> <span class=\"na\">type=<\/span><span class=\"s\">\"submit\"<\/span><span class=\"nt\">&gt;<\/span>Anmelden<span class=\"nt\">&lt;\/button&gt;<\/span><\/span>\r\n<span id=\"LC7\" class=\"line\" lang=\"html\"><span class=\"nt\">&lt;\/form&gt;<\/span><\/span>\r\n<span id=\"LC8\" class=\"line\" lang=\"html\"><\/span>\r\n<span id=\"LC9\" class=\"line\" lang=\"html\"><span class=\"c\">&lt;!-- Todo App --&gt;<\/span><\/span>\r\n<span id=\"LC10\" class=\"line\" lang=\"html\"><span class=\"nt\">&lt;div<\/span> <span class=\"na\">id=<\/span><span class=\"s\">\"todo-app\"<\/span> <span class=\"na\">style=<\/span><span class=\"s\">\"display: none\"<\/span><span class=\"nt\">&gt;<\/span><\/span>\r\n<span id=\"LC11\" class=\"line\" lang=\"html\">  <span class=\"nt\">&lt;div<\/span> <span class=\"na\">class=<\/span><span class=\"s\">\"user-header\"<\/span><span class=\"nt\">&gt;<\/span><\/span>\r\n<span id=\"LC12\" class=\"line\" lang=\"html\">    <span class=\"nt\">&lt;span<\/span> <span class=\"na\">id=<\/span><span class=\"s\">\"user-email\"<\/span><span class=\"nt\">&gt;&lt;\/span&gt;<\/span><\/span>\r\n<span id=\"LC13\" class=\"line\" lang=\"html\">    <span class=\"nt\">&lt;button<\/span> <span class=\"na\">id=<\/span><span class=\"s\">\"logout-button\"<\/span><span class=\"nt\">&gt;<\/span>Abmelden<span class=\"nt\">&lt;\/button&gt;<\/span><\/span>\r\n<span id=\"LC14\" class=\"line\" lang=\"html\">  <span class=\"nt\">&lt;\/div&gt;<\/span><\/span>\r\n<span id=\"LC15\" class=\"line\" lang=\"html\">  <span class=\"nt\">&lt;form<\/span> <span class=\"na\">id=<\/span><span class=\"s\">\"todo-form\"<\/span><span class=\"nt\">&gt;<\/span><\/span>\r\n<span id=\"LC16\" class=\"line\" lang=\"html\">    <span class=\"nt\">&lt;input<\/span> <span class=\"na\">type=<\/span><span class=\"s\">\"text\"<\/span> <span class=\"na\">id=<\/span><span class=\"s\">\"todo-input\"<\/span> <span class=\"na\">placeholder=<\/span><span class=\"s\">\"Neue Aufgabe...\"<\/span> <span class=\"na\">required<\/span> <span class=\"nt\">\/&gt;<\/span><\/span>\r\n<span id=\"LC17\" class=\"line\" lang=\"html\">    <span class=\"nt\">&lt;button<\/span> <span class=\"na\">type=<\/span><span class=\"s\">\"submit\"<\/span><span class=\"nt\">&gt;<\/span>Hinzuf\u00fcgen<span class=\"nt\">&lt;\/button&gt;<\/span><\/span>\r\n<span id=\"LC18\" class=\"line\" lang=\"html\">  <span class=\"nt\">&lt;\/form&gt;<\/span><\/span>\r\n<span id=\"LC19\" class=\"line\" lang=\"html\">  <span class=\"nt\">&lt;ul<\/span> <span class=\"na\">id=<\/span><span class=\"s\">\"todo-list\"<\/span><span class=\"nt\">&gt;&lt;\/ul&gt;<\/span><\/span>\r\n<span id=\"LC20\" class=\"line\" lang=\"html\"><span class=\"nt\">&lt;\/div&gt;<\/span><\/span><\/code><\/pre>\n<\/div>\n<h4 dir=\"auto\" data-sourcepos=\"208:1-208:41\"><a id=\"user-content-525-hauptfunktionen-implementieren\" class=\"anchor\" href=\"#525-hauptfunktionen-implementieren\" aria-hidden=\"true\"><\/a>5.2.5 Hauptfunktionen implementieren<\/h4>\n<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre id=\"code-111\" class=\"code highlight js-syntax-highlight language-javascript dark\" data-canonical-lang=\"js\" data-sourcepos=\"210:1-271:3\"><code><span id=\"LC1\" class=\"line\" lang=\"javascript\"><span class=\"c1\">\/\/ Login<\/span><\/span>\r\n<span id=\"LC2\" class=\"line\" lang=\"javascript\"><span class=\"nb\">document<\/span><\/span>\r\n<span id=\"LC3\" class=\"line\" lang=\"javascript\">  <span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">sign-in-form<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span><\/span>\r\n<span id=\"LC4\" class=\"line\" lang=\"javascript\">  <span class=\"p\">.<\/span><span class=\"nf\">addEventListener<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">submit<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"k\">async <\/span><span class=\"p\">(<\/span><span class=\"nx\">e<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span><\/span>\r\n<span id=\"LC5\" class=\"line\" lang=\"javascript\">    <span class=\"nx\">e<\/span><span class=\"p\">.<\/span><span class=\"nf\">preventDefault<\/span><span class=\"p\">();<\/span><\/span>\r\n<span id=\"LC6\" class=\"line\" lang=\"javascript\">    <span class=\"kd\">const<\/span> <span class=\"nx\">email<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">login-email<\/span><span class=\"dl\">\"<\/span><span class=\"p\">).<\/span><span class=\"nx\">value<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC7\" class=\"line\" lang=\"javascript\">    <span class=\"kd\">const<\/span> <span class=\"nx\">password<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">login-password<\/span><span class=\"dl\">\"<\/span><span class=\"p\">).<\/span><span class=\"nx\">value<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC9\" class=\"line\" lang=\"javascript\">    <span class=\"k\">try<\/span> <span class=\"p\">{<\/span><\/span>\r\n<span id=\"LC10\" class=\"line\" lang=\"javascript\">      <span class=\"kd\">const<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">data<\/span><span class=\"p\">,<\/span> <span class=\"nx\">error<\/span> <span class=\"p\">}<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">supabaseClient<\/span><span class=\"p\">.<\/span><span class=\"nx\">auth<\/span><span class=\"p\">.<\/span><span class=\"nf\">signInWithPassword<\/span><span class=\"p\">({<\/span><\/span>\r\n<span id=\"LC11\" class=\"line\" lang=\"javascript\">        <span class=\"nx\">email<\/span><span class=\"p\">,<\/span><\/span>\r\n<span id=\"LC12\" class=\"line\" lang=\"javascript\">        <span class=\"nx\">password<\/span><span class=\"p\">,<\/span><\/span>\r\n<span id=\"LC13\" class=\"line\" lang=\"javascript\">      <span class=\"p\">});<\/span><\/span>\r\n<span id=\"LC14\" class=\"line\" lang=\"javascript\">      <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">)<\/span> <span class=\"k\">throw<\/span> <span class=\"nx\">error<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC15\" class=\"line\" lang=\"javascript\">    <span class=\"p\">}<\/span> <span class=\"k\">catch <\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span><\/span>\r\n<span id=\"LC16\" class=\"line\" lang=\"javascript\">      <span class=\"nf\">alert<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">Login error: <\/span><span class=\"dl\">\"<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">error<\/span><span class=\"p\">.<\/span><span class=\"nx\">message<\/span><span class=\"p\">);<\/span><\/span>\r\n<span id=\"LC17\" class=\"line\" lang=\"javascript\">    <span class=\"p\">}<\/span><\/span>\r\n<span id=\"LC18\" class=\"line\" lang=\"javascript\">  <span class=\"p\">});<\/span><\/span>\r\n<span id=\"LC20\" class=\"line\" lang=\"javascript\"><span class=\"c1\">\/\/ Todos laden<\/span><\/span>\r\n<span id=\"LC21\" class=\"line\" lang=\"javascript\"><span class=\"k\">async<\/span> <span class=\"kd\">function<\/span> <span class=\"nf\">loadTodos<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span><\/span>\r\n<span id=\"LC22\" class=\"line\" lang=\"javascript\">  <span class=\"kd\">const<\/span> <span class=\"p\">{<\/span> <span class=\"na\">data<\/span><span class=\"p\">:<\/span> <span class=\"nx\">todos<\/span><span class=\"p\">,<\/span> <span class=\"nx\">error<\/span> <span class=\"p\">}<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">supabaseClient<\/span><\/span>\r\n<span id=\"LC23\" class=\"line\" lang=\"javascript\">    <span class=\"p\">.<\/span><span class=\"k\">from<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">todos<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span><\/span>\r\n<span id=\"LC24\" class=\"line\" lang=\"javascript\">    <span class=\"p\">.<\/span><span class=\"nf\">select<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">*<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span><\/span>\r\n<span id=\"LC25\" class=\"line\" lang=\"javascript\">    <span class=\"p\">.<\/span><span class=\"nf\">order<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">created_at<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"na\">ascending<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span> <span class=\"p\">});<\/span><\/span>\r\n<span id=\"LC27\" class=\"line\" lang=\"javascript\">  <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">)<\/span> <span class=\"k\">throw<\/span> <span class=\"nx\">error<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC29\" class=\"line\" lang=\"javascript\">  <span class=\"kd\">const<\/span> <span class=\"nx\">todoList<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">todo-list<\/span><span class=\"dl\">\"<\/span><span class=\"p\">);<\/span><\/span>\r\n<span id=\"LC30\" class=\"line\" lang=\"javascript\">  <span class=\"nx\">todoList<\/span><span class=\"p\">.<\/span><span class=\"nx\">innerHTML<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">\"\"<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC32\" class=\"line\" lang=\"javascript\">  <span class=\"nx\">todos<\/span><span class=\"p\">.<\/span><span class=\"nf\">forEach<\/span><span class=\"p\">((<\/span><span class=\"nx\">todo<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span><\/span>\r\n<span id=\"LC33\" class=\"line\" lang=\"javascript\">    <span class=\"kd\">const<\/span> <span class=\"nx\">li<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">createElement<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">li<\/span><span class=\"dl\">\"<\/span><span class=\"p\">);<\/span><\/span>\r\n<span id=\"LC34\" class=\"line\" lang=\"javascript\">    <span class=\"nx\">li<\/span><span class=\"p\">.<\/span><span class=\"nx\">innerHTML<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">`<\/span><\/span>\r\n<span id=\"LC35\" class=\"line\" lang=\"javascript\"><span class=\"s2\">      &lt;input type=\"checkbox\" <\/span><span class=\"p\">${<\/span><span class=\"nx\">todo<\/span><span class=\"p\">.<\/span><span class=\"nx\">completed<\/span> <span class=\"p\">?<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">checked<\/span><span class=\"dl\">\"<\/span> <span class=\"p\">:<\/span> <span class=\"dl\">\"\"<\/span><span class=\"p\">}<\/span> <\/span>\r\n<span id=\"LC36\" class=\"line\" lang=\"javascript\"><span class=\"s2\">          onchange=\"toggleTodo(<\/span><span class=\"p\">${<\/span><span class=\"nx\">todo<\/span><span class=\"p\">.<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">, this.checked)\"&gt;<\/span><\/span>\r\n<span id=\"LC37\" class=\"line\" lang=\"javascript\"><span class=\"s2\">      &lt;span&gt;<\/span><span class=\"p\">${<\/span><span class=\"nx\">todo<\/span><span class=\"p\">.<\/span><span class=\"nx\">title<\/span><span class=\"p\">}<\/span><span class=\"s2\">&lt;\/span&gt;<\/span><\/span>\r\n<span id=\"LC38\" class=\"line\" lang=\"javascript\"><span class=\"s2\">      &lt;button onclick=\"deleteTodo(<\/span><span class=\"p\">${<\/span><span class=\"nx\">todo<\/span><span class=\"p\">.<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">)\"&gt;L\u00f6schen&lt;\/button&gt;<\/span><\/span>\r\n<span id=\"LC39\" class=\"line\" lang=\"javascript\"><span class=\"s2\">    `<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC40\" class=\"line\" lang=\"javascript\">    <span class=\"nx\">todoList<\/span><span class=\"p\">.<\/span><span class=\"nf\">appendChild<\/span><span class=\"p\">(<\/span><span class=\"nx\">li<\/span><span class=\"p\">);<\/span><\/span>\r\n<span id=\"LC41\" class=\"line\" lang=\"javascript\">  <span class=\"p\">});<\/span><\/span>\r\n<span id=\"LC42\" class=\"line\" lang=\"javascript\"><span class=\"p\">}<\/span><\/span>\r\n<span id=\"LC44\" class=\"line\" lang=\"javascript\"><span class=\"c1\">\/\/ Auth Status \u00fcberwachen<\/span><\/span>\r\n<span id=\"LC45\" class=\"line\" lang=\"javascript\"><span class=\"nx\">supabaseClient<\/span><span class=\"p\">.<\/span><span class=\"nx\">auth<\/span><span class=\"p\">.<\/span><span class=\"nf\">onAuthStateChange<\/span><span class=\"p\">((<\/span><span class=\"nx\">event<\/span><span class=\"p\">,<\/span> <span class=\"nx\">session<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span><\/span>\r\n<span id=\"LC46\" class=\"line\" lang=\"javascript\">  <span class=\"kd\">const<\/span> <span class=\"nx\">todoApp<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">todo-app<\/span><span class=\"dl\">\"<\/span><span class=\"p\">);<\/span><\/span>\r\n<span id=\"LC47\" class=\"line\" lang=\"javascript\">  <span class=\"kd\">const<\/span> <span class=\"nx\">loginForm<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">sign-in-form<\/span><span class=\"dl\">\"<\/span><span class=\"p\">);<\/span><\/span>\r\n<span id=\"LC48\" class=\"line\" lang=\"javascript\">  <span class=\"kd\">const<\/span> <span class=\"nx\">userEmail<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">user-email<\/span><span class=\"dl\">\"<\/span><span class=\"p\">);<\/span><\/span>\r\n<span id=\"LC50\" class=\"line\" lang=\"javascript\">  <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span><\/span>\r\n<span id=\"LC51\" class=\"line\" lang=\"javascript\">    <span class=\"nx\">loginForm<\/span><span class=\"p\">.<\/span><span class=\"nx\">style<\/span><span class=\"p\">.<\/span><span class=\"nx\">display<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">none<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC52\" class=\"line\" lang=\"javascript\">    <span class=\"nx\">todoApp<\/span><span class=\"p\">.<\/span><span class=\"nx\">style<\/span><span class=\"p\">.<\/span><span class=\"nx\">display<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">block<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC53\" class=\"line\" lang=\"javascript\">    <span class=\"nx\">userEmail<\/span><span class=\"p\">.<\/span><span class=\"nx\">textContent<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">user<\/span><span class=\"p\">.<\/span><span class=\"nx\">email<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC54\" class=\"line\" lang=\"javascript\">    <span class=\"nf\">loadTodos<\/span><span class=\"p\">();<\/span><\/span>\r\n<span id=\"LC55\" class=\"line\" lang=\"javascript\">  <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span><\/span>\r\n<span id=\"LC56\" class=\"line\" lang=\"javascript\">    <span class=\"nx\">loginForm<\/span><span class=\"p\">.<\/span><span class=\"nx\">style<\/span><span class=\"p\">.<\/span><span class=\"nx\">display<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">flex<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC57\" class=\"line\" lang=\"javascript\">    <span class=\"nx\">todoApp<\/span><span class=\"p\">.<\/span><span class=\"nx\">style<\/span><span class=\"p\">.<\/span><span class=\"nx\">display<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">none<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC58\" class=\"line\" lang=\"javascript\">    <span class=\"nx\">userEmail<\/span><span class=\"p\">.<\/span><span class=\"nx\">textContent<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">\"\"<\/span><span class=\"p\">;<\/span><\/span>\r\n<span id=\"LC59\" class=\"line\" lang=\"javascript\">  <span class=\"p\">}<\/span><\/span>\r\n<span id=\"LC60\" class=\"line\" lang=\"javascript\"><span class=\"p\">});<\/span><\/span><\/code><\/pre>\n<\/div>\n<h3 dir=\"auto\" data-sourcepos=\"273:1-273:23\"><a id=\"user-content-53-zusammenfassung\" class=\"anchor\" href=\"#53-zusammenfassung\" aria-hidden=\"true\"><\/a>5.3 Zusammenfassung<\/h3>\n<p dir=\"auto\" data-sourcepos=\"275:1-275:69\">Diese einfache Todo-App demonstriert die Kernfunktionen von Supabase:<\/p>\n<ul dir=\"auto\" data-sourcepos=\"277:1-281:0\">\n<li data-sourcepos=\"277:1-277:51\">Benutzerauthentifizierung mit E-Mail und Passwort<\/li>\n<li data-sourcepos=\"278:1-278:45\">Datenbankoperationen mit Row Level Security<\/li>\n<li data-sourcepos=\"279:1-279:46\">Einfache Integration in Frontend-Anwendungen<\/li>\n<li data-sourcepos=\"280:1-281:0\">Kein API-Layer notwendig<\/li>\n<\/ul>\n<p dir=\"auto\" data-sourcepos=\"282:1-282:268\">Die gehostete Variante von Supabase erm\u00f6glicht es uns, schnell eine funktionale Anwendung zu erstellen, ohne uns um die Infrastruktur k\u00fcmmern zu m\u00fcssen. Die Row Level Security stellt dabei sicher, dass jeder Nutzer nur seine eigenen Daten sehen und bearbeiten kann.<\/p>\n<h2 dir=\"auto\" data-sourcepos=\"284:1-284:12\"><a id=\"user-content-literatur\" class=\"anchor\" href=\"#literatur\" aria-hidden=\"true\"><\/a>Literatur<\/h2>\n<p dir=\"auto\" data-sourcepos=\"288:1-288:146\">[1] \u201eDatabase | open source sql database\u201c, Supabase. Zugegriffen: 25. November 2024. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/database\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/database<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"290:1-290:138\">[2] \u201eAuth | Built-in user management\u201c, Supabase. Zugegriffen: 25. November 2024. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/auth\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/auth<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"292:1-292:145\">[3] \u201eStorage | Store any digital content\u201c, Supabase. Zugegriffen: 25. November 2024. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/storage\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/storage<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"294:1-294:149\">[4] \u201eRealtime | Sync your data in real time\u201c, Supabase. Zugegriffen: 25. November 2024. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/realtime\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/realtime<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"296:1-296:174\">[5] Supabase, \u201eSelf-Hosting with Docker | Supabase Docs\u201c. Zugegriffen: 25. November 2024. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/docs\/guides\/self-hosting\/docker\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/docs\/guides\/self-hosting\/docker<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"298:1-298:135\">[6] Supabase, \u201eSelf-Hosting | Supabase Docs\u201c. Zugegriffen: 25. November 2024. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/docs\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/docs<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"300:1-300:124\">[7] \u201ePricing &amp; Fees\u201c, Supabase. Zugegriffen: 25. November 2024. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/pricing\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/pricing<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"302:1-302:150\">[8] \u201eSupabase | The Open Source Firebase Alternative\u201c, Supabase. Zugegriffen: 25. November 2024. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"304:1-304:168\">[9] CodeParrot. \u201eFirebase vs Supabase\u201c, DEV Community. Zugegriffen: 14. Januar 2025. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/dev.to\/codeparrot\/firebase-vs-supabase-4770\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/dev.to\/codeparrot\/firebase-vs-supabase-4770<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"306:1-306:139\">[10] \u201eFirebase Pricing\u201c, Google Firebase. Zugegriffen: 16. Januar 2025. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/firebase.google.com\/pricing\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/firebase.google.com\/pricing<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"308:1-308:157\">[11] \u201ePreise f\u00fcr AWS Amplify\u201c, Amazon Web Services. Zugegriffen: 16. Januar 2025. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/aws.amazon.com\/de\/amplify\/pricing\/\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/aws.amazon.com\/de\/amplify\/pricing\/<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"310:1-310:130\">[12] Supabase, \u201eREST API\u201c. Zugegriffen: 16. Januar 2025. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/docs\/guides\/api\/rest\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/docs\/guides\/api\/rest<\/a><\/p>\n<p dir=\"auto\" data-sourcepos=\"312:1-312:141\">[13] Supabase, \u201eJavaScript SDK\u201c. Zugegriffen: 16. Januar 2025. [Online]. Verf\u00fcgbar unter: <a href=\"https:\/\/supabase.com\/docs\/reference\/javascript\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">https:\/\/supabase.com\/docs\/reference\/javascript<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Supabase: Die Open-Source Firebase-Alternative 1. Allgemeines 2. Preisgestaltung 3. Funktionen und Features 3.1 Datenbank 3.2 Echtzeit-Funktionen 3.3 Authentifizierung 3.4 Analyse-Tools<\/p>\n","protected":false},"author":195,"featured_media":3798,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,3],"tags":[17,9,122,5,33,121],"class_list":["post-3797","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-betriebliche-informationssysteme","category-lehrveranstaltungen","tag-baas","tag-docker","tag-firebase","tag-informationssystem","tag-open-source","tag-supabase"],"_links":{"self":[{"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/posts\/3797","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/users\/195"}],"replies":[{"embeddable":true,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/comments?post=3797"}],"version-history":[{"count":1,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/posts\/3797\/revisions"}],"predecessor-version":[{"id":3806,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/posts\/3797\/revisions\/3806"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/media\/3798"}],"wp:attachment":[{"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/media?parent=3797"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/categories?post=3797"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/tags?post=3797"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}