🚀 Feat(Core): Migración oficial y total B a Supabase (Auth, DB, APIs) + Eliminación de Backend Python y Fixes Firebase + Soporte Vite Vercel
This commit is contained in:
299
supabase_schema.sql
Normal file
299
supabase_schema.sql
Normal file
@ -0,0 +1,299 @@
|
||||
-- Extensions
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Enums
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE routestatus AS ENUM ('ACTIVE', 'INACTIVE', 'MAINTENANCE');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE stoptype AS ENUM ('TERMINAL', 'REGULAR', 'EXPRESS_ONLY');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE busscheduletype AS ENUM ('WEEKDAY', 'WEEKEND', 'HOLIDAY');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE userrole AS ENUM ('ADMIN', 'PASSENGER', 'DRIVER', 'PROMOTER');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE vehicletype AS ENUM ('taxi', 'bus');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE usercouponstatus AS ENUM ('claimed', 'redeemed', 'expired');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
-- 1. Users
|
||||
CREATE TABLE IF NOT EXISTS public.users (
|
||||
id UUID PRIMARY KEY, -- Will link to auth.users.id
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
full_name TEXT NOT NULL,
|
||||
role userrole DEFAULT 'PASSENGER'::userrole,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
is_verified BOOLEAN DEFAULT false,
|
||||
profile_photo_url TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 2. Driver Profiles
|
||||
CREATE TABLE IF NOT EXISTS public.driver_profiles (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID REFERENCES public.users(id) ON DELETE CASCADE,
|
||||
cedula TEXT NOT NULL,
|
||||
vehicle_type vehicletype NOT NULL,
|
||||
license_plate TEXT NOT NULL,
|
||||
photo_url TEXT,
|
||||
vehicle_photo_url TEXT,
|
||||
cooperative_name TEXT,
|
||||
shift TEXT,
|
||||
payment_methods TEXT,
|
||||
speaks_english BOOLEAN DEFAULT false
|
||||
);
|
||||
|
||||
-- 3. Bus Stops
|
||||
CREATE TABLE IF NOT EXISTS public.bus_stops (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name TEXT NOT NULL,
|
||||
latitude FLOAT NOT NULL,
|
||||
longitude FLOAT NOT NULL,
|
||||
city TEXT NOT NULL,
|
||||
address TEXT,
|
||||
stop_type stoptype NOT NULL,
|
||||
has_shelter BOOLEAN DEFAULT false,
|
||||
has_seating BOOLEAN DEFAULT false,
|
||||
is_accessible BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 4. Routes
|
||||
CREATE TABLE IF NOT EXISTS public.routes (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
origin_city TEXT NOT NULL,
|
||||
destination_city TEXT NOT NULL,
|
||||
distance_km FLOAT,
|
||||
estimated_duration_minutes INTEGER,
|
||||
average_speed_kmh FLOAT,
|
||||
color TEXT DEFAULT '#FEE715',
|
||||
direction TEXT DEFAULT 'outbound',
|
||||
status routestatus DEFAULT 'ACTIVE'::routestatus,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 5. Route Stops
|
||||
CREATE TABLE IF NOT EXISTS public.route_stops (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
route_id UUID REFERENCES public.routes(id) ON DELETE CASCADE,
|
||||
stop_id UUID REFERENCES public.bus_stops(id) ON DELETE CASCADE,
|
||||
stop_order INTEGER NOT NULL,
|
||||
travel_time_minutes INTEGER,
|
||||
stop_delay_minutes INTEGER DEFAULT 0,
|
||||
is_pickup_point BOOLEAN DEFAULT false,
|
||||
is_dropoff_point BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 6. Bus Schedules
|
||||
CREATE TABLE IF NOT EXISTS public.bus_schedules (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
route_id UUID REFERENCES public.routes(id) ON DELETE CASCADE,
|
||||
departure_time TIME NOT NULL,
|
||||
frequency_minutes INTEGER,
|
||||
schedule_type busscheduletype NOT NULL,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
is_published BOOLEAN DEFAULT true,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 7. Businesses
|
||||
CREATE TABLE IF NOT EXISTS public.businesses (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name TEXT NOT NULL,
|
||||
address TEXT,
|
||||
phone TEXT,
|
||||
image_url TEXT,
|
||||
social_media TEXT,
|
||||
category TEXT,
|
||||
latitude FLOAT,
|
||||
longitude FLOAT,
|
||||
area TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 8. Coupons
|
||||
CREATE TABLE IF NOT EXISTS public.coupons (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
business_id UUID REFERENCES public.businesses(id) ON DELETE CASCADE,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
image_url TEXT,
|
||||
social_media TEXT,
|
||||
terms TEXT,
|
||||
discount_percentage FLOAT,
|
||||
discount_amount FLOAT,
|
||||
category TEXT,
|
||||
valid_from TIMESTAMPTZ,
|
||||
valid_until TIMESTAMPTZ,
|
||||
is_active BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 9. Shuttles
|
||||
CREATE TABLE IF NOT EXISTS public.shuttles (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
route_name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
origin TEXT NOT NULL,
|
||||
destination TEXT NOT NULL,
|
||||
vehicle_type TEXT NOT NULL,
|
||||
company_name TEXT,
|
||||
trip_type TEXT DEFAULT 'one_way',
|
||||
price_per_person FLOAT,
|
||||
price_private_trip FLOAT,
|
||||
estimated_duration TEXT,
|
||||
departure_times TEXT,
|
||||
contact_whatsapp TEXT NOT NULL,
|
||||
phone_number TEXT,
|
||||
english_speaking BOOLEAN DEFAULT false,
|
||||
image_url TEXT,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 10. Taxis
|
||||
CREATE TABLE IF NOT EXISTS public.taxis (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
owner_name TEXT NOT NULL,
|
||||
phone_number TEXT NOT NULL,
|
||||
license_plate TEXT NOT NULL,
|
||||
cooperative TEXT,
|
||||
corregimiento TEXT NOT NULL,
|
||||
shift TEXT NOT NULL,
|
||||
rating FLOAT,
|
||||
english_speaking BOOLEAN DEFAULT false,
|
||||
image_url TEXT,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 11. Favorites
|
||||
CREATE TABLE IF NOT EXISTS public.favorites (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID REFERENCES public.users(id) ON DELETE CASCADE,
|
||||
item_type TEXT NOT NULL,
|
||||
item_id UUID NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 12. User Coupons
|
||||
CREATE TABLE IF NOT EXISTS public.user_coupons (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID REFERENCES public.users(id) ON DELETE CASCADE,
|
||||
coupon_id UUID REFERENCES public.coupons(id) ON DELETE CASCADE,
|
||||
status usercouponstatus DEFAULT 'claimed'::usercouponstatus,
|
||||
redemption_code TEXT NOT NULL,
|
||||
claimed_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
redeemed_at TIMESTAMPTZ,
|
||||
UNIQUE(user_id, coupon_id)
|
||||
);
|
||||
|
||||
-- TRIGGER FOR AUTH.USERS -> PUBLIC.USERS
|
||||
CREATE OR REPLACE FUNCTION public.handle_new_user()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
INSERT INTO public.users (id, email, full_name, role)
|
||||
VALUES (
|
||||
new.id,
|
||||
new.email,
|
||||
COALESCE(new.raw_user_meta_data->>'full_name', new.email),
|
||||
COALESCE((new.raw_user_meta_data->>'role')::userrole, 'PASSENGER'::userrole)
|
||||
);
|
||||
RETURN new;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Trigger firing when a new user signs up
|
||||
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
|
||||
CREATE TRIGGER on_auth_user_created
|
||||
AFTER INSERT ON auth.users
|
||||
FOR EACH ROW EXECUTE PROCEDURE public.handle_new_user();
|
||||
|
||||
-- SET DEFAULT RLS (Row Level Security) TO EVERY TABLE
|
||||
ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.routes ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.bus_stops ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.route_stops ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.bus_schedules ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.shuttles ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.businesses ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.coupons ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.user_coupons ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.taxis ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.favorites ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.driver_profiles ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- SIMPLE POLICIES (Read for all, Insert/Update/Delete requires auth)
|
||||
-- You can tighten these up later, this gets you going securely.
|
||||
|
||||
-- Routes, Stops, Shuttles, Taxis, Businesses, Coupons: public read
|
||||
CREATE POLICY "Public Read" ON public.routes FOR SELECT USING (true);
|
||||
CREATE POLICY "Public Read" ON public.bus_stops FOR SELECT USING (true);
|
||||
CREATE POLICY "Public Read" ON public.route_stops FOR SELECT USING (true);
|
||||
CREATE POLICY "Public Read" ON public.bus_schedules FOR SELECT USING (true);
|
||||
CREATE POLICY "Public Read" ON public.shuttles FOR SELECT USING (true);
|
||||
CREATE POLICY "Public Read" ON public.businesses FOR SELECT USING (true);
|
||||
CREATE POLICY "Public Read" ON public.coupons FOR SELECT USING (true);
|
||||
CREATE POLICY "Public Read" ON public.taxis FOR SELECT USING (true);
|
||||
CREATE POLICY "Public Read" ON public.driver_profiles FOR SELECT USING (true);
|
||||
|
||||
-- Users can read their own data, Admins can read everything
|
||||
CREATE POLICY "Users can view own data" ON public.users FOR SELECT USING (auth.uid() = id);
|
||||
CREATE POLICY "Users can update own data" ON public.users FOR UPDATE USING (auth.uid() = id);
|
||||
|
||||
-- Allow admins to manage (This policy assumes admins are users with role = 'ADMIN')
|
||||
CREATE OR REPLACE FUNCTION is_admin() RETURNS BOOLEAN AS $$
|
||||
BEGIN
|
||||
RETURN EXISTS (SELECT 1 FROM public.users WHERE id = auth.uid() AND role = 'ADMIN');
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
CREATE POLICY "Admins full access" ON public.routes FOR ALL USING (is_admin());
|
||||
CREATE POLICY "Admins full access" ON public.bus_stops FOR ALL USING (is_admin());
|
||||
CREATE POLICY "Admins full access" ON public.route_stops FOR ALL USING (is_admin());
|
||||
CREATE POLICY "Admins full access" ON public.bus_schedules FOR ALL USING (is_admin());
|
||||
CREATE POLICY "Admins full access" ON public.shuttles FOR ALL USING (is_admin());
|
||||
CREATE POLICY "Admins full access" ON public.businesses FOR ALL USING (is_admin());
|
||||
CREATE POLICY "Admins full access" ON public.coupons FOR ALL USING (is_admin());
|
||||
CREATE POLICY "Admins full access" ON public.taxis FOR ALL USING (is_admin());
|
||||
CREATE POLICY "Admins full access" ON public.users FOR ALL USING (is_admin());
|
||||
|
||||
-- Favorites and User Coupons
|
||||
CREATE POLICY "Users can view own favorites" ON public.favorites FOR SELECT USING (auth.uid() = user_id);
|
||||
CREATE POLICY "Users can manage own favorites" ON public.favorites FOR ALL USING (auth.uid() = user_id);
|
||||
|
||||
CREATE POLICY "Users can view own coupons" ON public.user_coupons FOR SELECT USING (auth.uid() = user_id);
|
||||
CREATE POLICY "Users can manage own coupons" ON public.user_coupons FOR ALL USING (auth.uid() = user_id);
|
||||
Reference in New Issue
Block a user