Files
mc_cars_gmbh_infraestructure/supabase/migrations/01-init.sql
T
Lago 61517879e1 feat: Add Supabase configuration and migrations for MC Cars application
- Create Kong declarative configuration for routing and authentication.
- Implement initialization script to set up the database.
- Add SQL migration for initializing roles, schemas, and seeding vehicle data.
- Create leads and customers tables with appropriate policies and functions for CRM.
- Seed admin user and configure storage bucket with RLS policies.
2026-04-17 17:50:57 +02:00

199 lines
9.2 KiB
PL/PgSQL

-- =============================================================================
-- MC Cars — Postgres bootstrap.
-- Creates the Supabase service roles that GoTrue / PostgREST / Storage expect,
-- installs required extensions, and sets up app schema + RLS + storage policies
-- + admin seed + sample fleet.
-- Runs once on first `docker compose up`.
-- =============================================================================
-- The Postgres connection is authenticated as role `supabase_admin` (POSTGRES_USER),
-- so we need it to be a superuser for the rest of this script to work. That is
-- handled by POSTGRES_USER=supabase_admin in compose.
create extension if not exists pgcrypto;
create extension if not exists "uuid-ossp";
-- Make the password from the shell wrapper available to the DO block below.
select set_config('mccars.pg_password', :'pg_password', false);
-- -----------------------------------------------------------------------------
-- Supabase service roles
-- -----------------------------------------------------------------------------
do $roles$
declare
pw text := current_setting('mccars.pg_password', true);
begin
if pw is null or pw = '' then
raise exception 'mccars.pg_password is not set';
end if;
-- anon (used by PostgREST for unauthenticated requests)
if not exists (select 1 from pg_roles where rolname = 'anon') then
execute 'create role anon nologin noinherit';
end if;
-- authenticated (role the JWT "authenticated" maps to)
if not exists (select 1 from pg_roles where rolname = 'authenticated') then
execute 'create role authenticated nologin noinherit';
end if;
-- service_role (full access; never exposed to the browser)
if not exists (select 1 from pg_roles where rolname = 'service_role') then
execute 'create role service_role nologin noinherit bypassrls';
end if;
-- authenticator (PostgREST logs in as this and switches role per JWT)
if not exists (select 1 from pg_roles where rolname = 'authenticator') then
execute format('create role authenticator login noinherit password %L', pw);
else
execute format('alter role authenticator with login noinherit password %L', pw);
end if;
-- supabase_auth_admin (GoTrue logs in with this, needs schema auth)
if not exists (select 1 from pg_roles where rolname = 'supabase_auth_admin') then
execute format('create role supabase_auth_admin login createrole password %L', pw);
else
execute format('alter role supabase_auth_admin with login createrole password %L', pw);
end if;
-- supabase_storage_admin (Storage service logs in with this)
if not exists (select 1 from pg_roles where rolname = 'supabase_storage_admin') then
execute format('create role supabase_storage_admin login createrole password %L', pw);
else
execute format('alter role supabase_storage_admin with login createrole password %L', pw);
end if;
-- Let authenticator impersonate app roles.
execute 'grant anon, authenticated, service_role to authenticator';
end
$roles$;
-- -----------------------------------------------------------------------------
-- Schemas for GoTrue / Storage (they create their own objects, but own schema)
-- -----------------------------------------------------------------------------
create schema if not exists auth authorization supabase_auth_admin;
create schema if not exists storage authorization supabase_storage_admin;
create schema if not exists _realtime authorization postgres;
grant usage on schema auth to service_role, authenticated, anon;
grant usage on schema storage to service_role, authenticated, anon;
grant all on schema _realtime to postgres;
-- Allow service admins to create/alter objects for their own migrations.
grant create, connect on database postgres to supabase_auth_admin, supabase_storage_admin;
grant all on schema auth to supabase_auth_admin;
grant all on schema storage to supabase_storage_admin;
-- Storage-api's migration process expects to see public schema too.
grant usage, create on schema public to supabase_storage_admin, supabase_auth_admin;
-- -----------------------------------------------------------------------------
-- Application schema: public.vehicles
-- -----------------------------------------------------------------------------
create table if not exists public.vehicles (
id uuid primary key default gen_random_uuid(),
brand text not null,
model text not null,
power_hp integer not null default 0,
top_speed_kmh integer not null default 0,
acceleration text not null default '',
seats integer not null default 2,
daily_price_eur integer not null default 0,
location text not null default 'Steiermark (TBD)',
description_de text not null default '',
description_en text not null default '',
photo_url text not null default '',
photo_path text,
sort_order integer not null default 100,
is_active boolean not null default true,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists vehicles_active_sort_idx
on public.vehicles (is_active, sort_order);
create or replace function public.tg_touch_updated_at() returns trigger
language plpgsql as $$
begin
new.updated_at := now();
return new;
end;
$$;
drop trigger if exists vehicles_touch on public.vehicles;
create trigger vehicles_touch
before update on public.vehicles
for each row execute function public.tg_touch_updated_at();
alter table public.vehicles enable row level security;
drop policy if exists "vehicles_public_read" on public.vehicles;
drop policy if exists "vehicles_admin_read_all" on public.vehicles;
drop policy if exists "vehicles_admin_insert" on public.vehicles;
drop policy if exists "vehicles_admin_update" on public.vehicles;
drop policy if exists "vehicles_admin_delete" on public.vehicles;
create policy "vehicles_public_read"
on public.vehicles for select
using (is_active = true);
create policy "vehicles_admin_read_all"
on public.vehicles for select
to authenticated using (true);
create policy "vehicles_admin_insert"
on public.vehicles for insert
to authenticated with check (true);
create policy "vehicles_admin_update"
on public.vehicles for update
to authenticated using (true) with check (true);
create policy "vehicles_admin_delete"
on public.vehicles for delete
to authenticated using (true);
grant select on public.vehicles to anon, authenticated;
grant insert, update, delete on public.vehicles to authenticated;
grant all on public.vehicles to service_role;
-- -----------------------------------------------------------------------------
-- Seed sample fleet (admin can replace any row / photo via the UI)
-- -----------------------------------------------------------------------------
insert into public.vehicles
(brand, model, power_hp, top_speed_kmh, acceleration, seats,
daily_price_eur, location, description_de, description_en, photo_url, sort_order)
values
('Porsche','911 GT3', 510, 318, '3.4s', 2, 890, 'Steiermark (TBD)',
'Puristischer Hochdrehzahl-Saugmotor und kompromissloser Motorsport-Charakter.',
'Pure high-revving naturally aspirated engine with uncompromising motorsport character.',
'https://images.unsplash.com/photo-1611821064430-0d40291d0f0b?auto=format&fit=crop&w=1400&q=80',
10),
('Lamborghini','Huracan EVO', 640, 325, '2.9s', 2, 990, 'Steiermark (TBD)',
'V10 mit 640 PS, scharfes Design und kompromisslose Performance auf Strasse und Rennstrecke.',
'V10 with 640 hp, sharp design and uncompromising performance on road and track.',
'https://images.unsplash.com/photo-1544636331-e26879cd4d9b?auto=format&fit=crop&w=1400&q=80',
20),
('Audi','RS6 Performance', 630, 305, '3.4s', 5, 540, 'Steiermark (TBD)',
'Alltagstauglicher Kombi mit brutaler V8-Biturbo-Power und Allradantrieb.',
'Everyday-ready estate with brutal twin-turbo V8 power and quattro AWD.',
'https://images.unsplash.com/photo-1606664515524-ed2f786a0bd6?auto=format&fit=crop&w=1400&q=80',
30),
('BMW','M4 Competition', 530, 290, '3.5s', 4, 430, 'Steiermark (TBD)',
'Reihensechszylinder-Biturbo mit praeziser Lenkung und sportlichem Fahrwerk.',
'Twin-turbo inline-six with precise steering and sporty chassis.',
'https://images.unsplash.com/photo-1555215695-3004980ad54e?auto=format&fit=crop&w=1400&q=80',
40),
('Nissan','GT-R R35', 570, 315, '2.8s', 4, 510, 'Steiermark (TBD)',
'Ikonischer Allrad-Supersportler mit Twin-Turbo V6 und brutalem Antritt.',
'Iconic AWD supercar with twin-turbo V6 and ferocious launch.',
'https://images.unsplash.com/photo-1626668893632-6f3a4466d22f?auto=format&fit=crop&w=1400&q=80',
50),
('Mercedes-AMG','G63', 585, 220, '4.5s', 5, 620, 'Steiermark (TBD)',
'Legendaere G-Klasse mit V8-Biturbo-Performance und unverkennbarem Design.',
'Legendary G-Class with V8 biturbo performance and unmistakable design.',
'https://images.unsplash.com/photo-1606611013016-969c19ba27bb?auto=format&fit=crop&w=1400&q=80',
60)
on conflict do nothing;