diff --git a/shop/app/admin/tools/page.tsx b/shop/app/admin/tools/page.tsx index ff9e6a2..f09255f 100644 --- a/shop/app/admin/tools/page.tsx +++ b/shop/app/admin/tools/page.tsx @@ -20,12 +20,7 @@ interface TableStatus { } interface IntegrityData { - tables: { - profiles: TableStatus; - end_customers: TableStatus; - pos_modules: TableStatus; - licenses: TableStatus; - }; + tables: Record; errors: { foreign_keys: number; }; diff --git a/shop/lib/actions/admin.ts b/shop/lib/actions/admin.ts index 2426bec..4aa8e8e 100644 --- a/shop/lib/actions/admin.ts +++ b/shop/lib/actions/admin.ts @@ -2,6 +2,7 @@ import { createClient } from '@/lib/supabase/server' import { verifyAdmin } from '@/lib/actions/auth' +import { Client } from 'pg' export async function getDatabaseIntegrity() { try { @@ -36,12 +37,20 @@ export async function repairDatabaseSchema() { export async function optimizeDatabaseIndices() { try { await verifyAdmin() - const supabase = await createClient() - const { data, error } = await supabase.rpc('optimize_database_indices') - if (error) { - return { success: false, error: error.message } - } - return { success: true, data } + + // REINDEX cannot be run inside a transaction block (such as inside a PL/pgSQL function). + // Therefore, we connect directly using pg client and execute raw query. + const connectionString = process.env.DATABASE_URL || 'postgresql://postgres:postgres@localhost:54322/postgres'; + const client = new Client({ + connectionString, + connectionTimeoutMillis: 10000, + }); + + await client.connect(); + await client.query('REINDEX SCHEMA public;'); + await client.end(); + + return { success: true } } catch (err: any) { console.error("Error in optimizeDatabaseIndices:", err) return { success: false, error: err.message || "Unerwarteter Fehler bei der Indexoptimierung." } diff --git a/shop/supabase/migrations/20260703140500_update_integrity_tables.sql b/shop/supabase/migrations/20260703140500_update_integrity_tables.sql new file mode 100644 index 0000000..d6e702b --- /dev/null +++ b/shop/supabase/migrations/20260703140500_update_integrity_tables.sql @@ -0,0 +1,63 @@ +-- Update check_database_integrity to check all tables +CREATE OR REPLACE FUNCTION public.check_database_integrity() +RETURNS jsonb +SECURITY DEFINER +AS $$ +DECLARE + tables_to_check text[] := ARRAY[ + 'users', + 'settings', + 'companies', + 'categories', + 'products', + 'product_modules', + 'orders', + 'profiles', + 'end_customers', + 'licenses', + 'pos_modules' + ]; + t text; + t_exists boolean; + t_count bigint; + tables_result jsonb := jsonb_build_object(); + fk_errors_count bigint := 0; + result jsonb; +BEGIN + FOREACH t IN ARRAY tables_to_check LOOP + SELECT EXISTS ( + SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = t + ) INTO t_exists; + + t_count := 0; + IF t_exists THEN + EXECUTE format('SELECT count(*) FROM public.%I', t) INTO t_count; + END IF; + + tables_result := tables_result || jsonb_build_object(t, jsonb_build_object('exists', t_exists, 'count', t_count)); + END LOOP; + + -- Count foreign key errors (orphaned licenses) + SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'licenses') INTO t_exists; + IF t_exists THEN + SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'end_customers') INTO t_exists; + IF t_exists THEN + EXECUTE ' + SELECT count(*) + FROM public.licenses l + LEFT JOIN public.end_customers c ON l.end_customer_id = c.id + WHERE c.id IS NULL AND l.end_customer_id IS NOT NULL + ' INTO fk_errors_count; + END IF; + END IF; + + result := jsonb_build_object( + 'tables', tables_result, + 'errors', jsonb_build_object( + 'foreign_keys', fk_errors_count + ) + ); + + RETURN result; +END; +$$ LANGUAGE plpgsql;