chore: reorganize project structure and ensure default queues

This commit is contained in:
Esdras Renan 2025-10-06 22:59:35 -03:00
parent 854887f499
commit 1cccb852a5
201 changed files with 417 additions and 838 deletions

View file

@ -0,0 +1,156 @@
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()
})