feat: sync convex companies and dashboard metrics

This commit is contained in:
Esdras Renan 2025-10-18 21:13:20 -03:00
parent 4f52114b48
commit 7a3eca9361
10 changed files with 356 additions and 19 deletions

View file

@ -4,6 +4,7 @@ import { prisma } from "@/lib/prisma"
import { assertStaffSession } from "@/lib/auth-server"
import { isAdmin } from "@/lib/authz"
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"
import { removeConvexCompany, syncConvexCompany } from "@/server/companies-sync"
export const runtime = "nodejs"
@ -45,6 +46,19 @@ export async function PATCH(request: Request, { params }: { params: Promise<{ id
// Atualize o client quando possível; por ora liberamos o shape dinamicamente.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const company = await prisma.company.update({ where: { id }, data: updates as any })
if (company.provisioningCode) {
const synced = await syncConvexCompany({
tenantId: company.tenantId,
slug: company.slug,
name: company.name,
provisioningCode: company.provisioningCode,
})
if (!synced) {
console.warn("[admin.companies] Convex não configurado; atualização aplicada apenas no Prisma.")
}
}
return NextResponse.json({ company })
} catch (error) {
console.error("Failed to update company", error)
@ -65,7 +79,7 @@ export async function DELETE(_: Request, { params }: { params: Promise<{ id: str
const company = await prisma.company.findUnique({
where: { id },
select: { id: true, tenantId: true, name: true },
select: { id: true, tenantId: true, name: true, slug: true },
})
if (!company) {
@ -90,6 +104,16 @@ export async function DELETE(_: Request, { params }: { params: Promise<{ id: str
return { detachedUsers: users.count, detachedTickets: tickets.count }
})
if (company.slug) {
const removed = await removeConvexCompany({
tenantId: company.tenantId,
slug: company.slug,
})
if (!removed) {
console.warn("[admin.companies] Convex não configurado; empresa removida apenas no Prisma.")
}
}
return NextResponse.json({ ok: true, ...result })
} catch (error) {
if (error instanceof PrismaClientKnownRequestError && error.code === "P2003") {

View file

@ -5,6 +5,7 @@ import { prisma } from "@/lib/prisma"
import { assertStaffSession } from "@/lib/auth-server"
import { isAdmin } from "@/lib/authz"
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"
import { syncConvexCompany } from "@/server/companies-sync"
export const runtime = "nodejs"
@ -64,6 +65,19 @@ export async function POST(request: Request) {
address: address ? String(address) : null,
},
})
if (company.provisioningCode) {
const synced = await syncConvexCompany({
tenantId: company.tenantId,
slug: company.slug,
name: company.name,
provisioningCode: company.provisioningCode,
})
if (!synced) {
console.warn("[admin.companies] Convex não configurado; empresa criada apenas no Prisma.")
}
}
return NextResponse.json({ company })
} catch (error) {
console.error("Failed to create company", error)

View file

@ -1,12 +1,12 @@
import { randomBytes } from "crypto"
import { Prisma } from "@prisma/client"
import { api } from "@/convex/_generated/api"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { env } from "@/lib/env"
import { normalizeSlug, slugify } from "@/lib/slug"
import { prisma } from "@/lib/prisma"
import { createCorsPreflight, jsonWithCors } from "@/server/cors"
import { createConvexClient, ConvexConfigurationError } from "@/server/convex-client"
import { ConvexConfigurationError } from "@/server/convex-client"
import { syncConvexCompany } from "@/server/companies-sync"
export const runtime = "nodejs"
@ -31,11 +31,6 @@ function extractSecret(request: Request, url: URL): string | null {
return null
}
async function ensureConvexCompany(params: { tenantId: string; slug: string; name: string; provisioningCode: string }) {
const client = createConvexClient()
await client.mutation(api.companies.ensureProvisioned, params)
}
export async function OPTIONS(request: Request) {
return createCorsPreflight(request.headers.get("origin"), CORS_METHODS)
}
@ -158,12 +153,15 @@ export async function POST(request: Request) {
}))
try {
await ensureConvexCompany({
const synced = await syncConvexCompany({
tenantId,
slug: company.slug,
name: company.name,
provisioningCode: company.provisioningCode,
})
if (!synced) {
throw new ConvexConfigurationError()
}
} catch (error) {
if (error instanceof ConvexConfigurationError) {
return jsonWithCors({ error: error.message }, 500, origin, CORS_METHODS)