feat: dispositivos e ajustes de csat e relatórios

This commit is contained in:
codex-bot 2025-11-03 19:29:50 -03:00
parent 25d2a9b062
commit e0ef66555d
86 changed files with 5811 additions and 992 deletions

View file

@ -10,7 +10,7 @@ export async function GET(_req: NextRequest, ctx: { params: Promise<{ id: string
const client = createConvexClient()
const { id } = await ctx.params
const machineId = id as Id<"machines">
const data = (await client.query(api.machines.getById, { id: machineId, includeMetadata: true })) as unknown
const data = (await client.query(api.devices.getById, { id: machineId, includeMetadata: true })) as unknown
if (!data) return NextResponse.json({ error: "Not found" }, { status: 404 })
return NextResponse.json(data, { status: 200 })
} catch (err) {

View file

@ -36,13 +36,13 @@ export async function GET(_request: Request, context: RouteContext) {
const tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID
try {
const machine = (await client.query(api.machines.getById, {
const machine = (await client.query(api.devices.getById, {
id: machineId,
includeMetadata: true,
})) as MachineInventoryRecord | null
if (!machine || machine.tenantId !== tenantId) {
return NextResponse.json({ error: "Máquina não encontrada" }, { status: 404 })
return NextResponse.json({ error: "Dispositivo não encontrada" }, { status: 404 })
}
const workbook = buildMachinesInventoryWorkbook([machine], {
@ -64,6 +64,6 @@ export async function GET(_request: Request, context: RouteContext) {
})
} catch (error) {
console.error("Failed to export machine inventory", error)
return NextResponse.json({ error: "Falha ao gerar planilha da máquina" }, { status: 500 })
return NextResponse.json({ error: "Falha ao gerar planilha da dispositivo" }, { status: 500 })
}
}

View file

@ -38,7 +38,7 @@ export async function POST(request: Request) {
const client = new ConvexHttpClient(convexUrl)
try {
const machine = (await client.query(api.machines.getContext, {
const machine = (await client.query(api.devices.getContext, {
machineId: parsed.machineId as Id<"machines">,
})) as {
id: string
@ -47,7 +47,7 @@ export async function POST(request: Request) {
} | null
if (!machine) {
return NextResponse.json({ error: "Máquina não encontrada" }, { status: 404 })
return NextResponse.json({ error: "Dispositivo não encontrada" }, { status: 404 })
}
const tenantId = machine.tenantId ?? session.user.tenantId ?? DEFAULT_TENANT_ID
@ -61,7 +61,7 @@ export async function POST(request: Request) {
companyId: machine.companyId ? (machine.companyId as Id<"companies">) : undefined,
})) as { _id?: Id<"users"> } | null
await client.mutation(api.machines.updatePersona, {
await client.mutation(api.devices.updatePersona, {
machineId: parsed.machineId as Id<"machines">,
persona: parsed.persona,
assignedUserId: ensuredUser?._id,
@ -73,6 +73,6 @@ export async function POST(request: Request) {
return NextResponse.json({ ok: true })
} catch (error) {
console.error("[machines.access]", error)
return NextResponse.json({ error: "Falha ao atualizar acesso da máquina" }, { status: 500 })
return NextResponse.json({ error: "Falha ao atualizar acesso da dispositivo" }, { status: 500 })
}
}

View file

@ -28,7 +28,7 @@ vi.mock("@/lib/auth-server", () => ({
assertAuthenticatedSession: assertAuthenticatedSession,
}))
describe("POST /api/admin/machines/delete", () => {
describe("POST /api/admin/devices/delete", () => {
const originalEnv = process.env.NEXT_PUBLIC_CONVEX_URL
let restoreConsole: (() => void) | undefined
@ -65,7 +65,7 @@ describe("POST /api/admin/machines/delete", () => {
it("returns ok when the machine removal succeeds", async () => {
const { POST } = await import("./route")
const response = await POST(
new Request("http://localhost/api/admin/machines/delete", {
new Request("http://localhost/api/admin/devices/delete", {
method: "POST",
body: JSON.stringify({ machineId: "jn_machine" }),
})
@ -81,13 +81,13 @@ describe("POST /api/admin/machines/delete", () => {
it("still succeeds when the Convex machine is already missing", async () => {
mutationMock.mockImplementation(async (_ctx, payload) => {
if (payload && typeof payload === "object" && "machineId" in payload) {
throw new Error("Máquina não encontrada")
throw new Error("Dispositivo não encontrada")
}
return { _id: "user_123" }
})
const { POST } = await import("./route")
const response = await POST(
new Request("http://localhost/api/admin/machines/delete", {
new Request("http://localhost/api/admin/devices/delete", {
method: "POST",
body: JSON.stringify({ machineId: "jn_machine" }),
})
@ -107,14 +107,14 @@ describe("POST /api/admin/machines/delete", () => {
})
const { POST } = await import("./route")
const response = await POST(
new Request("http://localhost/api/admin/machines/delete", {
new Request("http://localhost/api/admin/devices/delete", {
method: "POST",
body: JSON.stringify({ machineId: "jn_machine" }),
})
)
expect(response.status).toBe(500)
await expect(response.json()).resolves.toEqual({ error: "Falha ao remover máquina no Convex" })
await expect(response.json()).resolves.toEqual({ error: "Falha ao remover dispositivo no Convex" })
expect(deleteManyMock).not.toHaveBeenCalled()
})
})

View file

@ -50,17 +50,17 @@ export async function POST(request: Request) {
let machineMissing = false
try {
await convex.mutation(api.machines.remove, {
await convex.mutation(api.devices.remove, {
machineId: parsed.data.machineId as Id<"machines">,
actorId,
})
} catch (error) {
const message = error instanceof Error ? error.message : ""
if (message.includes("Máquina não encontrada")) {
if (message.includes("Dispositivo não encontrada")) {
machineMissing = true
} else {
console.error("[machines.delete] Convex failure", error)
return NextResponse.json({ error: "Falha ao remover máquina no Convex" }, { status: 500 })
return NextResponse.json({ error: "Falha ao remover dispositivo no Convex" }, { status: 500 })
}
}
@ -70,6 +70,6 @@ export async function POST(request: Request) {
return NextResponse.json({ ok: true, machineMissing })
} catch (error) {
console.error("[machines.delete] Falha ao excluir", error)
return NextResponse.json({ error: "Falha ao excluir máquina" }, { status: 500 })
return NextResponse.json({ error: "Falha ao excluir dispositivo" }, { status: 500 })
}
}

View file

@ -27,7 +27,7 @@ export async function POST(request: Request) {
const client = new ConvexHttpClient(convexUrl)
try {
await client.mutation(api.machines.linkUser, {
await client.mutation(api.devices.linkUser, {
machineId: parsed.machineId as Id<"machines">,
email: parsed.email,
})
@ -53,7 +53,7 @@ export async function DELETE(request: Request) {
const client = new ConvexHttpClient(convexUrl)
try {
await client.mutation(api.machines.unlinkUser, {
await client.mutation(api.devices.unlinkUser, {
machineId: parsed.data.machineId as Id<"machines">,
userId: parsed.data.userId as Id<"users">,
})

View file

@ -59,7 +59,7 @@ export async function POST(request: Request) {
return NextResponse.json({ ok: true })
} catch (error) {
console.error("[machines.rename] Falha ao renomear", error)
return NextResponse.json({ error: "Falha ao renomear máquina" }, { status: 500 })
return NextResponse.json({ error: "Falha ao renomear dispositivo" }, { status: 500 })
}
}

View file

@ -54,7 +54,7 @@ export async function POST(request: Request) {
return NextResponse.json({ ok: true, revoked: result?.revoked ?? 0 })
} catch (error) {
console.error("[machines.resetAgent] Falha ao resetar agente", error)
return NextResponse.json({ error: "Falha ao resetar agente da máquina" }, { status: 500 })
return NextResponse.json({ error: "Falha ao resetar agente da dispositivo" }, { status: 500 })
}
}

View file

@ -56,6 +56,6 @@ export async function POST(request: Request) {
return NextResponse.json({ ok: true })
} catch (error) {
console.error("[machines.toggleActive] Falha ao atualizar status", error)
return NextResponse.json({ error: "Falha ao atualizar status da máquina" }, { status: 500 })
return NextResponse.json({ error: "Falha ao atualizar status da dispositivo" }, { status: 500 })
}
}

View file

@ -41,7 +41,7 @@ export async function POST(request: Request, { params }: { params: Promise<{ id:
}
if (targetRole === "machine") {
return NextResponse.json({ error: "Contas de máquina não possuem senha web" }, { status: 400 })
return NextResponse.json({ error: "Contas de dispositivo não possuem senha web" }, { status: 400 })
}
const body = (await request.json().catch(() => null)) as { password?: string } | null

View file

@ -158,7 +158,7 @@ export async function PATCH(request: Request, { params }: { params: Promise<{ id
}
if ((user.role ?? "").toLowerCase() === "machine") {
return NextResponse.json({ error: "Ajustes de máquinas devem ser feitos em Admin ▸ Máquinas" }, { status: 400 })
return NextResponse.json({ error: "Ajustes de dispositivos devem ser feitos em Admin ▸ Dispositivos" }, { status: 400 })
}
if (!sessionIsAdmin && !canManageRole(nextRole)) {
@ -356,7 +356,7 @@ export async function DELETE(_: Request, { params }: { params: Promise<{ id: str
}
if (target.role === "machine") {
return NextResponse.json({ error: "Os agentes de máquina devem ser removidos via módulo de máquinas." }, { status: 400 })
return NextResponse.json({ error: "Os agentes de dispositivo devem ser removidos via módulo de dispositivos." }, { status: 400 })
}
if (target.email === session.user.email) {