feat(chat): integrate chat project into monorepo with full app structure

- Restructure chat as apps/mobile, apps/web, apps/landing, backend
- Add NestJS backend for secure Azure OpenAI API calls
- Remove exposed API key from mobile app (security fix)
- Add shared chat-types package
- Create SvelteKit web app scaffold
- Create Astro landing page scaffold
- Update pnpm workspace configuration
- Add project-level CLAUDE.md documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Till-JS 2025-11-25 13:48:24 +01:00
parent fcf3a344b1
commit c638a7ffee
155 changed files with 22622 additions and 348 deletions

View file

@ -0,0 +1,33 @@
-- SQL-Skript zum Hinzufügen der Archivfunktionalität
-- Fügt ein 'is_archived' Feld zur 'conversations' Tabelle hinzu
-- Prüfen, ob die Spalte existiert und füge sie hinzu, falls nicht
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'conversations'
AND column_name = 'is_archived'
) THEN
ALTER TABLE public.conversations
ADD COLUMN is_archived BOOLEAN DEFAULT false;
RAISE NOTICE 'Spalte is_archived zur conversations-Tabelle hinzugefügt.';
ELSE
RAISE NOTICE 'Spalte is_archived existiert bereits in der conversations-Tabelle.';
END IF;
END
$$;
-- Kommentar für die neue Spalte hinzufügen
COMMENT ON COLUMN conversations.is_archived IS 'Gibt an, ob die Konversation archiviert wurde.';
-- Index für schnellere Abfragen, da wir oft nach archivierten/nicht-archivierten Konversationen filtern werden
CREATE INDEX IF NOT EXISTS idx_conversations_is_archived ON conversations(is_archived);
-- Indices für die Kombination aus Benutzer-ID und Archivierungsstatus für optimierte Abfragen
CREATE INDEX IF NOT EXISTS idx_conversations_user_archived ON conversations(user_id, is_archived);
-- Stelle sicher, dass die RLS-Policies aktualisiert werden, um die neue Spalte zu berücksichtigen
ALTER TABLE conversations ENABLE ROW LEVEL SECURITY;

View file

@ -0,0 +1,19 @@
-- SQL zum Hinzufügen der Titel-Spalte zur Conversations-Tabelle
-- SCHRITT 1: Spalte zur Tabelle hinzufügen
ALTER TABLE conversations
ADD COLUMN IF NOT EXISTS title TEXT;
-- SCHRITT 2: Kommentar für Dokumentation hinzufügen
COMMENT ON COLUMN conversations.title IS 'KI-generierter Titel für die Konversation';
-- SCHRITT 3: Aktualisiere RLS-Policy (Row Level Security) für die neue Spalte
-- (Stelle sicher, dass Benutzer nur ihre eigenen Konversationen lesen/bearbeiten können)
DROP POLICY IF EXISTS "Users can update their own conversations" ON conversations;
CREATE POLICY "Users can update their own conversations"
ON conversations
FOR UPDATE USING (user_id = auth.uid());
-- SCHRITT 4: (Optional) Standardwerte für bestehende Konversationen setzen
UPDATE conversations
SET title = 'Frühere Konversation'
WHERE title IS NULL;

View file

@ -0,0 +1,84 @@
-- Überprüfe und erstelle Modelle in der Datenbank
-- 1. Überprüfe, ob die models-Tabelle existiert
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'models'
) THEN
-- Erstelle die models-Tabelle
CREATE TABLE public.models (
id UUID PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
parameters JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Erstelle einen Trigger für updated_at
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $func$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$func$ LANGUAGE plpgsql;
CREATE TRIGGER set_models_updated_at
BEFORE UPDATE ON public.models
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
RAISE NOTICE 'Tabelle models wurde erstellt.';
ELSE
RAISE NOTICE 'Tabelle models existiert bereits.';
END IF;
END
$$;
-- 2. Überprüfe die Struktur der models-Tabelle und füge updated_at hinzu, falls es fehlt
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'models'
AND column_name = 'updated_at'
) THEN
ALTER TABLE public.models ADD COLUMN updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW();
RAISE NOTICE 'Spalte updated_at zur models-Tabelle hinzugefügt.';
ELSE
RAISE NOTICE 'Spalte updated_at existiert bereits in der models-Tabelle.';
END IF;
END
$$;
-- 3. Füge Standard-Modelle ein
INSERT INTO public.models (id, name, description, parameters)
VALUES
('550e8400-e29b-41d4-a716-446655440000', 'GPT-O3-Mini', 'Azure OpenAI GPT-O3-Mini', '{"temperature": 0.7, "max_tokens": 800}'),
('550e8400-e29b-41d4-a716-446655440001', 'GPT-4', 'OpenAI GPT-4', '{"temperature": 0.7, "max_tokens": 1000}'),
('550e8400-e29b-41d4-a716-446655440002', 'GPT-3.5-Turbo', 'OpenAI GPT-3.5 Turbo', '{"temperature": 0.7, "max_tokens": 800}'),
('550e8400-e29b-41d4-a716-446655440003', 'Claude 3', 'Anthropic Claude 3', '{"temperature": 0.7, "max_tokens": 1000}')
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
description = EXCLUDED.description,
parameters = EXCLUDED.parameters;
-- 4. Aktiviere RLS für die models-Tabelle
ALTER TABLE public.models ENABLE ROW LEVEL SECURITY;
-- 5. Erstelle eine Richtlinie für das Lesen von Modellen
-- Alle authentifizierten Benutzer dürfen Modelle sehen
DROP POLICY IF EXISTS models_select_policy ON models;
CREATE POLICY models_select_policy
ON models
FOR SELECT
TO authenticated
USING (true);
-- 6. Überprüfe, ob die Modelle existieren
SELECT id, name, description FROM public.models;

View file

@ -0,0 +1,66 @@
-- Skript zur Überprüfung und Konfiguration der Azure OpenAI-Einstellungen in der Datenbank
-- 1. Erstelle eine Tabelle für die Anwendungseinstellungen, falls sie noch nicht existiert
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'app_settings'
) THEN
CREATE TABLE public.app_settings (
id SERIAL PRIMARY KEY,
key TEXT NOT NULL UNIQUE,
value TEXT,
description TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Erstelle einen Trigger für updated_at
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $func$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$func$ LANGUAGE plpgsql;
CREATE TRIGGER set_app_settings_updated_at
BEFORE UPDATE ON public.app_settings
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
RAISE NOTICE 'Tabelle app_settings wurde erstellt.';
ELSE
RAISE NOTICE 'Tabelle app_settings existiert bereits.';
END IF;
END
$$;
-- 2. Füge Azure OpenAI-Einstellungen hinzu oder aktualisiere sie
INSERT INTO public.app_settings (key, value, description)
VALUES
('AZURE_OPENAI_ENDPOINT', 'https://memoroseopenai.openai.azure.com', 'Azure OpenAI API Endpoint'),
('AZURE_OPENAI_DEPLOYMENT', 'gpt-o3-mini-se', 'Azure OpenAI Deployment Name'),
('AZURE_OPENAI_API_VERSION', '2024-12-01-preview', 'Azure OpenAI API Version'),
('AZURE_OPENAI_API_KEY', '3082103c9b0d4270a795686ccaa89921', 'Azure OpenAI API Key')
ON CONFLICT (key) DO UPDATE SET
value = EXCLUDED.value,
description = EXCLUDED.description,
updated_at = NOW();
-- 3. Aktiviere RLS für die app_settings-Tabelle
ALTER TABLE public.app_settings ENABLE ROW LEVEL SECURITY;
-- 4. Erstelle eine Richtlinie für das Lesen von Einstellungen
-- Alle authentifizierten Benutzer dürfen Einstellungen sehen
DROP POLICY IF EXISTS app_settings_select_policy ON app_settings;
CREATE POLICY app_settings_select_policy
ON app_settings
FOR SELECT
TO authenticated
USING (true);
-- 5. Überprüfe, ob die Einstellungen existieren
SELECT key, value, description FROM public.app_settings;

View file

@ -0,0 +1,31 @@
-- Diese SQL-Funktion zum Löschen eines Dokuments erstellt eine sichere Methode
-- zum Löschen über RPC, was besser gegen Datenbank-Caching und Race-Conditions ist
-- Führen Sie dieses SQL im Supabase SQL-Editor aus
CREATE OR REPLACE FUNCTION delete_document_by_id(document_id uuid)
RETURNS boolean AS $$
DECLARE
success boolean;
affected_rows int;
BEGIN
-- Führe die eigentliche Löschung durch
DELETE FROM documents
WHERE id = document_id
AND conversation_id IN (
SELECT id FROM conversations WHERE user_id = auth.uid()
);
-- Speichere die Anzahl der betroffenen Zeilen
GET DIAGNOSTICS affected_rows = ROW_COUNT;
-- Setze den Erfolgsstatus basierend auf der Anzahl der gelöschten Zeilen
success := affected_rows > 0;
-- Gib das Ergebnis zurück (true wenn erfolgreich, false wenn nicht)
RETURN success;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Diese Funktion kann dann mit dem folgenden JavaScript aufgerufen werden:
-- const { data, error } = await supabase.rpc('delete_document_by_id', { document_id: 'uuid-here' });

View file

@ -0,0 +1,66 @@
-- Erstelle die Tabelle für Vorlagen
CREATE TABLE IF NOT EXISTS templates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
description TEXT,
system_prompt TEXT NOT NULL,
model_id UUID REFERENCES models(id),
color TEXT DEFAULT '#0A84FF',
is_default BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Kommentare für Dokumentation
COMMENT ON TABLE templates IS 'Vorlagen für vordefinierte Chat-Prompts';
COMMENT ON COLUMN templates.name IS 'Name der Vorlage';
COMMENT ON COLUMN templates.description IS 'Beschreibung der Vorlage';
COMMENT ON COLUMN templates.system_prompt IS 'System-Prompt für die KI';
COMMENT ON COLUMN templates.model_id IS 'Das bevorzugte Modell für diese Vorlage (optional)';
COMMENT ON COLUMN templates.color IS 'Farbcode für die Darstellung in der UI';
COMMENT ON COLUMN templates.is_default IS 'Gibt an, ob diese Vorlage als Standard verwendet werden soll';
-- Row Level Security
ALTER TABLE templates ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view their own templates" ON templates
FOR SELECT USING (user_id = auth.uid());
CREATE POLICY "Users can create their own templates" ON templates
FOR INSERT WITH CHECK (user_id = auth.uid());
CREATE POLICY "Users can update their own templates" ON templates
FOR UPDATE USING (user_id = auth.uid());
CREATE POLICY "Users can delete their own templates" ON templates
FOR DELETE USING (user_id = auth.uid());
-- Beispiel-Vorlagen
INSERT INTO templates (user_id, name, description, system_prompt, color, is_default)
VALUES (
(SELECT id FROM auth.users LIMIT 1), -- Erste Benutzer-ID
'Persönlicher Assistent',
'Allgemeiner Assistent, der bei vielfältigen Aufgaben hilft',
'Du bist ein hilfreicher Assistent. Antworte präzise und freundlich auf alle Fragen des Nutzers. Wenn du etwas nicht weißt, gib an, dass du dir unsicher bist, statt zu spekulieren.',
'#0A84FF',
true
);
INSERT INTO templates (user_id, name, description, system_prompt, color)
VALUES (
(SELECT id FROM auth.users LIMIT 1), -- Erste Benutzer-ID
'Kreativer Schreibpartner',
'Hilft beim Brainstorming und der Entwicklung kreativer Ideen',
'Du bist ein kreativer Schreibpartner. Hilf dem Nutzer bei der Entwicklung von Ideen für Geschichten, Charaktere, Szenarien und Dialoge. Sei fantasievoll und inspirierend. Schlage neue Richtungen vor, wenn der Nutzer feststeckt.',
'#FF375F'
);
INSERT INTO templates (user_id, name, description, system_prompt, color)
VALUES (
(SELECT id FROM auth.users LIMIT 1), -- Erste Benutzer-ID
'Technischer Berater',
'Unterstützt bei technischen Fragen und Programmierung',
'Du bist ein technischer Berater mit Expertenwissen in Programmierung, Softwareentwicklung und IT. Erkläre technische Konzepte verständlich, gib Code-Beispiele wenn nötig und biete praktische Lösungen für technische Probleme. Wenn Code bereitgestellt wird, analysiere ihn gründlich vor der Antwort.',
'#32D74B'
);

View file

@ -0,0 +1,144 @@
-- Funktionen zum Abfragen der Token-Nutzung
-- 1. Funktion zum Abrufen der Token-Nutzung eines Benutzers, gruppiert nach Modell
CREATE OR REPLACE FUNCTION get_user_model_usage(user_id UUID)
RETURNS TABLE (
model_id UUID,
model_name TEXT,
total_prompt_tokens BIGINT,
total_completion_tokens BIGINT,
total_tokens BIGINT,
total_cost DECIMAL(10, 6)
)
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
RETURN QUERY
SELECT
ul.model_id,
m.name AS model_name,
SUM(ul.prompt_tokens)::BIGINT AS total_prompt_tokens,
SUM(ul.completion_tokens)::BIGINT AS total_completion_tokens,
SUM(ul.total_tokens)::BIGINT AS total_tokens,
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
FROM
usage_logs ul
JOIN
models m ON ul.model_id = m.id
WHERE
ul.user_id = get_user_model_usage.user_id
GROUP BY
ul.model_id, m.name
ORDER BY
total_cost DESC;
END;
$$;
-- 2. Funktion zum Abrufen der Token-Nutzung eines Benutzers nach Zeitraum
CREATE OR REPLACE FUNCTION get_user_usage_by_period(user_id UUID, period TEXT)
RETURNS TABLE (
time_period TEXT,
total_tokens BIGINT,
total_cost DECIMAL(10, 6)
)
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
IF period = 'day' THEN
RETURN QUERY
SELECT
TO_CHAR(ul.created_at, 'YYYY-MM-DD') AS time_period,
SUM(ul.total_tokens)::BIGINT AS total_tokens,
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
FROM
usage_logs ul
WHERE
ul.user_id = get_user_usage_by_period.user_id
GROUP BY
time_period
ORDER BY
time_period DESC;
ELSIF period = 'month' THEN
RETURN QUERY
SELECT
TO_CHAR(ul.created_at, 'YYYY-MM') AS time_period,
SUM(ul.total_tokens)::BIGINT AS total_tokens,
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
FROM
usage_logs ul
WHERE
ul.user_id = get_user_usage_by_period.user_id
GROUP BY
time_period
ORDER BY
time_period DESC;
ELSIF period = 'year' THEN
RETURN QUERY
SELECT
TO_CHAR(ul.created_at, 'YYYY') AS time_period,
SUM(ul.total_tokens)::BIGINT AS total_tokens,
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
FROM
usage_logs ul
WHERE
ul.user_id = get_user_usage_by_period.user_id
GROUP BY
time_period
ORDER BY
time_period DESC;
ELSE
-- Fallback auf tägliche Ansicht
RETURN QUERY
SELECT
TO_CHAR(ul.created_at, 'YYYY-MM-DD') AS time_period,
SUM(ul.total_tokens)::BIGINT AS total_tokens,
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
FROM
usage_logs ul
WHERE
ul.user_id = get_user_usage_by_period.user_id
GROUP BY
time_period
ORDER BY
time_period DESC;
END IF;
END;
$$;
-- 3. Funktion zum Abrufen der Token-Nutzung einer bestimmten Konversation
CREATE OR REPLACE FUNCTION get_conversation_usage(conversation_id UUID)
RETURNS TABLE (
message_id UUID,
created_at TIMESTAMP WITH TIME ZONE,
prompt_tokens BIGINT,
completion_tokens BIGINT,
total_tokens BIGINT,
estimated_cost DECIMAL(10, 6)
)
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
RETURN QUERY
SELECT
ul.message_id,
ul.created_at,
ul.prompt_tokens::BIGINT,
ul.completion_tokens::BIGINT,
ul.total_tokens::BIGINT,
ul.estimated_cost::DECIMAL(10, 6)
FROM
usage_logs ul
WHERE
ul.conversation_id = get_conversation_usage.conversation_id
ORDER BY
ul.created_at;
END;
$$;
-- Erteile Berechtigungen für die Funktionen
GRANT EXECUTE ON FUNCTION get_user_model_usage TO authenticated;
GRANT EXECUTE ON FUNCTION get_user_usage_by_period TO authenticated;
GRANT EXECUTE ON FUNCTION get_conversation_usage TO authenticated;

View file

@ -0,0 +1,122 @@
-- Erstelle eine neue Tabelle für die Token-Nutzung und Kostenerfassung
-- 1. Überprüfe, ob die usage_logs-Tabelle existiert
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'usage_logs'
) THEN
-- Erstelle die usage_logs-Tabelle
CREATE TABLE public.usage_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
conversation_id UUID REFERENCES conversations(id) ON DELETE CASCADE,
message_id UUID REFERENCES messages(id) ON DELETE CASCADE,
user_id UUID REFERENCES auth.users(id),
model_id UUID REFERENCES models(id),
prompt_tokens INTEGER NOT NULL,
completion_tokens INTEGER NOT NULL,
total_tokens INTEGER NOT NULL,
estimated_cost DECIMAL(10, 6) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
RAISE NOTICE 'Tabelle usage_logs wurde erstellt.';
ELSE
RAISE NOTICE 'Tabelle usage_logs existiert bereits.';
END IF;
END
$$;
-- 2. Aktiviere RLS für die usage_logs-Tabelle
ALTER TABLE public.usage_logs ENABLE ROW LEVEL SECURITY;
-- 3. Erstelle RLS-Richtlinien für usage_logs
-- Benutzer können nur ihre eigenen Nutzungsdaten sehen
DROP POLICY IF EXISTS usage_logs_select_policy ON usage_logs;
CREATE POLICY usage_logs_select_policy
ON usage_logs
FOR SELECT
TO authenticated
USING (user_id = auth.uid());
-- Nur über die Anwendung dürfen Einträge erstellt werden
DROP POLICY IF EXISTS usage_logs_insert_policy ON usage_logs;
CREATE POLICY usage_logs_insert_policy
ON usage_logs
FOR INSERT
TO authenticated
WITH CHECK (user_id = auth.uid());
-- 4. Erweitere das Modell-Schema um Kosteninformationen
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'models'
AND column_name = 'cost_settings'
) THEN
ALTER TABLE public.models ADD COLUMN cost_settings JSONB DEFAULT '{"prompt_per_1k_tokens": 0.0001, "completion_per_1k_tokens": 0.0002}'::jsonb;
RAISE NOTICE 'Spalte cost_settings zur models-Tabelle hinzugefügt.';
ELSE
RAISE NOTICE 'Spalte cost_settings existiert bereits in der models-Tabelle.';
END IF;
END
$$;
-- 5. Aktualisiere die vorhandenen Modelle mit Kosteninformationen
UPDATE public.models
SET cost_settings = jsonb_build_object(
'prompt_per_1k_tokens', CASE
WHEN name LIKE '%GPT-O3-Mini%' THEN 0.0001
WHEN name LIKE '%GPT-4o-mini%' THEN 0.0001
WHEN name LIKE '%GPT-4o%' THEN 0.003
WHEN name LIKE '%GPT-4%' THEN 0.003
WHEN name LIKE '%GPT-3.5%' THEN 0.0001
WHEN name LIKE '%Claude%' THEN 0.0008
ELSE 0.0001
END,
'completion_per_1k_tokens', CASE
WHEN name LIKE '%GPT-O3-Mini%' THEN 0.0002
WHEN name LIKE '%GPT-4o-mini%' THEN 0.0002
WHEN name LIKE '%GPT-4o%' THEN 0.006
WHEN name LIKE '%GPT-4%' THEN 0.006
WHEN name LIKE '%GPT-3.5%' THEN 0.0002
WHEN name LIKE '%Claude%' THEN 0.0024
ELSE 0.0002
END
)
WHERE cost_settings IS NULL OR cost_settings = '{}'::jsonb;
-- 6. Funktion zur Berechnung der Kosten
CREATE OR REPLACE FUNCTION calculate_token_cost(
p_prompt_tokens INTEGER,
p_completion_tokens INTEGER,
p_model_id UUID
) RETURNS DECIMAL(10, 6) AS $$
DECLARE
v_prompt_cost DECIMAL(10, 6);
v_completion_cost DECIMAL(10, 6);
v_cost_settings JSONB;
v_cost DECIMAL(10, 6);
BEGIN
-- Hole die Kosteneinstellungen für das angegebene Modell
SELECT cost_settings INTO v_cost_settings
FROM models
WHERE id = p_model_id;
-- Extrahiere die Kosten pro 1000 Token
v_prompt_cost := (v_cost_settings->>'prompt_per_1k_tokens')::DECIMAL;
v_completion_cost := (v_cost_settings->>'completion_per_1k_tokens')::DECIMAL;
-- Berechne die Gesamtkosten
v_cost := (p_prompt_tokens * v_prompt_cost + p_completion_tokens * v_completion_cost) / 1000;
RETURN ROUND(v_cost, 6);
END;
$$ LANGUAGE plpgsql;
-- 7. Berechtigung zum Ausführen der Funktion
GRANT EXECUTE ON FUNCTION calculate_token_cost TO authenticated;

View file

@ -0,0 +1,103 @@
-- Erstelle oder aktualisiere die users-Tabelle im public-Schema
-- Prüfe, ob die users-Tabelle bereits existiert
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'users'
) THEN
-- Erstelle die users-Tabelle
CREATE TABLE public.users (
id UUID PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
name TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Erstelle einen Trigger für updated_at
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $func$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$func$ LANGUAGE plpgsql;
CREATE TRIGGER set_users_updated_at
BEFORE UPDATE ON public.users
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
RAISE NOTICE 'Tabelle users wurde erstellt.';
ELSE
RAISE NOTICE 'Tabelle users existiert bereits.';
END IF;
END
$$;
-- Erstelle eine Funktion, um Benutzer aus auth.users in public.users zu synchronisieren
CREATE OR REPLACE FUNCTION sync_user_after_auth_event()
RETURNS TRIGGER AS $sync_func$
BEGIN
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') AND NEW.confirmed_at IS NOT NULL THEN
-- Füge den Benutzer in die public.users-Tabelle ein oder aktualisiere ihn
INSERT INTO public.users (id, email, name, created_at, updated_at)
VALUES (
NEW.id,
NEW.email,
COALESCE(NEW.raw_user_meta_data->>'name', NEW.email),
NEW.created_at,
NEW.updated_at
)
ON CONFLICT (id) DO UPDATE SET
email = EXCLUDED.email,
name = COALESCE(NEW.raw_user_meta_data->>'name', NEW.email),
updated_at = NOW();
END IF;
RETURN NEW;
END;
$sync_func$ LANGUAGE plpgsql SECURITY DEFINER;
-- Erstelle einen Trigger für die auth.users-Tabelle
DROP TRIGGER IF EXISTS sync_user_after_auth_event_trigger ON auth.users;
CREATE TRIGGER sync_user_after_auth_event_trigger
AFTER INSERT OR UPDATE ON auth.users
FOR EACH ROW
EXECUTE FUNCTION sync_user_after_auth_event();
-- Synchronisiere bestehende Benutzer
INSERT INTO public.users (id, email, name, created_at, updated_at)
SELECT
id,
email,
COALESCE(raw_user_meta_data->>'name', email) as name,
created_at,
updated_at
FROM auth.users
WHERE confirmed_at IS NOT NULL
ON CONFLICT (id) DO UPDATE SET
email = EXCLUDED.email,
name = COALESCE(EXCLUDED.name, users.name),
updated_at = NOW();
-- Aktiviere RLS für die users-Tabelle
ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;
-- Erstelle eine Richtlinie für das Lesen von Benutzern
-- Benutzer dürfen nur ihre eigenen Daten sehen
CREATE POLICY users_select_policy
ON public.users
FOR SELECT
TO authenticated
USING (id = auth.uid());
-- Erstelle eine Richtlinie für das Aktualisieren von Benutzern
-- Benutzer dürfen nur ihre eigenen Daten aktualisieren
CREATE POLICY users_update_policy
ON public.users
FOR UPDATE
TO authenticated
USING (id = auth.uid());

View file

@ -0,0 +1,120 @@
-- Überprüfe und behebe Probleme mit der Conversations-Tabelle
-- 1. Überprüfe die Struktur der Conversations-Tabelle
DO $$
DECLARE
column_exists BOOLEAN;
BEGIN
-- Prüfe, ob die user_id-Spalte vom Typ UUID ist
SELECT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'conversations'
AND column_name = 'user_id'
AND data_type = 'uuid'
) INTO column_exists;
IF NOT column_exists THEN
RAISE NOTICE 'Die user_id-Spalte in der conversations-Tabelle ist nicht vom Typ UUID. Bitte überprüfe die Tabellendefinition.';
ELSE
RAISE NOTICE 'Die user_id-Spalte in der conversations-Tabelle ist korrekt vom Typ UUID.';
END IF;
-- Prüfe, ob es eine Unique-Constraint gibt, die Konflikte verursachen könnte
SELECT EXISTS (
SELECT FROM information_schema.table_constraints
WHERE table_schema = 'public'
AND table_name = 'conversations'
AND constraint_type = 'UNIQUE'
) INTO column_exists;
IF column_exists THEN
RAISE NOTICE 'Es gibt eine Unique-Constraint in der conversations-Tabelle, die Konflikte verursachen könnte.';
ELSE
RAISE NOTICE 'Es gibt keine Unique-Constraint in der conversations-Tabelle.';
END IF;
END $$;
-- 2. Überprüfe den Foreign-Key-Constraint
DO $$
DECLARE
fk_exists BOOLEAN;
BEGIN
-- Prüfe, ob es einen Foreign-Key-Constraint auf die users-Tabelle gibt
SELECT EXISTS (
SELECT FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY'
AND tc.table_schema = 'public'
AND tc.table_name = 'conversations'
AND kcu.column_name = 'user_id'
) INTO fk_exists;
IF fk_exists THEN
RAISE NOTICE 'Es gibt einen Foreign-Key-Constraint auf die user_id-Spalte in der conversations-Tabelle.';
ELSE
RAISE NOTICE 'Es gibt keinen Foreign-Key-Constraint auf die user_id-Spalte in der conversations-Tabelle.';
END IF;
END $$;
-- 3. Überprüfe, ob der angemeldete Benutzer in der users-Tabelle existiert
-- Ersetze 'DEINE_BENUTZER_ID' durch die tatsächliche Benutzer-ID
DO $$
DECLARE
user_exists BOOLEAN;
user_id_value UUID := auth.uid(); -- Aktuelle Benutzer-ID
BEGIN
-- Prüfe, ob der Benutzer in der users-Tabelle existiert
EXECUTE format('
SELECT EXISTS (
SELECT FROM public.users
WHERE id = %L
)', user_id_value) INTO user_exists;
IF user_exists THEN
RAISE NOTICE 'Der Benutzer mit der ID % existiert in der users-Tabelle.', user_id_value;
ELSE
RAISE NOTICE 'Der Benutzer mit der ID % existiert NICHT in der users-Tabelle.', user_id_value;
-- Füge den Benutzer manuell in die users-Tabelle ein
EXECUTE format('
INSERT INTO public.users (id, email, created_at, updated_at)
SELECT id, email, created_at, updated_at
FROM auth.users
WHERE id = %L
ON CONFLICT (id) DO NOTHING
', user_id_value);
RAISE NOTICE 'Der Benutzer wurde in die users-Tabelle eingefügt.';
END IF;
END $$;
-- 4. Überprüfe, ob die Synchronisierung zwischen auth.users und public.users funktioniert
DO $$
BEGIN
-- Prüfe, ob der Trigger für die Synchronisierung existiert
IF EXISTS (
SELECT FROM pg_trigger
WHERE tgname = 'sync_user_after_auth_event_trigger'
) THEN
RAISE NOTICE 'Der Trigger für die Synchronisierung zwischen auth.users und public.users existiert.';
ELSE
RAISE NOTICE 'Der Trigger für die Synchronisierung zwischen auth.users und public.users existiert NICHT.';
END IF;
END $$;
-- 5. Synchronisiere alle Benutzer aus auth.users in public.users
INSERT INTO public.users (id, email, name, created_at, updated_at)
SELECT
id,
email,
COALESCE(raw_user_meta_data->>'name', email) as name,
created_at,
updated_at
FROM auth.users
WHERE confirmed_at IS NOT NULL
ON CONFLICT (id) DO UPDATE SET
email = EXCLUDED.email,
name = COALESCE(EXCLUDED.name, users.name),
updated_at = NOW();

View file

@ -0,0 +1,46 @@
-- SQL-Skript, um die Nachrichtentabelle zu überprüfen und zu korrigieren
-- Überprüfe die aktuelle Struktur der messages-Tabelle
SELECT
column_name,
data_type,
is_nullable,
column_default
FROM
information_schema.columns
WHERE
table_name = 'messages'
ORDER BY
ordinal_position;
-- Überprüfe Constraints für die messages-Tabelle
SELECT
tc.constraint_name,
tc.constraint_type,
kcu.column_name,
cc.check_clause
FROM
information_schema.table_constraints tc
JOIN
information_schema.constraint_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
LEFT JOIN
information_schema.check_constraints cc
ON tc.constraint_name = cc.constraint_name
WHERE
tc.table_name = 'messages';
-- Behebt das Problem mit der Check-Constraint in der messages-Tabelle
-- Entfernt die bestehende Check-Constraint und erstellt eine neue, die 'assistant' akzeptiert
DO $$
BEGIN
-- Entferne die bestehende Check-Constraint
ALTER TABLE messages DROP CONSTRAINT IF EXISTS messages_sender_check;
-- Erstelle eine neue Check-Constraint, die 'assistant' akzeptiert
ALTER TABLE messages
ADD CONSTRAINT messages_sender_check
CHECK (sender IN ('user', 'assistant', 'system'));
RAISE NOTICE 'Check-Constraint für die sender-Spalte in der messages-Tabelle wurde aktualisiert.';
END $$;

View file

@ -0,0 +1,27 @@
-- Überprüfe die aktuelle Struktur der models-Tabelle
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = 'models';
-- Füge die fehlenden Spalten hinzu, wenn sie nicht existieren
DO $$
BEGIN
-- Überprüfe, ob created_at existiert
IF NOT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'models' AND column_name = 'created_at'
) THEN
ALTER TABLE models ADD COLUMN created_at TIMESTAMPTZ DEFAULT now();
END IF;
-- Überprüfe, ob updated_at existiert
IF NOT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'models' AND column_name = 'updated_at'
) THEN
ALTER TABLE models ADD COLUMN updated_at TIMESTAMPTZ DEFAULT now();
END IF;
END
$$;

View file

@ -0,0 +1,157 @@
-- RLS-Richtlinien für die Conversations-Tabelle
-- Aktiviere RLS für die Conversations-Tabelle
ALTER TABLE conversations ENABLE ROW LEVEL SECURITY;
-- Löschen vorhandener Richtlinien (falls vorhanden)
DROP POLICY IF EXISTS conversations_insert_policy ON conversations;
DROP POLICY IF EXISTS conversations_select_policy ON conversations;
DROP POLICY IF EXISTS conversations_update_policy ON conversations;
DROP POLICY IF EXISTS conversations_delete_policy ON conversations;
-- Erstelle eine Richtlinie für das Einfügen von Konversationen
-- Benutzer dürfen nur Konversationen für sich selbst erstellen
CREATE POLICY conversations_insert_policy
ON conversations
FOR INSERT
TO authenticated
WITH CHECK (auth.uid() = user_id);
-- Erstelle eine Richtlinie für das Lesen von Konversationen
-- Benutzer dürfen nur ihre eigenen Konversationen sehen
CREATE POLICY conversations_select_policy
ON conversations
FOR SELECT
TO authenticated
USING (auth.uid() = user_id);
-- Erstelle eine Richtlinie für das Aktualisieren von Konversationen
-- Benutzer dürfen nur ihre eigenen Konversationen aktualisieren
CREATE POLICY conversations_update_policy
ON conversations
FOR UPDATE
TO authenticated
USING (auth.uid() = user_id);
-- Erstelle eine Richtlinie für das Löschen von Konversationen
-- Benutzer dürfen nur ihre eigenen Konversationen löschen
CREATE POLICY conversations_delete_policy
ON conversations
FOR DELETE
TO authenticated
USING (auth.uid() = user_id);
-- RLS-Richtlinien für die Messages-Tabelle
-- Aktiviere RLS für die Messages-Tabelle
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
-- Löschen vorhandener Richtlinien (falls vorhanden)
DROP POLICY IF EXISTS messages_insert_policy ON messages;
DROP POLICY IF EXISTS messages_select_policy ON messages;
DROP POLICY IF EXISTS messages_update_policy ON messages;
DROP POLICY IF EXISTS messages_delete_policy ON messages;
-- Erstelle eine Richtlinie für das Einfügen von Nachrichten
-- Benutzer dürfen nur Nachrichten zu ihren eigenen Konversationen hinzufügen
CREATE POLICY messages_insert_policy
ON messages
FOR INSERT
TO authenticated
WITH CHECK (
conversation_id IN (
SELECT id FROM conversations WHERE user_id = auth.uid()
)
);
-- Erstelle eine Richtlinie für das Lesen von Nachrichten
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen sehen
CREATE POLICY messages_select_policy
ON messages
FOR SELECT
TO authenticated
USING (
conversation_id IN (
SELECT id FROM conversations WHERE user_id = auth.uid()
)
);
-- Erstelle eine Richtlinie für das Aktualisieren von Nachrichten
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen aktualisieren
CREATE POLICY messages_update_policy
ON messages
FOR UPDATE
TO authenticated
USING (
conversation_id IN (
SELECT id FROM conversations WHERE user_id = auth.uid()
)
);
-- Erstelle eine Richtlinie für das Löschen von Nachrichten
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen löschen
CREATE POLICY messages_delete_policy
ON messages
FOR DELETE
TO authenticated
USING (
conversation_id IN (
SELECT id FROM conversations WHERE user_id = auth.uid()
)
);
-- RLS-Richtlinien für die Models-Tabelle
-- Aktiviere RLS für die Models-Tabelle
ALTER TABLE models ENABLE ROW LEVEL SECURITY;
-- Löschen vorhandener Richtlinien (falls vorhanden)
DROP POLICY IF EXISTS models_select_policy ON models;
-- Erstelle eine Richtlinie für das Lesen von Modellen
-- Alle authentifizierten Benutzer dürfen Modelle sehen
CREATE POLICY models_select_policy
ON models
FOR SELECT
TO authenticated
USING (true);
-- Erstelle eine Bypass-Richtlinie für Anon-Benutzer, um Modelle zu sehen
-- Dies ist wichtig für die API-Route, die Modelle abruft
CREATE POLICY models_anon_select_policy
ON models
FOR SELECT
TO anon
USING (true);
-- RLS-Richtlinien für die Templates-Tabelle (falls vorhanden)
-- Aktiviere RLS für die Templates-Tabelle (nur wenn sie existiert)
DO $$
BEGIN
IF EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'templates'
) THEN
EXECUTE 'ALTER TABLE templates ENABLE ROW LEVEL SECURITY;';
-- Löschen vorhandener Richtlinien (falls vorhanden)
EXECUTE 'DROP POLICY IF EXISTS templates_select_policy ON templates;';
-- Erstelle eine Richtlinie für das Lesen von Templates
EXECUTE 'CREATE POLICY templates_select_policy
ON templates
FOR SELECT
TO authenticated
USING (true);';
-- Erstelle eine Bypass-Richtlinie für Anon-Benutzer, um Templates zu sehen
EXECUTE 'CREATE POLICY templates_anon_select_policy
ON templates
FOR SELECT
TO anon
USING (true);';
END IF;
END
$$;

View file

@ -0,0 +1,73 @@
-- Überprüfe und korrigiere die templates-Tabelle
-- 1. Prüfe, ob die templates-Tabelle existiert, erstelle sie falls nicht
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'templates'
) THEN
-- Erstelle die Tabelle für Vorlagen
CREATE TABLE public.templates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
description TEXT,
system_prompt TEXT NOT NULL,
initial_question TEXT,
model_id UUID REFERENCES models(id),
color TEXT DEFAULT '#0A84FF',
is_default BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
RAISE NOTICE 'Tabelle templates wurde erstellt.';
ELSE
RAISE NOTICE 'Tabelle templates existiert bereits.';
END IF;
END
$$;
-- 2. Prüfe, ob die color-Spalte existiert, füge sie hinzu falls nicht
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'templates'
AND column_name = 'color'
) THEN
ALTER TABLE public.templates ADD COLUMN color TEXT DEFAULT '#0A84FF';
RAISE NOTICE 'Spalte color zur templates-Tabelle hinzugefügt.';
ELSE
RAISE NOTICE 'Spalte color existiert bereits in der templates-Tabelle.';
END IF;
END
$$;
-- 3. Row Level Security
ALTER TABLE templates ENABLE ROW LEVEL SECURITY;
-- Lösche bestehende Policies, falls vorhanden
DROP POLICY IF EXISTS "Users can view their own templates" ON templates;
DROP POLICY IF EXISTS "Users can create their own templates" ON templates;
DROP POLICY IF EXISTS "Users can update their own templates" ON templates;
DROP POLICY IF EXISTS "Users can delete their own templates" ON templates;
-- Erstelle die Policies neu
CREATE POLICY "Users can view their own templates" ON templates
FOR SELECT USING (user_id = auth.uid());
CREATE POLICY "Users can create their own templates" ON templates
FOR INSERT WITH CHECK (user_id = auth.uid());
CREATE POLICY "Users can update their own templates" ON templates
FOR UPDATE USING (user_id = auth.uid());
CREATE POLICY "Users can delete their own templates" ON templates
FOR DELETE USING (user_id = auth.uid());
-- 4. Zeige einige Beispieldaten an
SELECT id, name, description, color FROM templates LIMIT 5;

View file

@ -0,0 +1,115 @@
-- RLS-Richtlinien für die Conversations-Tabelle
-- Aktiviere RLS für die Conversations-Tabelle
ALTER TABLE conversations ENABLE ROW LEVEL SECURITY;
-- Erstelle eine Richtlinie für das Einfügen von Konversationen
-- Benutzer dürfen nur Konversationen für sich selbst erstellen
CREATE POLICY conversations_insert_policy
ON conversations
FOR INSERT
TO authenticated
WITH CHECK (auth.uid() = user_id);
-- Erstelle eine Richtlinie für das Lesen von Konversationen
-- Benutzer dürfen nur ihre eigenen Konversationen sehen
CREATE POLICY conversations_select_policy
ON conversations
FOR SELECT
TO authenticated
USING (auth.uid() = user_id);
-- Erstelle eine Richtlinie für das Aktualisieren von Konversationen
-- Benutzer dürfen nur ihre eigenen Konversationen aktualisieren
CREATE POLICY conversations_update_policy
ON conversations
FOR UPDATE
TO authenticated
USING (auth.uid() = user_id);
-- Erstelle eine Richtlinie für das Löschen von Konversationen
-- Benutzer dürfen nur ihre eigenen Konversationen löschen
CREATE POLICY conversations_delete_policy
ON conversations
FOR DELETE
TO authenticated
USING (auth.uid() = user_id);
-- RLS-Richtlinien für die Messages-Tabelle
-- Aktiviere RLS für die Messages-Tabelle
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
-- Erstelle eine Richtlinie für das Einfügen von Nachrichten
-- Benutzer dürfen nur Nachrichten zu ihren eigenen Konversationen hinzufügen
CREATE POLICY messages_insert_policy
ON messages
FOR INSERT
TO authenticated
WITH CHECK (
conversation_id IN (
SELECT id FROM conversations WHERE user_id = auth.uid()
)
);
-- Erstelle eine Richtlinie für das Lesen von Nachrichten
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen sehen
CREATE POLICY messages_select_policy
ON messages
FOR SELECT
TO authenticated
USING (
conversation_id IN (
SELECT id FROM conversations WHERE user_id = auth.uid()
)
);
-- Erstelle eine Richtlinie für das Aktualisieren von Nachrichten
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen aktualisieren
CREATE POLICY messages_update_policy
ON messages
FOR UPDATE
TO authenticated
USING (
conversation_id IN (
SELECT id FROM conversations WHERE user_id = auth.uid()
)
);
-- Erstelle eine Richtlinie für das Löschen von Nachrichten
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen löschen
CREATE POLICY messages_delete_policy
ON messages
FOR DELETE
TO authenticated
USING (
conversation_id IN (
SELECT id FROM conversations WHERE user_id = auth.uid()
)
);
-- RLS-Richtlinien für die Models-Tabelle
-- Aktiviere RLS für die Models-Tabelle
ALTER TABLE models ENABLE ROW LEVEL SECURITY;
-- Erstelle eine Richtlinie für das Lesen von Modellen
-- Alle authentifizierten Benutzer dürfen Modelle sehen
CREATE POLICY models_select_policy
ON models
FOR SELECT
TO authenticated
USING (true);
-- RLS-Richtlinien für die Templates-Tabelle
-- Aktiviere RLS für die Templates-Tabelle
ALTER TABLE templates ENABLE ROW LEVEL SECURITY;
-- Erstelle eine Richtlinie für das Lesen von Templates
-- Alle authentifizierten Benutzer dürfen Templates sehen
CREATE POLICY templates_select_policy
ON templates
FOR SELECT
TO authenticated
USING (true);

View file

@ -0,0 +1,136 @@
// Skript zum Einrichten von Supabase-Funktionen und Tabellen
import { createClient } from '@supabase/supabase-js';
import dotenv from 'dotenv';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import fs from 'fs';
// Lade Umgebungsvariablen aus .env
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Supabase-Client erstellen
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL;
const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseKey) {
console.error('Fehler: EXPO_PUBLIC_SUPABASE_URL und EXPO_PUBLIC_SUPABASE_ANON_KEY müssen in der .env-Datei definiert sein.');
process.exit(1);
}
const supabase = createClient(supabaseUrl, supabaseKey);
// Funktion zum Ausführen einer SQL-Datei
async function executeSqlFile(filePath) {
try {
const fullPath = join(__dirname, filePath);
console.log(`Führe SQL-Datei aus: ${fullPath}`);
if (!fs.existsSync(fullPath)) {
console.error(`Fehler: Datei ${fullPath} existiert nicht.`);
return false;
}
const query = fs.readFileSync(fullPath, 'utf8');
// Teile die Abfrage in einzelne Anweisungen auf
const statements = query.split(';').filter(stmt => stmt.trim() !== '');
for (const statement of statements) {
console.log(`Führe aus: ${statement.trim()}`);
const { error } = await supabase.rpc('execute_sql', { query: statement.trim() });
if (error) {
console.error('Fehler bei der Ausführung:', error.message);
// Fahre trotz Fehler fort
}
}
return true;
} catch (error) {
console.error('Fehler beim Lesen oder Ausführen der Datei:', error.message);
return false;
}
}
// Funktion zum Erstellen der execute_sql-Funktion
async function createExecuteSqlFunction() {
try {
console.log('Erstelle execute_sql-Funktion...');
const query = `
CREATE OR REPLACE FUNCTION execute_sql(query text)
RETURNS JSONB
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
result JSONB;
BEGIN
EXECUTE 'SELECT jsonb_agg(row_to_json(t)) FROM (' || query || ') t' INTO result;
RETURN COALESCE(result, '[]'::jsonb);
EXCEPTION
WHEN OTHERS THEN
RAISE EXCEPTION 'SQL-Fehler: %', SQLERRM;
END;
$$;
`;
const { error } = await supabase.rpc('execute_sql', { query });
if (error) {
// Die Funktion existiert möglicherweise noch nicht, versuche direkte SQL-Ausführung
console.log('Versuche direkte SQL-Ausführung...');
const { error: directError } = await supabase
.from('_exec_sql')
.insert({ sql: query });
if (directError) {
console.error('Fehler beim Erstellen der execute_sql-Funktion:', directError.message);
return false;
}
}
console.log('execute_sql-Funktion erfolgreich erstellt.');
return true;
} catch (error) {
console.error('Unerwarteter Fehler:', error.message);
return false;
}
}
// Hauptfunktion
async function setupSupabase() {
console.log('Starte Supabase-Setup...');
// Erstelle die execute_sql-Funktion
const execSqlCreated = await createExecuteSqlFunction();
if (!execSqlCreated) {
console.log('Konnte execute_sql-Funktion nicht erstellen. Versuche trotzdem fortzufahren...');
}
// Führe die SQL-Dateien aus
console.log('Führe Supabase-Funktionen-Setup aus...');
await executeSqlFile('setup_supabase_functions.sql');
console.log('Führe Modell-Updates aus...');
await executeSqlFile('update_models.sql');
console.log('Richte RLS-Richtlinien ein...');
await executeSqlFile('setup_rls_policies.sql');
console.log('Supabase-Setup abgeschlossen.');
}
// Führe die Funktion aus
setupSupabase()
.catch(error => {
console.error('Unerwarteter Fehler:', error);
})
.finally(() => {
process.exit(0);
});

View file

@ -0,0 +1,52 @@
-- Erstelle eine Funktion zum Ausführen von SQL-Abfragen
CREATE OR REPLACE FUNCTION execute_sql(query text)
RETURNS JSONB
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
result JSONB;
BEGIN
EXECUTE 'SELECT jsonb_agg(row_to_json(t)) FROM (' || query || ') t' INTO result;
RETURN COALESCE(result, '[]'::jsonb);
EXCEPTION
WHEN OTHERS THEN
RAISE EXCEPTION 'SQL-Fehler: %', SQLERRM;
END;
$$;
-- Erstelle eine Funktion zum Erstellen der models-Tabelle, falls sie nicht existiert
CREATE OR REPLACE FUNCTION create_models_table()
RETURNS VOID
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
-- Prüfe, ob die Tabelle bereits existiert
IF NOT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'models'
) THEN
-- Erstelle die Tabelle
CREATE TABLE models (
id UUID PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
parameters JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Erstelle einen Trigger für updated_at
CREATE TRIGGER set_updated_at
BEFORE UPDATE ON models
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
RAISE NOTICE 'Tabelle models wurde erstellt.';
ELSE
RAISE NOTICE 'Tabelle models existiert bereits.';
END IF;
END;
$$;

View file

@ -0,0 +1,176 @@
-- Enable Row Level Security for spaces tables
ALTER TABLE public.spaces ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.space_members ENABLE ROW LEVEL SECURITY;
-- RLS policies for spaces
-- Space owners can do everything with their spaces
CREATE POLICY spaces_owner_policy
ON public.spaces
TO authenticated
USING (owner_id = auth.uid());
-- Members can view spaces they belong to
CREATE POLICY spaces_member_select_policy
ON public.spaces
FOR SELECT
TO authenticated
USING (
id IN (
SELECT space_id
FROM public.space_members
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
)
);
-- RLS policies for space_members
-- Space owners can manage all members
CREATE POLICY space_members_owner_policy
ON public.space_members
TO authenticated
USING (
space_id IN (
SELECT id FROM public.spaces WHERE owner_id = auth.uid()
)
);
-- Space admins can manage members (except owners)
CREATE POLICY space_members_admin_policy
ON public.space_members
TO authenticated
USING (
space_id IN (
SELECT space_id FROM public.space_members
WHERE user_id = auth.uid() AND role = 'admin' AND invitation_status = 'accepted'
)
AND role != 'owner'
);
-- Users can see which spaces they are members of
CREATE POLICY space_members_self_select_policy
ON public.space_members
FOR SELECT
TO authenticated
USING (user_id = auth.uid());
-- Users can accept/decline their own invitations
CREATE POLICY space_members_invitation_update_policy
ON public.space_members
FOR UPDATE
TO authenticated
USING (user_id = auth.uid())
WITH CHECK (
user_id = auth.uid()
AND (OLD.invitation_status = 'pending')
AND (NEW.invitation_status IN ('accepted', 'declined'))
AND (OLD.role = NEW.role)
AND (OLD.space_id = NEW.space_id)
AND (OLD.user_id = NEW.user_id)
);
-- Update RLS policies for conversations
-- Modify existing policies to include space-based access
DROP POLICY IF EXISTS conversations_select_policy ON conversations;
CREATE POLICY conversations_select_policy
ON conversations
FOR SELECT
TO authenticated
USING (
user_id = auth.uid()
OR
(
space_id IN (
SELECT space_id FROM public.space_members
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
)
)
);
-- Allow space members to create conversations in spaces they belong to
CREATE POLICY conversations_space_insert_policy
ON conversations
FOR INSERT
TO authenticated
WITH CHECK (
user_id = auth.uid()
AND
(
space_id IS NULL
OR
space_id IN (
SELECT space_id FROM public.space_members
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
)
)
);
-- Allow updates to conversations in spaces based on role
DROP POLICY IF EXISTS conversations_update_policy ON conversations;
CREATE POLICY conversations_update_policy
ON conversations
FOR UPDATE
TO authenticated
USING (
user_id = auth.uid()
OR
(
space_id IN (
SELECT sm.space_id FROM public.space_members sm
WHERE sm.user_id = auth.uid()
AND sm.invitation_status = 'accepted'
AND sm.role IN ('owner', 'admin')
)
)
);
-- Allow deletion of conversations in spaces based on role
DROP POLICY IF EXISTS conversations_delete_policy ON conversations;
CREATE POLICY conversations_delete_policy
ON conversations
FOR DELETE
TO authenticated
USING (
user_id = auth.uid()
OR
(
space_id IN (
SELECT sm.space_id FROM public.space_members sm
WHERE sm.user_id = auth.uid()
AND sm.invitation_status = 'accepted'
AND sm.role IN ('owner', 'admin')
)
)
);
-- Helper function to check if a user has access to a space
CREATE OR REPLACE FUNCTION public.user_has_space_access(space_uuid UUID, role_level TEXT DEFAULT 'viewer')
RETURNS BOOLEAN AS $$
DECLARE
has_access BOOLEAN;
role_hierarchy TEXT[];
BEGIN
-- Define role hierarchy from highest to lowest
role_hierarchy := ARRAY['owner', 'admin', 'member', 'viewer'];
-- Find position of requested role in hierarchy
WITH role_positions AS (
SELECT
unnest(role_hierarchy) AS role,
row_number() OVER () AS position
)
SELECT EXISTS (
SELECT 1 FROM public.space_members sm
JOIN role_positions rp1 ON sm.role = rp1.role
JOIN role_positions rp2 ON rp2.role = role_level
WHERE sm.space_id = space_uuid
AND sm.user_id = auth.uid()
AND sm.invitation_status = 'accepted'
AND rp1.position <= rp2.position -- Check if user's role is at least the required level
) INTO has_access;
RETURN has_access;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

View file

@ -0,0 +1,45 @@
-- Create spaces table
CREATE TABLE IF NOT EXISTS public.spaces (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
owner_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
is_archived BOOLEAN DEFAULT false
);
-- Add comments for documentation
COMMENT ON TABLE public.spaces IS 'Collaborative spaces for organizing conversations';
COMMENT ON COLUMN spaces.name IS 'Name of the space';
COMMENT ON COLUMN spaces.description IS 'Optional description of the space';
COMMENT ON COLUMN spaces.owner_id IS 'User ID of the space owner';
COMMENT ON COLUMN spaces.is_archived IS 'Indicates whether the space is archived';
-- Create space_members table with roles/permissions
CREATE TABLE IF NOT EXISTS public.space_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
space_id UUID NOT NULL REFERENCES public.spaces(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
role TEXT NOT NULL CHECK (role IN ('owner', 'admin', 'member', 'viewer')),
invitation_status TEXT NOT NULL DEFAULT 'pending' CHECK (invitation_status IN ('pending', 'accepted', 'declined')),
invited_by UUID REFERENCES public.users(id),
invited_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
joined_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(space_id, user_id)
);
-- Add comments for space_members
COMMENT ON TABLE public.space_members IS 'Members of collaborative spaces with defined roles';
COMMENT ON COLUMN space_members.role IS 'Role of the user in the space (owner, admin, member, viewer)';
COMMENT ON COLUMN space_members.invitation_status IS 'Status of the invitation (pending, accepted, declined)';
-- Modify conversations table to add space_id
ALTER TABLE public.conversations
ADD COLUMN IF NOT EXISTS space_id UUID REFERENCES public.spaces(id) ON DELETE SET NULL;
-- Create indexes for faster queries
CREATE INDEX IF NOT EXISTS idx_conversations_space_id ON conversations(space_id);
CREATE INDEX IF NOT EXISTS idx_conversations_space_user ON conversations(space_id, user_id);

View file

@ -0,0 +1,97 @@
-- Create updated_at trigger for spaces
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Apply updated_at trigger to spaces table if it doesn't exist
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_trigger WHERE tgname = 'set_spaces_updated_at'
) THEN
CREATE TRIGGER set_spaces_updated_at
BEFORE UPDATE ON public.spaces
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
END IF;
END
$$;
-- Apply updated_at trigger to space_members table if it doesn't exist
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_trigger WHERE tgname = 'set_space_members_updated_at'
) THEN
CREATE TRIGGER set_space_members_updated_at
BEFORE UPDATE ON public.space_members
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
END IF;
END
$$;
-- Automatically add space owner as member with owner role
CREATE OR REPLACE FUNCTION add_owner_to_space_members()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.space_members (
space_id,
user_id,
role,
invitation_status,
joined_at
)
VALUES (
NEW.id,
NEW.owner_id,
'owner',
'accepted',
NOW()
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Apply owner trigger to spaces table if it doesn't exist
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_trigger WHERE tgname = 'add_owner_to_space_members_trigger'
) THEN
CREATE TRIGGER add_owner_to_space_members_trigger
AFTER INSERT ON public.spaces
FOR EACH ROW
EXECUTE FUNCTION add_owner_to_space_members();
END IF;
END
$$;
-- Update space modification timestamp when members are added/changed
CREATE OR REPLACE FUNCTION update_space_timestamp_on_member_change()
RETURNS TRIGGER AS $$
BEGIN
UPDATE public.spaces
SET updated_at = NOW()
WHERE id = NEW.space_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Apply space timestamp update trigger if it doesn't exist
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_trigger WHERE tgname = 'update_space_timestamp_trigger'
) THEN
CREATE TRIGGER update_space_timestamp_trigger
AFTER INSERT OR UPDATE ON public.space_members
FOR EACH ROW
EXECUTE FUNCTION update_space_timestamp_on_member_change();
END IF;
END
$$;

View file

@ -0,0 +1,86 @@
-- Drop problematic policies that cause infinite recursion
DROP POLICY IF EXISTS space_members_owner_policy ON space_members;
DROP POLICY IF EXISTS space_members_admin_policy ON space_members;
DROP POLICY IF EXISTS space_members_self_select_policy ON space_members;
DROP POLICY IF EXISTS space_members_invitation_update_policy ON space_members;
DROP POLICY IF EXISTS conversations_select_policy ON conversations;
DROP POLICY IF EXISTS conversations_space_insert_policy ON conversations;
DROP POLICY IF EXISTS conversations_update_policy ON conversations;
DROP POLICY IF EXISTS conversations_delete_policy ON conversations;
-- Recreate RLS policies for space_members (simplified to avoid recursion)
CREATE POLICY space_members_owner_policy
ON public.space_members
TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.spaces
WHERE id = space_id AND owner_id = auth.uid()
)
);
-- Users can see which spaces they are members of
CREATE POLICY space_members_self_select_policy
ON public.space_members
FOR SELECT
TO authenticated
USING (user_id = auth.uid());
-- Users can accept/decline their own invitations
CREATE POLICY space_members_invitation_update_policy
ON public.space_members
FOR UPDATE
TO authenticated
USING (user_id = auth.uid())
WITH CHECK (
user_id = auth.uid()
AND invitation_status = 'pending'
);
-- Create simplified policies for conversations
-- Allow users to see their own conversations or shared with them
CREATE POLICY conversations_select_policy
ON conversations
FOR SELECT
TO authenticated
USING (
user_id = auth.uid()
OR
space_id IN (
SELECT space_id FROM public.space_members
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
)
);
-- Allow users to create conversations in spaces they belong to
CREATE POLICY conversations_space_insert_policy
ON conversations
FOR INSERT
TO authenticated
WITH CHECK (
user_id = auth.uid()
AND
(
space_id IS NULL
OR
space_id IN (
SELECT space_id FROM public.space_members
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
)
)
);
-- Allow users to update their own conversations
CREATE POLICY conversations_update_policy
ON conversations
FOR UPDATE
TO authenticated
USING (user_id = auth.uid());
-- Allow users to delete their own conversations
CREATE POLICY conversations_delete_policy
ON conversations
FOR DELETE
TO authenticated
USING (user_id = auth.uid());

View file

@ -0,0 +1,69 @@
-- Completely drop ALL RLS policies for the affected tables
DROP POLICY IF EXISTS spaces_owner_policy ON spaces;
DROP POLICY IF EXISTS spaces_member_select_policy ON spaces;
DROP POLICY IF EXISTS space_members_owner_policy ON space_members;
DROP POLICY IF EXISTS space_members_admin_policy ON space_members;
DROP POLICY IF EXISTS space_members_self_select_policy ON space_members;
DROP POLICY IF EXISTS space_members_invitation_update_policy ON space_members;
DROP POLICY IF EXISTS conversations_select_policy ON conversations;
DROP POLICY IF EXISTS conversations_space_insert_policy ON conversations;
DROP POLICY IF EXISTS conversations_update_policy ON conversations;
DROP POLICY IF EXISTS conversations_delete_policy ON conversations;
-- Create minimal basic policies for spaces
CREATE POLICY spaces_select_policy
ON public.spaces
FOR SELECT
TO authenticated
USING (true); -- Allow all users to see all spaces for now
CREATE POLICY spaces_insert_policy
ON public.spaces
FOR INSERT
TO authenticated
WITH CHECK (owner_id = auth.uid()); -- Only allow users to create spaces where they are the owner
-- Create minimal basic policies for space_members
CREATE POLICY space_members_select_policy
ON public.space_members
FOR SELECT
TO authenticated
USING (true); -- Allow all users to see all space members for now
CREATE POLICY space_members_insert_policy
ON public.space_members
FOR INSERT
TO authenticated
WITH CHECK (true); -- Allow all insertions for now
CREATE POLICY space_members_update_policy
ON public.space_members
FOR UPDATE
TO authenticated
USING (true) -- Allow all updates for now
WITH CHECK (true);
-- Revert conversations back to simple user-based policies
CREATE POLICY conversations_select_policy
ON conversations
FOR SELECT
TO authenticated
USING (user_id = auth.uid()); -- Only see your own conversations
CREATE POLICY conversations_insert_policy
ON conversations
FOR INSERT
TO authenticated
WITH CHECK (user_id = auth.uid()); -- Only create your own conversations
CREATE POLICY conversations_update_policy
ON conversations
FOR UPDATE
TO authenticated
USING (user_id = auth.uid()); -- Only update your own conversations
CREATE POLICY conversations_delete_policy
ON conversations
FOR DELETE
TO authenticated
USING (user_id = auth.uid()); -- Only delete your own conversations

View file

@ -0,0 +1,83 @@
#!/usr/bin/env node
/**
* This script sets up the spaces feature by running the necessary SQL scripts
*/
const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');
const { createClient } = require('@supabase/supabase-js');
// Get environment variables
const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_SERVICE_KEY = process.env.SUPABASE_SERVICE_KEY;
if (!SUPABASE_URL || !SUPABASE_SERVICE_KEY) {
console.error('Error: SUPABASE_URL and SUPABASE_SERVICE_KEY environment variables must be set');
process.exit(1);
}
// Create Supabase client
const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY, {
auth: {
autoRefreshToken: false,
persistSession: false
}
});
async function executeSQL(filename) {
try {
const filePath = path.join(__dirname, filename);
const sql = fs.readFileSync(filePath, 'utf8');
// Split the SQL file by semicolons to get individual statements
const statements = sql
.split(';')
.map(statement => statement.trim())
.filter(statement => statement.length > 0);
console.log(`Executing ${statements.length} statements from ${filename}...`);
for (const statement of statements) {
const { error } = await supabase.rpc('exec_sql', { sql: statement });
if (error) {
console.error(`Error executing statement:`, error);
console.error(`Statement was: ${statement.substring(0, 100)}...`);
}
}
console.log(`✅ Successfully executed ${filename}`);
return true;
} catch (error) {
console.error(`❌ Error executing ${filename}:`, error);
return false;
}
}
async function main() {
console.log('Setting up spaces feature...');
// Run the SQL scripts in the correct order
const scripts = [
'create_spaces_tables.sql',
'create_spaces_triggers.sql',
'create_spaces_rls.sql'
];
for (const script of scripts) {
const success = await executeSQL(script);
if (!success) {
console.error(`Failed to execute ${script}. Aborting.`);
process.exit(1);
}
}
console.log('✅ Spaces feature setup complete!');
}
main().catch(err => {
console.error('Unhandled error:', err);
process.exit(1);
});

View file

@ -0,0 +1,167 @@
#!/usr/bin/env node
import { createClient } from '@supabase/supabase-js';
import dotenv from 'dotenv';
import readline from 'readline';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import fs from 'fs';
// Lade Umgebungsvariablen aus .env
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Supabase-Client erstellen
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL;
const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseKey) {
console.error('Fehler: EXPO_PUBLIC_SUPABASE_URL und EXPO_PUBLIC_SUPABASE_ANON_KEY müssen in der .env-Datei definiert sein.');
process.exit(1);
}
const supabase = createClient(supabaseUrl, supabaseKey);
// Readline-Interface für interaktive Eingabe
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// Funktion zum Ausführen einer SQL-Abfrage
async function executeQuery(query) {
try {
console.log(`Führe Abfrage aus: ${query}`);
const { data, error } = await supabase.rpc('execute_sql', { query });
if (error) {
console.error('Fehler bei der Ausführung der Abfrage:', error.message);
return;
}
console.log('Ergebnis:');
console.table(data);
} catch (error) {
console.error('Unerwarteter Fehler:', error.message);
}
}
// Funktion zum Ausführen einer SQL-Datei
async function executeFile(filePath) {
try {
const fullPath = join(process.cwd(), filePath);
console.log(`Führe SQL-Datei aus: ${fullPath}`);
if (!fs.existsSync(fullPath)) {
console.error(`Fehler: Datei ${fullPath} existiert nicht.`);
return;
}
const query = fs.readFileSync(fullPath, 'utf8');
await executeQuery(query);
} catch (error) {
console.error('Fehler beim Lesen oder Ausführen der Datei:', error.message);
}
}
// Funktion zum Anzeigen der Tabellenliste
async function listTables() {
try {
const query = `
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name;
`;
const { data, error } = await supabase.rpc('execute_sql', { query });
if (error) {
console.error('Fehler beim Abrufen der Tabellenliste:', error.message);
return;
}
console.log('Verfügbare Tabellen:');
data.forEach((row, index) => {
console.log(`${index + 1}. ${row.table_name}`);
});
} catch (error) {
console.error('Unerwarteter Fehler:', error.message);
}
}
// Funktion zum Anzeigen der Tabellenstruktur
async function describeTable(tableName) {
try {
const query = `
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = '${tableName}'
ORDER BY ordinal_position;
`;
const { data, error } = await supabase.rpc('execute_sql', { query });
if (error) {
console.error(`Fehler beim Beschreiben der Tabelle ${tableName}:`, error.message);
return;
}
console.log(`Struktur der Tabelle ${tableName}:`);
console.table(data);
} catch (error) {
console.error('Unerwarteter Fehler:', error.message);
}
}
// Hauptmenü
function showMenu() {
console.log('\n--- Supabase CLI ---');
console.log('1. SQL-Abfrage ausführen');
console.log('2. SQL-Datei ausführen');
console.log('3. Tabellenliste anzeigen');
console.log('4. Tabellenstruktur anzeigen');
console.log('5. Beenden');
rl.question('\nWähle eine Option (1-5): ', async (answer) => {
switch (answer.trim()) {
case '1':
rl.question('Gib deine SQL-Abfrage ein: ', async (query) => {
await executeQuery(query);
showMenu();
});
break;
case '2':
rl.question('Gib den Pfad zur SQL-Datei ein: ', async (filePath) => {
await executeFile(filePath);
showMenu();
});
break;
case '3':
await listTables();
showMenu();
break;
case '4':
rl.question('Gib den Tabellennamen ein: ', async (tableName) => {
await describeTable(tableName);
showMenu();
});
break;
case '5':
console.log('Auf Wiedersehen!');
rl.close();
process.exit(0);
break;
default:
console.log('Ungültige Option. Bitte wähle 1-5.');
showMenu();
break;
}
});
}
// Starte das Programm
console.log('Verbindung zu Supabase hergestellt.');
console.log(`URL: ${supabaseUrl}`);
showMenu();

View file

@ -0,0 +1,112 @@
// Skript zum Aktualisieren der Modelle in der Supabase-Datenbank
import { createClient } from '@supabase/supabase-js';
import dotenv from 'dotenv';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
// Lade Umgebungsvariablen aus .env
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Supabase-Client erstellen
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL;
const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseKey) {
console.error('Fehler: EXPO_PUBLIC_SUPABASE_URL und EXPO_PUBLIC_SUPABASE_ANON_KEY müssen in der .env-Datei definiert sein.');
process.exit(1);
}
const supabase = createClient(supabaseUrl, supabaseKey);
// Modelle, die wir in die Datenbank einfügen wollen
const models = [
{
id: '550e8400-e29b-41d4-a716-446655440000',
name: 'GPT-O3-Mini',
description: 'Azure OpenAI O3-Mini: Effizientes Modell für schnelle Antworten.',
parameters: {
temperature: 0.7,
max_tokens: 800,
provider: 'azure',
deployment: 'gpt-o3-mini-se',
endpoint: 'https://memoroseopenai.openai.azure.com',
api_version: '2024-12-01-preview'
}
},
{
id: '550e8400-e29b-41d4-a716-446655440004',
name: 'GPT-4o-Mini',
description: 'Azure OpenAI GPT-4o-Mini: Kompaktes, leistungsstarkes KI-Modell.',
parameters: {
temperature: 0.7,
max_tokens: 1000,
provider: 'azure',
deployment: 'gpt-4o-mini-se',
endpoint: 'https://memoroseopenai.openai.azure.com',
api_version: '2024-12-01-preview'
}
},
{
id: '550e8400-e29b-41d4-a716-446655440005',
name: 'GPT-4o',
description: 'Azure OpenAI GPT-4o: Das fortschrittlichste multimodale KI-Modell.',
parameters: {
temperature: 0.7,
max_tokens: 1200,
provider: 'azure',
deployment: 'gpt-4o-se',
endpoint: 'https://memoroseopenai.openai.azure.com',
api_version: '2024-12-01-preview'
}
}
];
async function updateModels() {
console.log('Aktualisiere Modelle in der Supabase-Datenbank...');
// Prüfe, ob die Tabelle existiert
const { error: tableError } = await supabase
.from('models')
.select('id')
.limit(1);
if (tableError) {
console.error('Fehler beim Zugriff auf die models-Tabelle:', tableError.message);
console.log('Erstelle models-Tabelle...');
// Erstelle die Tabelle, falls sie nicht existiert
const { error: createError } = await supabase.rpc('create_models_table');
if (createError) {
console.error('Fehler beim Erstellen der models-Tabelle:', createError.message);
return;
}
}
// Füge die Modelle ein oder aktualisiere sie
for (const model of models) {
const { error } = await supabase
.from('models')
.upsert(model, { onConflict: 'id' });
if (error) {
console.error(`Fehler beim Aktualisieren des Modells ${model.name}:`, error.message);
} else {
console.log(`Modell ${model.name} erfolgreich aktualisiert.`);
}
}
console.log('Modellaktualisierung abgeschlossen.');
}
// Führe die Funktion aus
updateModels()
.catch(error => {
console.error('Unerwarteter Fehler:', error);
})
.finally(() => {
process.exit(0);
});

View file

@ -0,0 +1,29 @@
-- Löschen der vorhandenen Modelle (optional)
-- DELETE FROM models;
-- Einfügen der neuen Modelle mit UUIDs
INSERT INTO models (id, name, description, parameters)
VALUES
(
'550e8400-e29b-41d4-a716-446655440000',
'GPT-O3-Mini',
'Azure OpenAI O3-Mini: Effizientes Modell für schnelle Antworten.',
'{"temperature": 0.7, "max_tokens": 800, "provider": "azure", "deployment": "gpt-o3-mini-se", "endpoint": "https://memoroseopenai.openai.azure.com", "api_version": "2024-12-01-preview"}'
),
(
'550e8400-e29b-41d4-a716-446655440004',
'GPT-4o-Mini',
'Azure OpenAI GPT-4o-Mini: Kompaktes, leistungsstarkes KI-Modell.',
'{"temperature": 0.7, "max_tokens": 1000, "provider": "azure", "deployment": "gpt-4o-mini-se", "endpoint": "https://memoroseopenai.openai.azure.com", "api_version": "2024-12-01-preview"}'
),
(
'550e8400-e29b-41d4-a716-446655440005',
'GPT-4o',
'Azure OpenAI GPT-4o: Das fortschrittlichste multimodale KI-Modell.',
'{"temperature": 0.7, "max_tokens": 1200, "provider": "azure", "deployment": "gpt-4o-se", "endpoint": "https://memoroseopenai.openai.azure.com", "api_version": "2024-12-01-preview"}'
)
ON CONFLICT (id)
DO UPDATE SET
name = EXCLUDED.name,
description = EXCLUDED.description,
parameters = EXCLUDED.parameters;