Initial SeConectai briefing system

This commit is contained in:
2026-10-04 10:42:23 -03:00
commit 45cd8d2f03
163 changed files with 12659 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
File diff suppressed because it is too large Load Diff
+149
View File
@@ -0,0 +1,149 @@
CREATE TYPE "Papel" AS ENUM ('CLIENTE', 'ADMIN');
CREATE TYPE "TipoPessoa" AS ENUM ('PF', 'PJ');
CREATE TYPE "TipoPergunta" AS ENUM ('TEXTAREA', 'RADIO', 'CHECKBOX', 'ANEXO');
CREATE TYPE "StatusBriefing" AS ENUM ('RASCUNHO', 'ENVIADO', 'EM_ANALISE', 'CONCLUIDO');
CREATE TABLE "users" (
"id" TEXT NOT NULL,
"email" TEXT NOT NULL,
"senhaHash" TEXT NOT NULL,
"papel" "Papel" NOT NULL DEFAULT 'CLIENTE',
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"atualizadoEm" TIMESTAMP(3) NOT NULL,
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "clientes" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"nomeCompleto" TEXT NOT NULL,
"cpfCifrado" TEXT NOT NULL,
"cpfHash" TEXT NOT NULL,
"whatsapp" TEXT NOT NULL,
"tipo" "TipoPessoa" NOT NULL DEFAULT 'PF',
"razaoSocial" TEXT,
"cnpj" TEXT,
"cep" TEXT,
"logradouro" TEXT,
"numero" TEXT,
"complemento" TEXT,
"bairro" TEXT,
"cidade" TEXT,
"uf" TEXT,
"lgpdAceiteEm" TIMESTAMP(3) NOT NULL,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"atualizadoEm" TIMESTAMP(3) NOT NULL,
CONSTRAINT "clientes_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "secoes" (
"id" TEXT NOT NULL,
"ordem" INTEGER NOT NULL,
"titulo" TEXT NOT NULL,
"descricao" TEXT,
"ativo" BOOLEAN NOT NULL DEFAULT true,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"atualizadoEm" TIMESTAMP(3) NOT NULL,
CONSTRAINT "secoes_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "perguntas" (
"id" TEXT NOT NULL,
"secaoId" TEXT NOT NULL,
"ordem" INTEGER NOT NULL,
"rotulo" TEXT NOT NULL,
"dica" TEXT,
"tipo" "TipoPergunta" NOT NULL,
"opcoes" JSONB NOT NULL,
"obrigatoria" BOOLEAN NOT NULL DEFAULT false,
"permiteComplemento" BOOLEAN NOT NULL DEFAULT false,
"ativo" BOOLEAN NOT NULL DEFAULT true,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"atualizadoEm" TIMESTAMP(3) NOT NULL,
CONSTRAINT "perguntas_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "ajudas" (
"id" TEXT NOT NULL,
"perguntaId" TEXT NOT NULL,
"oQueResponder" TEXT NOT NULL,
"porQuePerguntamos" TEXT NOT NULL,
"miniExemplo" TEXT NOT NULL,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"atualizadoEm" TIMESTAMP(3) NOT NULL,
CONSTRAINT "ajudas_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "briefings" (
"id" TEXT NOT NULL,
"clienteId" TEXT NOT NULL,
"titulo" TEXT NOT NULL,
"status" "StatusBriefing" NOT NULL DEFAULT 'RASCUNHO',
"confirmadoEm" TIMESTAMP(3),
"enviadoEm" TIMESTAMP(3),
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"atualizadoEm" TIMESTAMP(3) NOT NULL,
CONSTRAINT "briefings_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "respostas" (
"id" TEXT NOT NULL,
"briefingId" TEXT NOT NULL,
"perguntaId" TEXT NOT NULL,
"texto" TEXT,
"complemento" TEXT,
"selecionadas" JSONB,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"atualizadoEm" TIMESTAMP(3) NOT NULL,
CONSTRAINT "respostas_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "anexos" (
"id" TEXT NOT NULL,
"briefingId" TEXT NOT NULL,
"perguntaId" TEXT NOT NULL,
"nomeOriginal" TEXT NOT NULL,
"caminho" TEXT NOT NULL,
"mime" TEXT NOT NULL,
"tamanho" INTEGER NOT NULL,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "anexos_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "password_reset_tokens" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"tokenHash" TEXT NOT NULL,
"expiraEm" TIMESTAMP(3) NOT NULL,
"usadoEm" TIMESTAMP(3),
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "password_reset_tokens_pkey" PRIMARY KEY ("id")
);
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
CREATE UNIQUE INDEX "clientes_userId_key" ON "clientes"("userId");
CREATE UNIQUE INDEX "clientes_cpfHash_key" ON "clientes"("cpfHash");
CREATE INDEX "clientes_tipo_idx" ON "clientes"("tipo");
CREATE UNIQUE INDEX "secoes_ordem_key" ON "secoes"("ordem");
CREATE INDEX "perguntas_tipo_idx" ON "perguntas"("tipo");
CREATE UNIQUE INDEX "perguntas_secaoId_ordem_key" ON "perguntas"("secaoId", "ordem");
CREATE UNIQUE INDEX "ajudas_perguntaId_key" ON "ajudas"("perguntaId");
CREATE INDEX "briefings_clienteId_idx" ON "briefings"("clienteId");
CREATE INDEX "briefings_status_idx" ON "briefings"("status");
CREATE INDEX "respostas_perguntaId_idx" ON "respostas"("perguntaId");
CREATE UNIQUE INDEX "respostas_briefingId_perguntaId_key" ON "respostas"("briefingId", "perguntaId");
CREATE INDEX "anexos_briefingId_idx" ON "anexos"("briefingId");
CREATE INDEX "anexos_perguntaId_idx" ON "anexos"("perguntaId");
CREATE UNIQUE INDEX "password_reset_tokens_tokenHash_key" ON "password_reset_tokens"("tokenHash");
CREATE INDEX "password_reset_tokens_userId_idx" ON "password_reset_tokens"("userId");
CREATE INDEX "password_reset_tokens_expiraEm_idx" ON "password_reset_tokens"("expiraEm");
ALTER TABLE "clientes" ADD CONSTRAINT "clientes_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "perguntas" ADD CONSTRAINT "perguntas_secaoId_fkey" FOREIGN KEY ("secaoId") REFERENCES "secoes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "ajudas" ADD CONSTRAINT "ajudas_perguntaId_fkey" FOREIGN KEY ("perguntaId") REFERENCES "perguntas"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "briefings" ADD CONSTRAINT "briefings_clienteId_fkey" FOREIGN KEY ("clienteId") REFERENCES "clientes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "respostas" ADD CONSTRAINT "respostas_briefingId_fkey" FOREIGN KEY ("briefingId") REFERENCES "briefings"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "respostas" ADD CONSTRAINT "respostas_perguntaId_fkey" FOREIGN KEY ("perguntaId") REFERENCES "perguntas"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "anexos" ADD CONSTRAINT "anexos_briefingId_fkey" FOREIGN KEY ("briefingId") REFERENCES "briefings"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "anexos" ADD CONSTRAINT "anexos_perguntaId_fkey" FOREIGN KEY ("perguntaId") REFERENCES "perguntas"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -0,0 +1,10 @@
CREATE TABLE "configuracoes" (
"id" TEXT NOT NULL,
"chave" TEXT NOT NULL,
"valor" JSONB NOT NULL,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"atualizadoEm" TIMESTAMP(3) NOT NULL,
CONSTRAINT "configuracoes_pkey" PRIMARY KEY ("id")
);
CREATE UNIQUE INDEX "configuracoes_chave_key" ON "configuracoes"("chave");
@@ -0,0 +1,27 @@
CREATE TABLE "auditorias_acesso" (
"id" TEXT NOT NULL,
"adminId" TEXT NOT NULL,
"clienteId" TEXT NOT NULL,
"acao" TEXT NOT NULL,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "auditorias_acesso_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "notas_internas" (
"id" TEXT NOT NULL,
"briefingId" TEXT NOT NULL,
"adminId" TEXT NOT NULL,
"texto" TEXT NOT NULL,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "notas_internas_pkey" PRIMARY KEY ("id")
);
CREATE INDEX "auditorias_acesso_adminId_idx" ON "auditorias_acesso"("adminId");
CREATE INDEX "auditorias_acesso_clienteId_idx" ON "auditorias_acesso"("clienteId");
CREATE INDEX "notas_internas_briefingId_idx" ON "notas_internas"("briefingId");
CREATE INDEX "notas_internas_adminId_idx" ON "notas_internas"("adminId");
ALTER TABLE "auditorias_acesso" ADD CONSTRAINT "auditorias_acesso_adminId_fkey" FOREIGN KEY ("adminId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "auditorias_acesso" ADD CONSTRAINT "auditorias_acesso_clienteId_fkey" FOREIGN KEY ("clienteId") REFERENCES "clientes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "notas_internas" ADD CONSTRAINT "notas_internas_briefingId_fkey" FOREIGN KEY ("briefingId") REFERENCES "briefings"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "notas_internas" ADD CONSTRAINT "notas_internas_adminId_fkey" FOREIGN KEY ("adminId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -0,0 +1,22 @@
CREATE TYPE "CanalNotificacao" AS ENUM ('EMAIL', 'WHATSAPP');
CREATE TYPE "StatusNotificacao" AS ENUM ('PENDENTE', 'ENVIADO', 'ERRO');
CREATE TABLE "envios_notificacao" (
"id" TEXT NOT NULL,
"briefingId" TEXT NOT NULL,
"canal" "CanalNotificacao" NOT NULL,
"destino" TEXT NOT NULL,
"assunto" TEXT,
"status" "StatusNotificacao" NOT NULL DEFAULT 'PENDENTE',
"erro" TEXT,
"tentativas" INTEGER NOT NULL DEFAULT 0,
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"atualizadoEm" TIMESTAMP(3) NOT NULL,
"enviadoEm" TIMESTAMP(3),
CONSTRAINT "envios_notificacao_pkey" PRIMARY KEY ("id")
);
CREATE INDEX "envios_notificacao_briefingId_idx" ON "envios_notificacao"("briefingId");
CREATE INDEX "envios_notificacao_status_idx" ON "envios_notificacao"("status");
ALTER TABLE "envios_notificacao" ADD CONSTRAINT "envios_notificacao_briefingId_fkey" FOREIGN KEY ("briefingId") REFERENCES "briefings"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,16 @@
CREATE TYPE "StatusSolicitacaoExclusao" AS ENUM ('PENDENTE', 'PROCESSADA', 'CANCELADA');
CREATE TABLE "solicitacoes_exclusao" (
"id" TEXT NOT NULL,
"clienteId" TEXT NOT NULL,
"motivo" TEXT,
"status" "StatusSolicitacaoExclusao" NOT NULL DEFAULT 'PENDENTE',
"criadoEm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"processadoEm" TIMESTAMP(3),
CONSTRAINT "solicitacoes_exclusao_pkey" PRIMARY KEY ("id")
);
CREATE INDEX "solicitacoes_exclusao_clienteId_idx" ON "solicitacoes_exclusao"("clienteId");
CREATE INDEX "solicitacoes_exclusao_status_idx" ON "solicitacoes_exclusao"("status");
ALTER TABLE "solicitacoes_exclusao" ADD CONSTRAINT "solicitacoes_exclusao_clienteId_fkey" FOREIGN KEY ("clienteId") REFERENCES "clientes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+282
View File
@@ -0,0 +1,282 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum Papel {
CLIENTE
ADMIN
}
enum TipoPessoa {
PF
PJ
}
enum TipoPergunta {
TEXTAREA
RADIO
CHECKBOX
ANEXO
}
enum StatusBriefing {
RASCUNHO
ENVIADO
EM_ANALISE
CONCLUIDO
}
enum CanalNotificacao {
EMAIL
WHATSAPP
}
enum StatusNotificacao {
PENDENTE
ENVIADO
ERRO
}
enum StatusSolicitacaoExclusao {
PENDENTE
PROCESSADA
CANCELADA
}
model User {
id String @id @default(cuid())
email String @unique
senhaHash String
papel Papel @default(CLIENTE)
criadoEm DateTime @default(now())
atualizadoEm DateTime @updatedAt
cliente Cliente?
passwordResetTokens PasswordResetToken[]
auditorias AuditoriaAcesso[]
notasInternas NotaInterna[]
@@map("users")
}
model Cliente {
id String @id @default(cuid())
userId String @unique
nomeCompleto String
cpfCifrado String
cpfHash String @unique
whatsapp String
tipo TipoPessoa @default(PF)
razaoSocial String?
cnpj String?
cep String?
logradouro String?
numero String?
complemento String?
bairro String?
cidade String?
uf String?
lgpdAceiteEm DateTime
criadoEm DateTime @default(now())
atualizadoEm DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
briefings Briefing[]
auditorias AuditoriaAcesso[]
solicitacoesExclusao SolicitacaoExclusao[]
@@index([tipo])
@@map("clientes")
}
model Secao {
id String @id @default(cuid())
ordem Int
titulo String
descricao String?
ativo Boolean @default(true)
criadoEm DateTime @default(now())
atualizadoEm DateTime @updatedAt
perguntas Pergunta[]
@@unique([ordem])
@@map("secoes")
}
model Pergunta {
id String @id @default(cuid())
secaoId String
ordem Int
rotulo String
dica String?
tipo TipoPergunta
opcoes Json
obrigatoria Boolean @default(false)
permiteComplemento Boolean @default(false)
ativo Boolean @default(true)
criadoEm DateTime @default(now())
atualizadoEm DateTime @updatedAt
secao Secao @relation(fields: [secaoId], references: [id])
ajuda Ajuda?
respostas Resposta[]
anexos Anexo[]
@@unique([secaoId, ordem])
@@index([tipo])
@@map("perguntas")
}
model Ajuda {
id String @id @default(cuid())
perguntaId String @unique
oQueResponder String
porQuePerguntamos String
miniExemplo String
criadoEm DateTime @default(now())
atualizadoEm DateTime @updatedAt
pergunta Pergunta @relation(fields: [perguntaId], references: [id])
@@map("ajudas")
}
model Briefing {
id String @id @default(cuid())
clienteId String
titulo String
status StatusBriefing @default(RASCUNHO)
confirmadoEm DateTime?
enviadoEm DateTime?
criadoEm DateTime @default(now())
atualizadoEm DateTime @updatedAt
cliente Cliente @relation(fields: [clienteId], references: [id])
respostas Resposta[]
anexos Anexo[]
notasInternas NotaInterna[]
notificacoes EnvioNotificacao[]
@@index([clienteId])
@@index([status])
@@map("briefings")
}
model Resposta {
id String @id @default(cuid())
briefingId String
perguntaId String
texto String?
complemento String?
selecionadas Json?
criadoEm DateTime @default(now())
atualizadoEm DateTime @updatedAt
briefing Briefing @relation(fields: [briefingId], references: [id], onDelete: Cascade)
pergunta Pergunta @relation(fields: [perguntaId], references: [id])
@@unique([briefingId, perguntaId])
@@index([perguntaId])
@@map("respostas")
}
model Anexo {
id String @id @default(cuid())
briefingId String
perguntaId String
nomeOriginal String
caminho String
mime String
tamanho Int
criadoEm DateTime @default(now())
briefing Briefing @relation(fields: [briefingId], references: [id], onDelete: Cascade)
pergunta Pergunta @relation(fields: [perguntaId], references: [id])
@@index([briefingId])
@@index([perguntaId])
@@map("anexos")
}
model PasswordResetToken {
id String @id @default(cuid())
userId String
tokenHash String @unique
expiraEm DateTime
usadoEm DateTime?
criadoEm DateTime @default(now())
user User @relation(fields: [userId], references: [id])
@@index([userId])
@@index([expiraEm])
@@map("password_reset_tokens")
}
model Configuracao {
id String @id @default(cuid())
chave String @unique
valor Json
criadoEm DateTime @default(now())
atualizadoEm DateTime @updatedAt
@@map("configuracoes")
}
model AuditoriaAcesso {
id String @id @default(cuid())
adminId String
clienteId String
acao String
criadoEm DateTime @default(now())
admin User @relation(fields: [adminId], references: [id])
cliente Cliente @relation(fields: [clienteId], references: [id])
@@index([adminId])
@@index([clienteId])
@@map("auditorias_acesso")
}
model NotaInterna {
id String @id @default(cuid())
briefingId String
adminId String
texto String
criadoEm DateTime @default(now())
briefing Briefing @relation(fields: [briefingId], references: [id], onDelete: Cascade)
admin User @relation(fields: [adminId], references: [id])
@@index([briefingId])
@@index([adminId])
@@map("notas_internas")
}
model EnvioNotificacao {
id String @id @default(cuid())
briefingId String
canal CanalNotificacao
destino String
assunto String?
status StatusNotificacao @default(PENDENTE)
erro String?
tentativas Int @default(0)
criadoEm DateTime @default(now())
atualizadoEm DateTime @updatedAt
enviadoEm DateTime?
briefing Briefing @relation(fields: [briefingId], references: [id], onDelete: Cascade)
@@index([briefingId])
@@index([status])
@@map("envios_notificacao")
}
model SolicitacaoExclusao {
id String @id @default(cuid())
clienteId String
motivo String?
status StatusSolicitacaoExclusao @default(PENDENTE)
criadoEm DateTime @default(now())
processadoEm DateTime?
cliente Cliente @relation(fields: [clienteId], references: [id])
@@index([clienteId])
@@index([status])
@@map("solicitacoes_exclusao")
}
+154
View File
@@ -0,0 +1,154 @@
import { PrismaClient, TipoPergunta } from "@prisma/client";
import argon2 from "argon2";
import briefingSeed from "./briefing-seed.json";
const prisma = new PrismaClient();
type SeedPergunta = {
ordem: number;
rotulo: string;
dica?: string;
tipo: keyof typeof TipoPergunta;
opcoes: string[];
permiteComplemento?: boolean;
obrigatoria?: boolean;
ajuda: {
oQueResponder: string;
porQuePerguntamos: string;
miniExemplo: string;
};
};
type SeedSecao = {
ordem: number;
titulo: string;
descricao?: string;
perguntas: SeedPergunta[];
};
async function seedConfiguracoes() {
const meta = briefingSeed.meta;
await prisma.configuracao.upsert({
where: { chave: "comoPreencher" },
update: { valor: meta.comoPreencher },
create: { chave: "comoPreencher", valor: meta.comoPreencher }
});
await prisma.configuracao.upsert({
where: { chave: "avisoSenhas" },
update: { valor: meta.avisoSenhas },
create: { chave: "avisoSenhas", valor: meta.avisoSenhas }
});
await prisma.configuracao.upsert({
where: { chave: "confirmacaoCliente" },
update: { valor: meta.confirmacaoCliente },
create: { chave: "confirmacaoCliente", valor: meta.confirmacaoCliente }
});
}
async function seedBriefing() {
for (const secaoSeed of briefingSeed.secoes as SeedSecao[]) {
const secao = await prisma.secao.upsert({
where: { ordem: secaoSeed.ordem },
update: {
titulo: secaoSeed.titulo,
descricao: secaoSeed.descricao ?? null,
ativo: true
},
create: {
ordem: secaoSeed.ordem,
titulo: secaoSeed.titulo,
descricao: secaoSeed.descricao ?? null,
ativo: true
}
});
for (const perguntaSeed of secaoSeed.perguntas) {
const pergunta = await prisma.pergunta.upsert({
where: {
secaoId_ordem: {
secaoId: secao.id,
ordem: perguntaSeed.ordem
}
},
update: {
rotulo: perguntaSeed.rotulo,
dica: perguntaSeed.dica ?? null,
tipo: perguntaSeed.tipo,
opcoes: perguntaSeed.opcoes,
obrigatoria: perguntaSeed.obrigatoria ?? false,
permiteComplemento: perguntaSeed.permiteComplemento ?? false,
ativo: true
},
create: {
secaoId: secao.id,
ordem: perguntaSeed.ordem,
rotulo: perguntaSeed.rotulo,
dica: perguntaSeed.dica ?? null,
tipo: perguntaSeed.tipo,
opcoes: perguntaSeed.opcoes,
obrigatoria: perguntaSeed.obrigatoria ?? false,
permiteComplemento: perguntaSeed.permiteComplemento ?? false,
ativo: true
}
});
await prisma.ajuda.upsert({
where: { perguntaId: pergunta.id },
update: {
oQueResponder: perguntaSeed.ajuda.oQueResponder,
porQuePerguntamos: perguntaSeed.ajuda.porQuePerguntamos,
miniExemplo: perguntaSeed.ajuda.miniExemplo
},
create: {
perguntaId: pergunta.id,
oQueResponder: perguntaSeed.ajuda.oQueResponder,
porQuePerguntamos: perguntaSeed.ajuda.porQuePerguntamos,
miniExemplo: perguntaSeed.ajuda.miniExemplo
}
});
}
}
}
async function seedAdmin() {
const email = process.env.ADMIN_EMAIL?.trim().toLowerCase();
const password = process.env.ADMIN_INITIAL_PASSWORD;
if (!email || !password) {
return;
}
const existingAdmin = await prisma.user.findUnique({
where: { email }
});
if (existingAdmin) {
return;
}
await prisma.user.create({
data: {
email,
senhaHash: await argon2.hash(password),
papel: "ADMIN"
}
});
}
async function main() {
await seedConfiguracoes();
await seedBriefing();
await seedAdmin();
}
main()
.catch((error) => {
process.stderr.write(`Seed falhou: ${error instanceof Error ? error.message : "erro desconhecido"}\n`);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});