import "dotenv/config" import { PrismaClient } from "@prisma/client" import { ConvexHttpClient } from "convex/browser" const prisma = new PrismaClient() function toMillis(date) { return date instanceof Date ? date.getTime() : date ? new Date(date).getTime() : undefined } function normalizeString(value, fallback = "") { if (!value) return fallback return value.trim() } function slugify(value) { return normalizeString(value) .toLowerCase() .replace(/[^a-z0-9\s-]/g, "") .replace(/\s+/g, "-") .replace(/-+/g, "-") || undefined } async function main() { const tenantId = process.env.SYNC_TENANT_ID || "tenant-atlas" const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL || "http://127.0.0.1:3210" const secret = process.env.CONVEX_SYNC_SECRET if (!secret) { console.error("CONVEX_SYNC_SECRET não configurado. Configure no .env.") process.exit(1) } const [users, queues, tickets, companies] = await Promise.all([ prisma.user.findMany({ include: { teams: { include: { team: true }, }, company: true, }, }), prisma.queue.findMany(), prisma.ticket.findMany({ include: { requester: true, assignee: true, queue: true, company: true, comments: { include: { author: true, }, }, events: true, }, orderBy: { createdAt: "asc" }, }), prisma.company.findMany(), ]) const userSnapshot = users.map((user) => ({ email: user.email, name: normalizeString(user.name, user.email), role: user.role, avatarUrl: user.avatarUrl ?? undefined, teams: user.teams .map((membership) => membership.team?.name) .filter((name) => Boolean(name) && typeof name === "string"), companySlug: user.company?.slug ?? undefined, })) const queueSnapshot = queues.map((queue) => ({ name: normalizeString(queue.name, queue.slug ?? queue.id), slug: queue.slug ? queue.slug : normalizeString(queue.name, queue.id).toLowerCase().replace(/\s+/g, "-"), })) const referenceFallbackStart = 41000 let referenceCounter = referenceFallbackStart const ticketSnapshot = tickets.map((ticket) => { const reference = ticket.reference && ticket.reference > 0 ? ticket.reference : ++referenceCounter const requesterEmail = ticket.requester?.email ?? userSnapshot[0]?.email ?? "unknown@example.com" const assigneeEmail = ticket.assignee?.email ?? undefined const queueSlug = ticket.queue?.slug ?? slugify(ticket.queue?.name) const companySlug = ticket.company?.slug ?? ticket.requester?.company?.slug ?? undefined return { reference, subject: normalizeString(ticket.subject, `Ticket ${reference}`), summary: ticket.summary ?? undefined, status: ticket.status, priority: ticket.priority, channel: ticket.channel, queueSlug: queueSlug ?? undefined, requesterEmail, assigneeEmail, companySlug, dueAt: toMillis(ticket.dueAt) ?? undefined, firstResponseAt: toMillis(ticket.firstResponseAt) ?? undefined, resolvedAt: toMillis(ticket.resolvedAt) ?? undefined, closedAt: toMillis(ticket.closedAt) ?? undefined, createdAt: toMillis(ticket.createdAt) ?? Date.now(), updatedAt: toMillis(ticket.updatedAt) ?? Date.now(), tags: Array.isArray(ticket.tags) ? ticket.tags : undefined, comments: ticket.comments.map((comment) => ({ authorEmail: comment.author?.email ?? requesterEmail, visibility: comment.visibility, body: comment.body, createdAt: toMillis(comment.createdAt) ?? Date.now(), updatedAt: toMillis(comment.updatedAt) ?? Date.now(), })), events: ticket.events.map((event) => ({ type: event.type, payload: event.payload ?? {}, createdAt: toMillis(event.createdAt) ?? Date.now(), })), } }) const companySnapshot = companies.map((company) => ({ slug: company.slug ?? slugify(company.name), name: company.name, cnpj: company.cnpj ?? undefined, domain: company.domain ?? undefined, phone: company.phone ?? undefined, description: company.description ?? undefined, address: company.address ?? undefined, createdAt: toMillis(company.createdAt) ?? Date.now(), updatedAt: toMillis(company.updatedAt) ?? Date.now(), })) const client = new ConvexHttpClient(convexUrl) const result = await client.mutation("migrations:importPrismaSnapshot", { secret, snapshot: { tenantId, companies: companySnapshot, users: userSnapshot, queues: queueSnapshot, tickets: ticketSnapshot, }, }) console.log("Sincronização concluída:", result) } main() .catch((error) => { console.error(error) process.exitCode = 1 }) .finally(async () => { await prisma.$disconnect() })