-- ============================================================================ -- MIGRAÇÃO COMPLETA DO SCHEMA 'rdo' PARA SUPABASE -- Executar este script no SQL Editor do Supabase -- ============================================================================ -- 1. CRIAR ESQUEMA -- ============================================================================ CREATE SCHEMA IF NOT EXISTS rdo; -- 2. GARANTIR EXTENSÕES -- ============================================================================ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- 3. CRIAR TABELAS NO ESQUEMA 'rdo' -- ============================================================================ -- Tabela: Organizacoes CREATE TABLE IF NOT EXISTS rdo.organizacoes ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, nome TEXT NOT NULL, slug TEXT UNIQUE NOT NULL, razao_social TEXT, cnpj TEXT, status TEXT DEFAULT 'ativa' CHECK (status IN ('ativa', 'inativa', 'suspensa')), plano TEXT DEFAULT 'trial' CHECK (plano IN ('trial', 'basico', 'profissional', 'enterprise')), max_usuarios INTEGER DEFAULT 5, max_obras INTEGER DEFAULT 10, max_rdos_mes INTEGER DEFAULT 100, max_storage_mb INTEGER DEFAULT 1024, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: Usuarios CREATE TABLE IF NOT EXISTS rdo.usuarios ( id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, organizacao_id UUID REFERENCES rdo.organizacoes(id) ON DELETE SET NULL, email TEXT NOT NULL, nome TEXT NOT NULL, telefone TEXT, cargo TEXT, role TEXT DEFAULT 'usuario' CHECK (role IN ('dev', 'admin', 'engenheiro', 'mestre_obra', 'usuario')), ativo BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: Obras CREATE TABLE IF NOT EXISTS rdo.obras ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, organizacao_id UUID NOT NULL REFERENCES rdo.organizacoes(id) ON DELETE CASCADE, nome TEXT NOT NULL, descricao TEXT, endereco TEXT, cep TEXT, cidade TEXT, estado TEXT, responsavel_id UUID REFERENCES rdo.usuarios(id) ON DELETE SET NULL, data_inicio DATE, data_prevista_fim DATE, data_conclusao DATE, progresso_geral NUMERIC(5,2) DEFAULT 0, status TEXT DEFAULT 'ativa' CHECK (status IN ('ativa', 'pausada', 'concluida', 'cancelada')), configuracoes JSONB DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: RDOs CREATE TABLE IF NOT EXISTS rdo.rdos ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, organizacao_id UUID REFERENCES rdo.organizacoes(id) ON DELETE CASCADE, obra_id UUID NOT NULL REFERENCES rdo.obras(id) ON DELETE CASCADE, criado_por UUID NOT NULL REFERENCES rdo.usuarios(id), data_relatorio DATE NOT NULL, condicoes_climaticas TEXT NOT NULL, observacoes_gerais TEXT, status TEXT DEFAULT 'rascunho' CHECK (status IN ('rascunho', 'enviado', 'aprovado', 'rejeitado')), aprovado_por UUID REFERENCES rdo.usuarios(id), aprovado_em TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: RDO Atividades CREATE TABLE IF NOT EXISTS rdo.rdo_atividades ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE, tipo_atividade TEXT NOT NULL, descricao TEXT NOT NULL, localizacao TEXT, percentual_concluido NUMERIC(5,2) DEFAULT 0, ordem INTEGER DEFAULT 0, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: RDO Mão de Obra CREATE TABLE IF NOT EXISTS rdo.rdo_mao_obra ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE, funcao TEXT NOT NULL, quantidade INTEGER DEFAULT 0, horas_trabalhadas NUMERIC(5,2) DEFAULT 0, observacoes TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: RDO Equipamentos CREATE TABLE IF NOT EXISTS rdo.rdo_equipamentos ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE, nome_equipamento TEXT NOT NULL, tipo TEXT, horas_utilizadas NUMERIC(5,2) DEFAULT 0, combustivel_gasto NUMERIC(10,2) DEFAULT 0, observacoes TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: RDO Ocorrencias CREATE TABLE IF NOT EXISTS rdo.rdo_ocorrencias ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE, tipo_ocorrencia TEXT NOT NULL, descricao TEXT NOT NULL, gravidade TEXT CHECK (gravidade IN ('baixa', 'media', 'alta', 'critica')), acao_tomada TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: RDO Anexos CREATE TABLE IF NOT EXISTS rdo.rdo_anexos ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE, nome_arquivo TEXT NOT NULL, tipo_arquivo TEXT, url_storage TEXT NOT NULL, tamanho_bytes BIGINT, descricao TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: Tipos de Atividade (configuração) CREATE TABLE IF NOT EXISTS rdo.tipos_atividade ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, nome TEXT NOT NULL, descricao TEXT, ativo BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Tabela: Condições Climáticas (configuração) CREATE TABLE IF NOT EXISTS rdo.condicoes_climaticas ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, nome TEXT NOT NULL, descricao TEXT, ativo BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 4. CRIAR ÍNDICES PARA OTIMIZAÇÃO -- ============================================================================ CREATE INDEX IF NOT EXISTS idx_usuarios_org ON rdo.usuarios(organizacao_id); CREATE INDEX IF NOT EXISTS idx_obras_org ON rdo.obras(organizacao_id); CREATE INDEX IF NOT EXISTS idx_obras_status ON rdo.obras(status); CREATE INDEX IF NOT EXISTS idx_rdos_obra ON rdo.rdos(obra_id); CREATE INDEX IF NOT EXISTS idx_rdos_data ON rdo.rdos(data_relatorio); CREATE INDEX IF NOT EXISTS idx_rdos_status ON rdo.rdos(status); CREATE INDEX IF NOT EXISTS idx_rdo_atividades_rdo ON rdo.rdo_atividades(rdo_id); CREATE INDEX IF NOT EXISTS idx_rdo_mao_obra_rdo ON rdo.rdo_mao_obra(rdo_id); CREATE INDEX IF NOT EXISTS idx_rdo_equipamentos_rdo ON rdo.rdo_equipamentos(rdo_id); CREATE INDEX IF NOT EXISTS idx_rdo_ocorrencias_rdo ON rdo.rdo_ocorrencias(rdo_id); -- 5. HABILITAR RLS -- ============================================================================ ALTER TABLE rdo.organizacoes ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.usuarios ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.obras ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.rdos ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.rdo_atividades ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.rdo_mao_obra ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.rdo_equipamentos ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.rdo_ocorrencias ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.rdo_anexos ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.tipos_atividade ENABLE ROW LEVEL SECURITY; ALTER TABLE rdo.condicoes_climaticas ENABLE ROW LEVEL SECURITY; -- 6. CRIAR POLÍTICAS RLS -- ============================================================================ CREATE POLICY "auth_all_rdo_usuarios" ON rdo.usuarios FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_orgs" ON rdo.organizacoes FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_obras" ON rdo.obras FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_rdos" ON rdo.rdos FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_ativ" ON rdo.rdo_atividades FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_mao" ON rdo.rdo_mao_obra FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_equip" ON rdo.rdo_equipamentos FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_ocor" ON rdo.rdo_ocorrencias FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_anex" ON rdo.rdo_anexos FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_tipos_ativ" ON rdo.tipos_atividade FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); CREATE POLICY "auth_all_rdo_cond_clim" ON rdo.condicoes_climaticas FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL); -- 7. PERMISSÕES -- ============================================================================ GRANT USAGE ON SCHEMA rdo TO authenticated, anon; GRANT ALL ON ALL TABLES IN SCHEMA rdo TO authenticated; GRANT ALL ON ALL SEQUENCES IN SCHEMA rdo TO authenticated; GRANT ALL ON ALL FUNCTIONS IN SCHEMA rdo TO authenticated; -- 8. CRIAR TRIGGER PARA NOVO USUÁRIO -- ============================================================================ CREATE OR REPLACE FUNCTION rdo.handle_new_user() RETURNS TRIGGER SECURITY DEFINER SET search_path = rdo, public AS $$ DECLARE user_name TEXT; BEGIN user_name := COALESCE( NEW.raw_user_meta_data->>'nome', NEW.raw_user_meta_data->>'name', NEW.raw_user_meta_data->>'full_name', split_part(NEW.email, '@', 1) ); INSERT INTO rdo.usuarios (id, email, nome, role, ativo) VALUES (NEW.id, NEW.email, user_name, 'usuario', true) ON CONFLICT (id) DO UPDATE SET email = EXCLUDED.email, nome = COALESCE(EXCLUDED.nome, rdo.usuarios.nome), updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; 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 FUNCTION rdo.handle_new_user(); -- 9. DADOS INICIAIS (SEED) -- ============================================================================ INSERT INTO rdo.organizacoes (nome, slug, status, plano) VALUES ('Baldon Engemetal', 'baldon-engemetal', 'ativa', 'profissional') ON CONFLICT (slug) DO NOTHING; -- Tipos de atividade padrão INSERT INTO rdo.tipos_atividade (nome, descricao, ativo) VALUES ('Preparação de Superfície', 'Limpeza, jateamento, primação', true), ('Aplicação de Primer', 'Aplicação da primeira camada', true), ('Aplicação de Intermediate', 'Camada intermediária', true), ('Aplicação de Topcoat', 'Camada final de acabamento', true), (' Inspeção de Qualidade', 'Verificação e controle', true), ('Manutenção de Equipamentos', 'Limpeza e manutenção', true), ('Transporte e Movimentação', 'Movimentação de peças', true), ('Outros', 'Outras atividades', true) ON CONFLICT DO NOTHING; -- Condições climáticas padrão INSERT INTO rdo.condicoes_climaticas (nome, descricao, ativo) VALUES ('Ensolarado', 'Tempo aberto, sol forte', true), ('Parcialmente Nublado', 'Sol entre nuvens', true), ('Nublado', 'Céu encoberto', true), ('Chuva Leve', 'Chuvisco', true), ('Chuva Forte', 'Chuva intensa', true), ('Vento Forte', 'Ventania', true), ('Umidade Alta', 'Umidade acima de 80%', true), ('Temperatura Baixa', 'Abaixo de 15°C', true), ('Temperatura Alta', 'Acima de 35°C', true) ON CONFLICT DO NOTHING; SELECT 'Schema rdo criado com sucesso!' AS resultado;