TaskMonkey Handbuch

Supabase (eigene Datenbank)

Workspace-eigene Postgres-DB via Supabase als Backend.

Wenn dein Workspace eigene strukturierte Daten braucht — eigene Tabellen, Queries, Beziehungen — ist Supabase eine leichtgewichtige Variante: Postgres + auto-generierte REST-API, ohne eigenen Backend-Server.

Setup

  1. Du hast einen eigenen Supabase-Account (kostenlos für kleine Projekte).
  2. Im Manage-Bereich /manage/supabase: URL und Service-Key eintragen.
  3. Tabellen in Supabase anlegen (über deren Dashboard).
  4. Tools in deinem Workspace definieren, die diese Tabellen lesen / schreiben.

API-Definition

// apis.php
'supabase' => [
    'base_url' => 'https://xxx.supabase.co/rest/v1/',
    'headers' => [
        'apikey' => 'eyJhbGciOi…',
        'Authorization' => 'Bearer ' . 'eyJhbGciOi…',
        'Content-Type' => 'application/json',
        'Prefer' => 'return=representation',
    ],
],

Einfache Tools

'tools' => [
    'createLead' => [
        'description' => 'Lead in unserer Supabase-DB anlegen.',
        'parameters' => [
            'type' => 'object',
            'properties' => [
                'name' => ['type' => 'string'],
                'email' => ['type' => 'string'],
                'source' => ['type' => 'string'],
            ],
            'required' => ['name', 'email'],
        ],
        'api' => 'supabase',
        'method' => 'POST',
        'path' => 'leads',
        'body' => [
            'name' => '{name}',
            'email' => '{email}',
            'source' => '{source}',
        ],
        'mapping' => [
            'id' => '[0].id',
            'created' => '[0].created_at',
        ],
    ],

    'findLeads' => [
        'description' => 'Leads suchen nach E-Mail-Teilstring.',
        'parameters' => [
            'type' => 'object',
            'properties' => [
                'email' => ['type' => 'string'],
                'limit' => ['type' => 'integer'],
            ],
            'required' => ['email'],
        ],
        'api' => 'supabase',
        'method' => 'GET',
        'path' => 'leads?email=ilike.%25{email}%25&limit={limit}',
        'mapping' => [
            'results' => [
                'id' => 'id',
                'name' => 'name',
                'email' => 'email',
            ],
        ],
    ],
];

Supabase-Query-Syntax

PostgREST (Supabase) nutzt Query-Operatoren im URL-Parameter:

Operator Beispiel SQL
eq status=eq.active = 'active'
neq status=neq.archived != 'archived'
gt / gte created_at=gt.2026-01-01 > '2026-01-01'
lt / lte price=lte.100 <= 100
like / ilike email=ilike.%example% ILIKE '%example%'
in status=in.(active,pending) IN ('active','pending')
order order=created_at.desc ORDER BY created_at DESC
limit limit=10 LIMIT 10

Volle Referenz: postgrest.org/en/stable/api.html

Foreign-Key Joins

Supabase/PostgREST kann Beziehungen inline auflösen:

GET /orders?select=id,total,customer:customers(name,email)

Gibt Orders zurück mit verschachtelten Customer-Daten. In Tool-Form:

'getOrderWithCustomer' => [
    'api' => 'supabase',
    'method' => 'GET',
    'path' => 'orders?id=eq.{id}&select=id,total,status,customer:customers(name,email)',
    'mapping' => [
        'id' => '[0].id',
        'total' => '[0].total',
        'customer' => '[0].customer',
    ],
];

Browser-UI zum Durchsuchen

Im Manage-Bereich unter /manage/supabase gibt's einen vollwertigen Daten-Browser im Supabase-Stil. Was er kann:

Tabellen-Browser

  • Multi-Filter mit Operatoren: =, !=, >, >=, <, <=, like, ilike, in, is. Klick auf "Filter hinzufügen" → Spalte → Operator → Wert. Beliebig viele Filter, alle als AND verknüpft. Auch mehrere Filter auf dieselbe Spalte möglich (z.B. created_at >= 2026-01-01 AND created_at < 2026-06-01).
  • Multi-Sort: Klick auf Spaltenkopf sortiert. Shift+Klick fügt eine weitere Sortierspalte hinzu (Priorität wird am Header angezeigt).
  • Inline-Edit: Doppelklick auf Zelle, ändern, Enter zum Speichern.
  • FK-Navigation: Klick auf eine UUID-Spalte (z.B. customer_id) springt zur referenzierten Tabelle.
  • Combobox-Suggestions: Bei Spalten mit endlichen Werten (Enums, Status) zeigt der Editor existierende Werte als Vorschlag.

Group + Aggregation

Klick auf "Group" oben rechts schaltet den Aggregationsmodus ein. Dann:

  • Group by eine oder mehrere Spalten
  • Aggregation hinzufügen (count, sum, avg, min, max) über beliebige Spalte
  • "Ausführen" rendert die Gruppenresultate als Tabelle

Das ist echtes Postgres GROUP BY, kein Client-Side-Aggregat — funktioniert auch bei Tabellen mit Millionen Zeilen. Die aktiven Filter werden in die WHERE-Klausel übernommen.

SQL Editor

Klick auf "SQL Editor" in der Sidebar öffnet einen Monaco-Editor mit Postgres-SQL-Syntax-Highlighting. Was er kann:

  • Beliebige SELECT-Queries mit ergebnisbasierter Tabellen-Anzeige
  • Writes (INSERT, UPDATE, DELETE, CREATE TABLE etc.) — vor dem Senden warnt eine gelbe Banderole
  • Dry-Run: Bei Writes wrappt das System das Statement in BEGIN ... ROLLBACK, sodass die Daten unverändert bleiben — perfekt um Auswirkungen zu prüfen
  • Snippets: SQL-Statements als Browser-lokale Bookmarks speichern (per Tenant)
  • Shortcuts: Ctrl/Cmd + Enter führt aus

Voraussetzung für den SQL Editor: exec_sql-Funktion muss in der Tenant-Supabase existieren (siehe Abschnitt "Schema-Änderungen via Tool" weiter unten).

Saved Views

Aktueller Tabellen-Browser-Zustand (Tabelle + Filter + Sort) als wiederverwendbare View speichern:

  • "Speichern" oben rechts → Name eingeben → "Mit allen teilen?" (OK = shared, Abbrechen = privat)
  • Views erscheinen in der Sidebar unter "Saved Views" — Klick lädt sie
  • Eigene Views löschbar (Trash-Icon)
  • Fremde shared Views kopierbar (Copy-Icon) — werden als neue private View angelegt
  • Persistiert in der Tabelle taskmonkey_views (wird beim ersten Zugriff automatisch im Tenant-Supabase angelegt)

Multi-Tenant-Setup

Der Browser ist generisch und funktioniert für jeden Tenant, der apis.supabase in seiner apis.php konfiguriert hat. Pflichtfelder:

'apis' => [
    'supabase' => [
        'url' => 'https://your-project.supabase.co',
        'anon_key' => 'eyJhbG…',
        'service_role_key' => 'eyJhbG…', // nötig für Writes und SQL Editor
        'timeout' => 15, // optional
    ],
],

Optional: SQL Editor + Saved Views brauchen exec_sql (siehe unten).

Row-Level Security (RLS)

Supabase bietet RLS — pro-Zeile Zugriffsrechte. Entscheide:

  • RLS an + Service-Role-Key: TaskMonkey umgeht RLS (bequem, aber alle Zeilen sichtbar)
  • RLS an + User-Key: TaskMonkey respektiert RLS (komplexer, aber sicherer bei Multi-User-Szenarien)

Für rein interne Workspace-Automation reicht meist Variante 1. Für kundenorientierte Daten (mehrere Kunden teilen sich die DB) ist Variante 2 Pflicht.

Backup / Migration

Supabase macht automatische Daily-Backups (im Plan inkl.). Schema-Änderungen solltest du als SQL-Migrations versionieren, z. B. in deinem Workspace unter sql/ committen.

Schema-Änderungen via Tool (execSupabaseSql)

PostgREST (das HTTP-Frontend von Supabase) kann kein DDL — also kein ALTER TABLE, CREATE VIEW, CREATE INDEX. Trotzdem soll man von TaskMonkey aus Schema-Änderungen anstoßen können (Migrationen, neue Views, Bulk-Updates), ohne sich jedes Mal manuell ins Supabase SQL Editor einzuloggen.

Lösung: eine SECURITY-DEFINER-Function exec_sql(text) in der DB anlegen, die beliebiges SQL ausführt. Die ist nur für service_role aufrufbar, kein anon-User kommt da ran. Das Tool execSupabaseSql ruft diese Function über HTTP-RPC auf.

Einmal pro Supabase-Projekt, im SQL Editor ausführen:

CREATE OR REPLACE FUNCTION exec_sql(statement text)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
  EXECUTE statement;
  RETURN jsonb_build_object('ok', true);
EXCEPTION WHEN OTHERS THEN
  RETURN jsonb_build_object('ok', false, 'error', SQLERRM, 'sqlstate', SQLSTATE);
END;
$$;

REVOKE EXECUTE ON FUNCTION exec_sql(text) FROM PUBLIC, anon, authenticated;
GRANT EXECUTE ON FUNCTION exec_sql(text) TO service_role;

Danach kann der Workspace-Assistent (oder du via CLI) Migrationen ausführen:

tm test-tool execSupabaseSql statements='[
  "ALTER TABLE leads ADD COLUMN IF NOT EXISTS enriched_at TIMESTAMPTZ",
  "CREATE INDEX IF NOT EXISTS idx_leads_enriched_at ON leads(enriched_at)"
]'

Konventionen:

  • Immer idempotent (IF NOT EXISTS, CREATE OR REPLACE)
  • Ein Statement pro Schritt — der Tool-Output meldet pro Statement Erfolg/Fehler einzeln
  • DDL zuerst, danach Backfill-UPDATE als eigenes Statement

Was nicht geht: Multi-Statement-Transactions, Session-Settings, Statements > 30 s Laufzeit (PostgREST-Timeout). Für solche Fälle lieber direkt im Supabase SQL Editor.

Mehr Details siehe docs/supabase-migrations.md.

Debug

tm test-tool findLeads email=test
tm logs   # bei 400 → wahrscheinlich Syntax-Fehler in der Query

Supabase gibt bei Syntax-Fehlern sehr präzise Fehlermeldungen — lies sie genau.

Zuletzt aktualisiert: 2026-04-19