diff --git a/src/types/database.ts b/src/types/database.ts index 4614d4a..b932d16 100644 --- a/src/types/database.ts +++ b/src/types/database.ts @@ -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 diff --git a/supabase/migrations/20260414000001_tenants_and_app_config.sql b/supabase/migrations/20260414000001_tenants_and_app_config.sql new file mode 100644 index 0000000..ae74176 --- /dev/null +++ b/supabase/migrations/20260414000001_tenants_and_app_config.sql @@ -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() +); diff --git a/supabase/migrations/20260414000002_add_tenant_id_backfill.sql b/supabase/migrations/20260414000002_add_tenant_id_backfill.sql new file mode 100644 index 0000000..c119e2e --- /dev/null +++ b/supabase/migrations/20260414000002_add_tenant_id_backfill.sql @@ -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); diff --git a/supabase/migrations/20260414000003_rls_tenant_scoping.sql b/supabase/migrations/20260414000003_rls_tenant_scoping.sql new file mode 100644 index 0000000..dfbadfc --- /dev/null +++ b/supabase/migrations/20260414000003_rls_tenant_scoping.sql @@ -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;