-- CREATE FUNCTION public.check_database_integrity CREATE OR REPLACE FUNCTION public.check_database_integrity() RETURNS jsonb SECURITY DEFINER AS $$ DECLARE profiles_exist boolean; end_customers_exist boolean; pos_modules_exist boolean; licenses_exist boolean; profiles_count bigint := 0; end_customers_count bigint := 0; pos_modules_count bigint := 0; licenses_count bigint := 0; fk_errors_count bigint := 0; result jsonb; BEGIN -- Check table existence SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'profiles') INTO profiles_exist; SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'end_customers') INTO end_customers_exist; SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'pos_modules') INTO pos_modules_exist; SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'licenses') INTO licenses_exist; -- Count rows if table exists IF profiles_exist THEN EXECUTE 'SELECT count(*) FROM public.profiles' INTO profiles_count; END IF; IF end_customers_exist THEN EXECUTE 'SELECT count(*) FROM public.end_customers' INTO end_customers_count; END IF; IF pos_modules_exist THEN EXECUTE 'SELECT count(*) FROM public.pos_modules' INTO pos_modules_count; END IF; IF licenses_exist THEN EXECUTE 'SELECT count(*) FROM public.licenses' INTO licenses_count; END IF; -- Count foreign key errors (orphaned licenses) IF licenses_exist AND end_customers_exist 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; -- Build JSON result result := jsonb_build_object( 'tables', jsonb_build_object( 'profiles', jsonb_build_object('exists', profiles_exist, 'count', profiles_count), 'end_customers', jsonb_build_object('exists', end_customers_exist, 'count', end_customers_count), 'pos_modules', jsonb_build_object('exists', pos_modules_exist, 'count', pos_modules_count), 'licenses', jsonb_build_object('exists', licenses_exist, 'count', licenses_count) ), 'errors', jsonb_build_object( 'foreign_keys', fk_errors_count ) ); RETURN result; END; $$ LANGUAGE plpgsql; -- CREATE FUNCTION public.repair_database_schema CREATE OR REPLACE FUNCTION public.repair_database_schema() RETURNS jsonb SECURITY DEFINER AS $$ DECLARE repaired_tables text[] := '{}'; result jsonb; BEGIN -- 1. profiles table (should exist, but check just in case) IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'profiles') THEN CREATE TABLE public.profiles ( id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, first_name TEXT, last_name TEXT, company_name TEXT, vat_id TEXT, address TEXT, city TEXT, zip_code TEXT, updated_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL ); repaired_tables := array_append(repaired_tables, 'profiles'); END IF; -- 2. end_customers table IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'end_customers') THEN CREATE TABLE public.end_customers ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), partner_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE, company_name TEXT NOT NULL, vat_id TEXT, first_name TEXT, last_name TEXT, street TEXT, zip TEXT, city TEXT, is_anonymized BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); repaired_tables := array_append(repaired_tables, 'end_customers'); END IF; -- 3. pos_modules table IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'pos_modules') THEN CREATE TABLE public.pos_modules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, price NUMERIC(10, 2) NOT NULL DEFAULT 0.00, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); repaired_tables := array_append(repaired_tables, 'pos_modules'); END IF; -- 4. licenses table IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'licenses') THEN CREATE TABLE public.licenses ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), end_customer_id UUID REFERENCES public.end_customers(id) ON DELETE CASCADE, pos_module_id UUID REFERENCES public.pos_modules(id) ON DELETE CASCADE, license_key TEXT NOT NULL UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); repaired_tables := array_append(repaired_tables, 'licenses'); END IF; -- Enable RLS on all tables ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY; ALTER TABLE public.end_customers ENABLE ROW LEVEL SECURITY; ALTER TABLE public.pos_modules ENABLE ROW LEVEL SECURITY; ALTER TABLE public.licenses ENABLE ROW LEVEL SECURITY; -- Recreate RLS Policies -- profiles Policies DROP POLICY IF EXISTS "Users can view their own profile" ON public.profiles; CREATE POLICY "Users can view their own profile" ON public.profiles FOR SELECT USING (auth.uid() = id); DROP POLICY IF EXISTS "Users can update their own profile" ON public.profiles; CREATE POLICY "Users can update their own profile" ON public.profiles FOR UPDATE USING (auth.uid() = id); DROP POLICY IF EXISTS "Users can insert their own profile" ON public.profiles; CREATE POLICY "Users can insert their own profile" ON public.profiles FOR INSERT WITH CHECK (auth.uid() = id); DROP POLICY IF EXISTS "Admins can view all profiles" ON public.profiles; CREATE POLICY "Admins can view all profiles" ON public.profiles FOR SELECT USING (auth.role() = 'authenticated'); -- end_customers Policies DROP POLICY IF EXISTS "Partner sehen nur eigene Endkunden" ON public.end_customers; CREATE POLICY "Partner sehen nur eigene Endkunden" ON public.end_customers FOR ALL USING (auth.uid() = partner_id) WITH CHECK (auth.uid() = partner_id); -- pos_modules Policies DROP POLICY IF EXISTS "Allow authenticated read on pos_modules" ON public.pos_modules; CREATE POLICY "Allow authenticated read on pos_modules" ON public.pos_modules FOR SELECT USING (auth.role() = 'authenticated'); -- licenses Policies DROP POLICY IF EXISTS "Partner sehen Lizenzen eigener Kunden" ON public.licenses; CREATE POLICY "Partner sehen Lizenzen eigener Kunden" ON public.licenses FOR SELECT USING ( EXISTS ( SELECT 1 FROM public.end_customers c WHERE c.id = licenses.end_customer_id AND c.partner_id = auth.uid() ) ); DROP POLICY IF EXISTS "Partner erstellen Lizenzen eigener Kunden" ON public.licenses; CREATE POLICY "Partner erstellen Lizenzen eigener Kunden" ON public.licenses FOR INSERT WITH CHECK ( EXISTS ( SELECT 1 FROM public.end_customers c WHERE c.id = licenses.end_customer_id AND c.partner_id = auth.uid() ) ); result := jsonb_build_object( 'repaired', to_jsonb(repaired_tables), 'success', true ); RETURN result; END; $$ LANGUAGE plpgsql; -- CREATE FUNCTION public.optimize_database_indices CREATE OR REPLACE FUNCTION public.optimize_database_indices() RETURNS jsonb SECURITY DEFINER AS $$ BEGIN REINDEX SCHEMA public; RETURN jsonb_build_object('success', true, 'message', 'Schema public successfully reindexed.'); END; $$ LANGUAGE plpgsql;