// SeConectai Vendas — Prisma schema // Traduzido 1:1 a partir de `Etapas/seconectai-vendas-schema.sql` (fonte de verdade). // Constructos que o Prisma DSL não expressa nativamente (views, índices parciais, // CHECK constraints e as policies de RLS) são criados por uma migration manual // em `prisma/migrations/_rls_views_constraints/migration.sql`. generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ============================================================ // ENUMS // ============================================================ enum tenant_status { trial ativo inadimplente suspenso cancelado } enum cobranca_status { pendente pago atrasado cancelado } enum user_role { tenant_admin vendedor financeiro visualizador } enum item_tipo { produto servico } enum venda_status { orcamento confirmada cancelada concluida } enum parcela_status { pendente pago atrasado cancelado } // ============================================================ // 1. NÍVEL MASTER // ============================================================ model master_admins { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid nome String @db.VarChar(150) email String @unique @db.VarChar(150) senha_hash String ativo Boolean @default(true) mfa_secret String? ultimo_login DateTime? @db.Timestamptz(6) criado_em DateTime @default(now()) @db.Timestamptz(6) atualizado_em DateTime @default(now()) @db.Timestamptz(6) tenants_criados tenants[] } model evolution_api_config { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid nome String @db.VarChar(100) base_url String @db.VarChar(255) api_key_cripto String versao String @default("2.3") @db.VarChar(20) ativo Boolean @default(true) criado_em DateTime @default(now()) @db.Timestamptz(6) instancias tenant_whatsapp_instances[] } model master_email_config { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid smtp_host String @db.VarChar(150) smtp_porta Int smtp_usuario String @db.VarChar(150) smtp_senha_cripto String email_remetente String @db.VarChar(150) ativo Boolean @default(true) criado_em DateTime @default(now()) @db.Timestamptz(6) } model planos { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid nome String @db.VarChar(100) descricao String? valor_mensal Decimal @db.Decimal(10, 2) limite_customers Int? limite_usuarios Int? limite_instancias_whatsapp Int @default(1) ativo Boolean @default(true) criado_em DateTime @default(now()) @db.Timestamptz(6) tenants tenants[] } // ============================================================ // 2. TENANTS // ============================================================ model tenants { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid razao_social String @db.VarChar(200) nome_fantasia String? @db.VarChar(200) documento String? @db.VarChar(20) email_contato String @db.VarChar(150) telefone String? @db.VarChar(20) logo_url String? cor_primaria String? @db.VarChar(7) plano_id String? @db.Uuid status tenant_status @default(trial) dia_vencimento_mensalidade Int @default(10) @db.SmallInt trial_expira_em DateTime? @db.Timestamptz(6) criado_por String? @db.Uuid criado_em DateTime @default(now()) @db.Timestamptz(6) atualizado_em DateTime @default(now()) @db.Timestamptz(6) plano planos? @relation(fields: [plano_id], references: [id]) criador master_admins? @relation(fields: [criado_por], references: [id]) faturas tenant_faturas[] usuarios tenant_users[] whatsapp_instances tenant_whatsapp_instances[] email_config tenant_email_config? alert_templates alert_templates[] alert_logs alert_logs[] customers customers[] produtos products_services[] vendas sales[] audit_logs audit_logs[] @@index([status], map: "idx_tenants_status") } model tenant_faturas { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String @db.Uuid referencia String @db.VarChar(7) valor Decimal @db.Decimal(10, 2) vencimento DateTime @db.Date pago_em DateTime? @db.Timestamptz(6) status cobranca_status @default(pendente) alerta_enviado_em DateTime? @db.Timestamptz(6) criado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) @@unique([tenant_id, referencia]) } // ============================================================ // 3. USUÁRIOS E AUTENTICAÇÃO // ============================================================ model tenant_users { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String @db.Uuid nome String @db.VarChar(150) email String @db.VarChar(150) senha_hash String role user_role @default(vendedor) ativo Boolean @default(true) mfa_secret String? ultimo_login DateTime? @db.Timestamptz(6) criado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) vendas sales[] @@unique([tenant_id, email]) @@index([tenant_id], map: "idx_tenant_users_tenant") } model auth_refresh_tokens { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid usuario_tipo String @db.VarChar(20) usuario_id String @db.Uuid token_hash String expira_em DateTime @db.Timestamptz(6) revogado Boolean @default(false) ip_origem String? @db.Inet user_agent String? criado_em DateTime @default(now()) @db.Timestamptz(6) @@index([usuario_tipo, usuario_id], map: "idx_refresh_tokens_usuario") } model password_reset_tokens { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid usuario_tipo String @db.VarChar(20) usuario_id String @db.Uuid token_hash String expira_em DateTime @db.Timestamptz(6) usado Boolean @default(false) criado_em DateTime @default(now()) @db.Timestamptz(6) } model login_attempts { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid email String @db.VarChar(150) usuario_tipo String @db.VarChar(20) sucesso Boolean ip_origem String? @db.Inet criado_em DateTime @default(now()) @db.Timestamptz(6) @@index([email, criado_em], map: "idx_login_attempts_email_data") } // ============================================================ // 4. INTEGRAÇÕES POR TENANT // ============================================================ model tenant_whatsapp_instances { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String @db.Uuid evolution_config_id String? @db.Uuid instance_name String @unique @db.VarChar(100) numero_conectado String? @db.VarChar(20) status String @default("desconectado") @db.VarChar(30) qr_code_gerado_em DateTime? @db.Timestamptz(6) criado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) evolution_config evolution_api_config? @relation(fields: [evolution_config_id], references: [id]) } model tenant_email_config { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String @unique @db.Uuid smtp_host String? @db.VarChar(150) smtp_porta Int? smtp_usuario String? @db.VarChar(150) smtp_senha_cripto String? email_remetente String? @db.VarChar(150) usar_config_padrao Boolean @default(true) criado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) } model alert_templates { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String? @db.Uuid tipo String @db.VarChar(50) canal String @db.VarChar(20) assunto String? @db.VarChar(200) corpo String ativo Boolean @default(true) criado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants? @relation(fields: [tenant_id], references: [id], onDelete: Cascade) alert_logs alert_logs[] } model alert_logs { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String? @db.Uuid destinatario_tipo String @db.VarChar(20) destinatario_id String @db.Uuid canal String @db.VarChar(20) template_id String? @db.Uuid conteudo_enviado String? status String @default("enviado") @db.VarChar(20) erro String? enviado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants? @relation(fields: [tenant_id], references: [id], onDelete: Cascade) template alert_templates? @relation(fields: [template_id], references: [id]) @@index([tenant_id, enviado_em], map: "idx_alert_logs_tenant") } // ============================================================ // 5. CLIENTES DO TENANT ("customers") // ============================================================ model customers { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String @db.Uuid razao_social String @db.VarChar(200) nome_fantasia String? @db.VarChar(200) documento String? @db.VarChar(20) email String? @db.VarChar(150) telefone_whatsapp String? @db.VarChar(20) endereco String? cidade String? @db.VarChar(100) uf String? @db.Char(2) observacoes String? ativo Boolean @default(true) criado_em DateTime @default(now()) @db.Timestamptz(6) atualizado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) contatos customer_contacts[] vendas sales[] @@index([tenant_id], map: "idx_customers_tenant") } model customer_contacts { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid customer_id String @db.Uuid nome String @db.VarChar(150) cargo String? @db.VarChar(100) email String? @db.VarChar(150) telefone_whatsapp String? @db.VarChar(20) principal Boolean @default(false) criado_em DateTime @default(now()) @db.Timestamptz(6) customer customers @relation(fields: [customer_id], references: [id], onDelete: Cascade) } // ============================================================ // 6. PRODUTOS E SERVIÇOS DO TENANT // ============================================================ model products_services { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String @db.Uuid tipo item_tipo nome String @db.VarChar(200) descricao String? sku String? @db.VarChar(50) valor_venda Decimal @db.Decimal(12, 2) valor_custo Decimal? @db.Decimal(12, 2) unidade String @default("un") @db.VarChar(20) recorrente Boolean @default(false) ativo Boolean @default(true) criado_em DateTime @default(now()) @db.Timestamptz(6) atualizado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) itens_venda sale_items[] @@unique([tenant_id, sku]) @@index([tenant_id], map: "idx_products_tenant") } // ============================================================ // 7. VENDAS // ============================================================ model sales { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String @db.Uuid customer_id String @db.Uuid vendedor_id String? @db.Uuid numero_venda Int @default(autoincrement()) status venda_status @default(confirmada) valor_total Decimal @default(0) @db.Decimal(12, 2) desconto Decimal @default(0) @db.Decimal(12, 2) observacoes String? data_venda DateTime @default(now()) @db.Date criado_em DateTime @default(now()) @db.Timestamptz(6) atualizado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) customer customers @relation(fields: [customer_id], references: [id]) vendedor tenant_users? @relation(fields: [vendedor_id], references: [id]) itens sale_items[] parcelas sale_payments[] @@index([tenant_id, data_venda], map: "idx_sales_tenant_data") @@index([customer_id], map: "idx_sales_customer") } model sale_items { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid sale_id String @db.Uuid product_service_id String @db.Uuid quantidade Decimal @default(1) @db.Decimal(10, 2) valor_unitario Decimal @db.Decimal(12, 2) valor_total Decimal @db.Decimal(12, 2) sale sales @relation(fields: [sale_id], references: [id], onDelete: Cascade) produto products_services @relation(fields: [product_service_id], references: [id]) @@index([sale_id], map: "idx_sale_items_sale") } model sale_payments { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid sale_id String @db.Uuid numero_parcela Int @default(1) @db.SmallInt valor Decimal @db.Decimal(12, 2) vencimento DateTime @db.Date pago_em DateTime? @db.Timestamptz(6) forma_pagamento String? @db.VarChar(30) status parcela_status @default(pendente) alerta_enviado_em DateTime? @db.Timestamptz(6) criado_em DateTime @default(now()) @db.Timestamptz(6) sale sales @relation(fields: [sale_id], references: [id], onDelete: Cascade) } // ============================================================ // 8. AUDITORIA GERAL // ============================================================ model audit_logs { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid tenant_id String? @db.Uuid usuario_tipo String @db.VarChar(20) usuario_id String? @db.Uuid acao String @db.VarChar(100) entidade String? @db.VarChar(50) entidade_id String? @db.Uuid detalhes Json? ip_origem String? @db.Inet criado_em DateTime @default(now()) @db.Timestamptz(6) tenant tenants? @relation(fields: [tenant_id], references: [id], onDelete: SetNull) @@index([tenant_id, criado_em], map: "idx_audit_tenant_data") }