feat: schema multi-tenant (tenants, app_config, tenant_id backfill, RLS)
- Novas tabelas reserva_hotel.tenants e reserva_hotel.app_config - Coluna tenant_id adicionada em todas as tabelas de catalogo/reservas - Tenant default 'grupo-1001' criado + backfill das rows existentes - RLS + grants pro anon ler tenants e app_config - Types TS regenerados Aplicado via MCP. Arquivos de migration sao source of truth historica.
This commit is contained in:
parent
45ffd9110c
commit
e912563196
@ -14,6 +14,77 @@ export type Database = {
|
||||
}
|
||||
reserva_hotel: {
|
||||
Tables: {
|
||||
app_config: {
|
||||
Row: {
|
||||
cor_fundo: string
|
||||
cor_primaria: string
|
||||
cor_secundaria: string
|
||||
cor_superficie: string
|
||||
cor_texto: string
|
||||
created_at: string
|
||||
favicon_url: string | null
|
||||
fonte_corpo: string
|
||||
fonte_display: string
|
||||
footer_text: string | null
|
||||
id: number
|
||||
logo_url: string | null
|
||||
nome_rede: string
|
||||
subtitulo_hero: string | null
|
||||
tagline: string | null
|
||||
tenant_id: number
|
||||
titulo_hero: string
|
||||
updated_at: string
|
||||
}
|
||||
Insert: {
|
||||
cor_fundo?: string
|
||||
cor_primaria?: string
|
||||
cor_secundaria?: string
|
||||
cor_superficie?: string
|
||||
cor_texto?: string
|
||||
created_at?: string
|
||||
favicon_url?: string | null
|
||||
fonte_corpo?: string
|
||||
fonte_display?: string
|
||||
footer_text?: string | null
|
||||
id?: number
|
||||
logo_url?: string | null
|
||||
nome_rede: string
|
||||
subtitulo_hero?: string | null
|
||||
tagline?: string | null
|
||||
tenant_id: number
|
||||
titulo_hero: string
|
||||
updated_at?: string
|
||||
}
|
||||
Update: {
|
||||
cor_fundo?: string
|
||||
cor_primaria?: string
|
||||
cor_secundaria?: string
|
||||
cor_superficie?: string
|
||||
cor_texto?: string
|
||||
created_at?: string
|
||||
favicon_url?: string | null
|
||||
fonte_corpo?: string
|
||||
fonte_display?: string
|
||||
footer_text?: string | null
|
||||
id?: number
|
||||
logo_url?: string | null
|
||||
nome_rede?: string
|
||||
subtitulo_hero?: string | null
|
||||
tagline?: string | null
|
||||
tenant_id?: number
|
||||
titulo_hero?: string
|
||||
updated_at?: string
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "app_config_tenant_id_fkey"
|
||||
columns: ["tenant_id"]
|
||||
isOneToOne: true
|
||||
referencedRelation: "tenants"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
contas_pagamento: {
|
||||
Row: {
|
||||
ativa: boolean | null
|
||||
@ -26,6 +97,7 @@ export type Database = {
|
||||
nome_identificacao: string
|
||||
path_crt: string | null
|
||||
path_key: string | null
|
||||
tenant_id: number
|
||||
updated_at: string | null
|
||||
}
|
||||
Insert: {
|
||||
@ -39,6 +111,7 @@ export type Database = {
|
||||
nome_identificacao: string
|
||||
path_crt?: string | null
|
||||
path_key?: string | null
|
||||
tenant_id: number
|
||||
updated_at?: string | null
|
||||
}
|
||||
Update: {
|
||||
@ -52,9 +125,18 @@ export type Database = {
|
||||
nome_identificacao?: string
|
||||
path_crt?: string | null
|
||||
path_key?: string | null
|
||||
tenant_id?: number
|
||||
updated_at?: string | null
|
||||
}
|
||||
Relationships: []
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "contas_pagamento_tenant_id_fkey"
|
||||
columns: ["tenant_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "tenants"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
extras: {
|
||||
Row: {
|
||||
@ -66,6 +148,7 @@ export type Database = {
|
||||
imagem_url: string | null
|
||||
ordem: number
|
||||
preco: number
|
||||
tenant_id: number
|
||||
titulo: string
|
||||
updated_at: string
|
||||
}
|
||||
@ -78,6 +161,7 @@ export type Database = {
|
||||
imagem_url?: string | null
|
||||
ordem?: number
|
||||
preco: number
|
||||
tenant_id: number
|
||||
titulo: string
|
||||
updated_at?: string
|
||||
}
|
||||
@ -90,6 +174,7 @@ export type Database = {
|
||||
imagem_url?: string | null
|
||||
ordem?: number
|
||||
preco?: number
|
||||
tenant_id?: number
|
||||
titulo?: string
|
||||
updated_at?: string
|
||||
}
|
||||
@ -101,6 +186,13 @@ export type Database = {
|
||||
referencedRelation: "marcas"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "extras_tenant_id_fkey"
|
||||
columns: ["tenant_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "tenants"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
fotos_categoria: {
|
||||
@ -112,6 +204,7 @@ export type Database = {
|
||||
id: string
|
||||
id_unidade: string
|
||||
ordem: number
|
||||
tenant_id: number
|
||||
updated_at: string
|
||||
url_foto: string
|
||||
}
|
||||
@ -123,6 +216,7 @@ export type Database = {
|
||||
id?: string
|
||||
id_unidade: string
|
||||
ordem?: number
|
||||
tenant_id: number
|
||||
updated_at?: string
|
||||
url_foto: string
|
||||
}
|
||||
@ -134,6 +228,7 @@ export type Database = {
|
||||
id?: string
|
||||
id_unidade?: string
|
||||
ordem?: number
|
||||
tenant_id?: number
|
||||
updated_at?: string
|
||||
url_foto?: string
|
||||
}
|
||||
@ -145,6 +240,13 @@ export type Database = {
|
||||
referencedRelation: "unidades"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "fotos_categoria_tenant_id_fkey"
|
||||
columns: ["tenant_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "tenants"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
marcas: {
|
||||
@ -156,6 +258,7 @@ export type Database = {
|
||||
id: string
|
||||
nome: string
|
||||
permanencias: string[]
|
||||
tenant_id: number
|
||||
updated_at: string | null
|
||||
}
|
||||
Insert: {
|
||||
@ -166,6 +269,7 @@ export type Database = {
|
||||
id?: string
|
||||
nome: string
|
||||
permanencias?: string[]
|
||||
tenant_id: number
|
||||
updated_at?: string | null
|
||||
}
|
||||
Update: {
|
||||
@ -176,9 +280,18 @@ export type Database = {
|
||||
id?: string
|
||||
nome?: string
|
||||
permanencias?: string[]
|
||||
tenant_id?: number
|
||||
updated_at?: string | null
|
||||
}
|
||||
Relationships: []
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "marcas_tenant_id_fkey"
|
||||
columns: ["tenant_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "tenants"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
precos: {
|
||||
Row: {
|
||||
@ -190,6 +303,7 @@ export type Database = {
|
||||
id_marca: string
|
||||
periodo_semana: string
|
||||
permanencia: string
|
||||
tenant_id: number
|
||||
updated_at: string | null
|
||||
valor: number
|
||||
}
|
||||
@ -202,6 +316,7 @@ export type Database = {
|
||||
id_marca: string
|
||||
periodo_semana?: string
|
||||
permanencia: string
|
||||
tenant_id: number
|
||||
updated_at?: string | null
|
||||
valor: number
|
||||
}
|
||||
@ -214,6 +329,7 @@ export type Database = {
|
||||
id_marca?: string
|
||||
periodo_semana?: string
|
||||
permanencia?: string
|
||||
tenant_id?: number
|
||||
updated_at?: string | null
|
||||
valor?: number
|
||||
}
|
||||
@ -225,6 +341,13 @@ export type Database = {
|
||||
referencedRelation: "marcas"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "precos_tenant_id_fkey"
|
||||
columns: ["tenant_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "tenants"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
reserva_extras: {
|
||||
@ -292,6 +415,7 @@ export type Database = {
|
||||
qr_code_pix: string | null
|
||||
status: string
|
||||
telefone_cliente: string | null
|
||||
tenant_id: number
|
||||
tipo_permanencia: string
|
||||
txid_pix: string | null
|
||||
updated_at: string | null
|
||||
@ -319,6 +443,7 @@ export type Database = {
|
||||
qr_code_pix?: string | null
|
||||
status?: string
|
||||
telefone_cliente?: string | null
|
||||
tenant_id: number
|
||||
tipo_permanencia: string
|
||||
txid_pix?: string | null
|
||||
updated_at?: string | null
|
||||
@ -346,6 +471,7 @@ export type Database = {
|
||||
qr_code_pix?: string | null
|
||||
status?: string
|
||||
telefone_cliente?: string | null
|
||||
tenant_id?: number
|
||||
tipo_permanencia?: string
|
||||
txid_pix?: string | null
|
||||
updated_at?: string | null
|
||||
@ -367,6 +493,13 @@ export type Database = {
|
||||
referencedRelation: "unidades"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "reservas_tenant_id_fkey"
|
||||
columns: ["tenant_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "tenants"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
suites: {
|
||||
@ -380,6 +513,7 @@ export type Database = {
|
||||
id_api: string | null
|
||||
nome: string
|
||||
numero: string | null
|
||||
tenant_id: number
|
||||
updated_at: string | null
|
||||
}
|
||||
Insert: {
|
||||
@ -392,6 +526,7 @@ export type Database = {
|
||||
id_api?: string | null
|
||||
nome: string
|
||||
numero?: string | null
|
||||
tenant_id: number
|
||||
updated_at?: string | null
|
||||
}
|
||||
Update: {
|
||||
@ -404,9 +539,18 @@ export type Database = {
|
||||
id_api?: string | null
|
||||
nome?: string
|
||||
numero?: string | null
|
||||
tenant_id?: number
|
||||
updated_at?: string | null
|
||||
}
|
||||
Relationships: []
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "suites_tenant_id_fkey"
|
||||
columns: ["tenant_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "tenants"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
suites_unidades: {
|
||||
Row: {
|
||||
@ -444,6 +588,33 @@ export type Database = {
|
||||
},
|
||||
]
|
||||
}
|
||||
tenants: {
|
||||
Row: {
|
||||
ativo: boolean
|
||||
created_at: string
|
||||
id: number
|
||||
nome: string
|
||||
slug: string
|
||||
updated_at: string
|
||||
}
|
||||
Insert: {
|
||||
ativo?: boolean
|
||||
created_at?: string
|
||||
id?: number
|
||||
nome: string
|
||||
slug: string
|
||||
updated_at?: string
|
||||
}
|
||||
Update: {
|
||||
ativo?: boolean
|
||||
created_at?: string
|
||||
id?: number
|
||||
nome?: string
|
||||
slug?: string
|
||||
updated_at?: string
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
unidades: {
|
||||
Row: {
|
||||
ativa: boolean | null
|
||||
@ -457,6 +628,7 @@ export type Database = {
|
||||
id_marca: string
|
||||
nome: string
|
||||
telefone: string | null
|
||||
tenant_id: number
|
||||
updated_at: string | null
|
||||
}
|
||||
Insert: {
|
||||
@ -471,6 +643,7 @@ export type Database = {
|
||||
id_marca: string
|
||||
nome: string
|
||||
telefone?: string | null
|
||||
tenant_id: number
|
||||
updated_at?: string | null
|
||||
}
|
||||
Update: {
|
||||
@ -485,6 +658,7 @@ export type Database = {
|
||||
id_marca?: string
|
||||
nome?: string
|
||||
telefone?: string | null
|
||||
tenant_id?: number
|
||||
updated_at?: string | null
|
||||
}
|
||||
Relationships: [
|
||||
@ -502,6 +676,13 @@ export type Database = {
|
||||
referencedRelation: "marcas"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "unidades_tenant_id_fkey"
|
||||
columns: ["tenant_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "tenants"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -720,3 +901,5 @@ export const Constants = {
|
||||
Enums: {},
|
||||
},
|
||||
} as const
|
||||
A new version of Supabase CLI is available: v2.90.0 (currently installed v2.48.3)
|
||||
We recommend updating regularly for new features and bug fixes: https://supabase.com/docs/guides/cli/getting-started#updating-the-supabase-cli
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
-- Multi-tenancy foundation: tenants + app_config
|
||||
-- Já aplicada via MCP.
|
||||
|
||||
create table if not exists reserva_hotel.tenants (
|
||||
id bigserial primary key,
|
||||
slug text not null unique,
|
||||
nome text not null,
|
||||
ativo boolean not null default true,
|
||||
created_at timestamptz not null default now(),
|
||||
updated_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create index if not exists idx_tenants_slug on reserva_hotel.tenants(slug);
|
||||
|
||||
create table if not exists reserva_hotel.app_config (
|
||||
id bigserial primary key,
|
||||
tenant_id bigint not null unique references reserva_hotel.tenants(id) on delete cascade,
|
||||
nome_rede text not null, -- "Rede 1001"
|
||||
titulo_hero text not null, -- "Reserva Rede 1001"
|
||||
subtitulo_hero text, -- "Experiência exclusiva"
|
||||
tagline text, -- "Escolha, confirme e receba seu PIX na hora."
|
||||
footer_text text, -- "© 2026 Rede 1001 · Experiência Exclusiva"
|
||||
logo_url text,
|
||||
favicon_url text,
|
||||
cor_primaria text not null default '#C9A961',
|
||||
cor_secundaria text not null default '#E8B4A0',
|
||||
cor_fundo text not null default '#0B0D12',
|
||||
cor_superficie text not null default '#0F1A2E',
|
||||
cor_texto text not null default '#F5F1E8',
|
||||
fonte_display text not null default 'Fraunces',
|
||||
fonte_corpo text not null default 'Inter',
|
||||
created_at timestamptz not null default now(),
|
||||
updated_at timestamptz not null default now()
|
||||
);
|
||||
@ -0,0 +1,70 @@
|
||||
-- Adiciona tenant_id em todas as tabelas existentes + cria tenant default
|
||||
-- + backfill de tudo pro tenant 1 ("Grupo Nova / Rede 1001")
|
||||
-- Já aplicada via MCP.
|
||||
|
||||
-- 1. Tenant default
|
||||
insert into reserva_hotel.tenants (slug, nome, ativo)
|
||||
values ('grupo-1001', 'Grupo Nova — Rede 1001', true)
|
||||
on conflict (slug) do nothing;
|
||||
|
||||
-- 2. app_config default
|
||||
insert into reserva_hotel.app_config
|
||||
(tenant_id, nome_rede, titulo_hero, subtitulo_hero, tagline, footer_text,
|
||||
cor_primaria, cor_secundaria, cor_fundo, cor_superficie, cor_texto,
|
||||
fonte_display, fonte_corpo)
|
||||
select
|
||||
t.id,
|
||||
'Rede 1001',
|
||||
'Reserva Rede 1001',
|
||||
'Experiência exclusiva',
|
||||
'Escolha, confirme e receba seu PIX na hora.',
|
||||
'© 2026 Rede 1001 · Experiência Exclusiva',
|
||||
'#C9A961', '#E8B4A0', '#0B0D12', '#0F1A2E', '#F5F1E8',
|
||||
'Fraunces', 'Inter'
|
||||
from reserva_hotel.tenants t
|
||||
where t.slug = 'grupo-1001'
|
||||
on conflict (tenant_id) do nothing;
|
||||
|
||||
-- 3. Adiciona tenant_id (nullable pra backfill)
|
||||
alter table reserva_hotel.marcas add column if not exists tenant_id bigint references reserva_hotel.tenants(id);
|
||||
alter table reserva_hotel.unidades add column if not exists tenant_id bigint references reserva_hotel.tenants(id);
|
||||
alter table reserva_hotel.suites add column if not exists tenant_id bigint references reserva_hotel.tenants(id);
|
||||
alter table reserva_hotel.precos add column if not exists tenant_id bigint references reserva_hotel.tenants(id);
|
||||
alter table reserva_hotel.contas_pagamento add column if not exists tenant_id bigint references reserva_hotel.tenants(id);
|
||||
alter table reserva_hotel.reservas add column if not exists tenant_id bigint references reserva_hotel.tenants(id);
|
||||
alter table reserva_hotel.fotos_categoria add column if not exists tenant_id bigint references reserva_hotel.tenants(id);
|
||||
alter table reserva_hotel.extras add column if not exists tenant_id bigint references reserva_hotel.tenants(id);
|
||||
|
||||
-- 4. Backfill
|
||||
do $$
|
||||
declare v_tenant_id bigint;
|
||||
begin
|
||||
select id into v_tenant_id from reserva_hotel.tenants where slug = 'grupo-1001';
|
||||
|
||||
update reserva_hotel.marcas set tenant_id = v_tenant_id where tenant_id is null;
|
||||
update reserva_hotel.unidades set tenant_id = v_tenant_id where tenant_id is null;
|
||||
update reserva_hotel.suites set tenant_id = v_tenant_id where tenant_id is null;
|
||||
update reserva_hotel.precos set tenant_id = v_tenant_id where tenant_id is null;
|
||||
update reserva_hotel.contas_pagamento set tenant_id = v_tenant_id where tenant_id is null;
|
||||
update reserva_hotel.reservas set tenant_id = v_tenant_id where tenant_id is null;
|
||||
update reserva_hotel.fotos_categoria set tenant_id = v_tenant_id where tenant_id is null;
|
||||
update reserva_hotel.extras set tenant_id = v_tenant_id where tenant_id is null;
|
||||
end $$;
|
||||
|
||||
-- 5. NOT NULL
|
||||
alter table reserva_hotel.marcas alter column tenant_id set not null;
|
||||
alter table reserva_hotel.unidades alter column tenant_id set not null;
|
||||
alter table reserva_hotel.suites alter column tenant_id set not null;
|
||||
alter table reserva_hotel.precos alter column tenant_id set not null;
|
||||
alter table reserva_hotel.contas_pagamento alter column tenant_id set not null;
|
||||
alter table reserva_hotel.reservas alter column tenant_id set not null;
|
||||
alter table reserva_hotel.fotos_categoria alter column tenant_id set not null;
|
||||
alter table reserva_hotel.extras alter column tenant_id set not null;
|
||||
|
||||
-- 6. Indexes
|
||||
create index if not exists idx_marcas_tenant on reserva_hotel.marcas(tenant_id);
|
||||
create index if not exists idx_unidades_tenant on reserva_hotel.unidades(tenant_id);
|
||||
create index if not exists idx_precos_tenant on reserva_hotel.precos(tenant_id);
|
||||
create index if not exists idx_reservas_tenant on reserva_hotel.reservas(tenant_id);
|
||||
create index if not exists idx_fotos_categoria_tenant on reserva_hotel.fotos_categoria(tenant_id);
|
||||
create index if not exists idx_extras_tenant on reserva_hotel.extras(tenant_id);
|
||||
16
supabase/migrations/20260414000003_rls_tenant_scoping.sql
Normal file
16
supabase/migrations/20260414000003_rls_tenant_scoping.sql
Normal file
@ -0,0 +1,16 @@
|
||||
-- RLS + grants pras tabelas publicas de tenant
|
||||
-- Já aplicada via MCP.
|
||||
|
||||
alter table reserva_hotel.tenants enable row level security;
|
||||
alter table reserva_hotel.app_config enable row level security;
|
||||
|
||||
drop policy if exists "public_read_tenants" on reserva_hotel.tenants;
|
||||
create policy "public_read_tenants" on reserva_hotel.tenants
|
||||
for select using (ativo = true);
|
||||
|
||||
drop policy if exists "public_read_app_config" on reserva_hotel.app_config;
|
||||
create policy "public_read_app_config" on reserva_hotel.app_config
|
||||
for select using (true);
|
||||
|
||||
grant select on reserva_hotel.tenants to anon, authenticated;
|
||||
grant select on reserva_hotel.app_config to anon, authenticated;
|
||||
Loading…
Reference in New Issue
Block a user