docs: registrar fluxo do updater e atualizar chaves

This commit is contained in:
Esdras Renan 2025-10-12 04:06:29 -03:00
parent 206d00700e
commit b5fd920efd
50 changed files with 980 additions and 93 deletions

View file

@ -23,6 +23,13 @@ const registerSchema = z
serialNumbers: z.array(z.string()).default([]),
metadata: z.record(z.string(), z.unknown()).optional(),
registeredBy: z.string().optional(),
accessRole: z.enum(["collaborator", "manager"]).optional(),
collaborator: z
.object({
email: z.string().email(),
name: z.string().optional(),
})
.optional(),
})
.refine(
(data) => (data.macAddresses && data.macAddresses.length > 0) || (data.serialNumbers && data.serialNumbers.length > 0),
@ -61,15 +68,43 @@ export async function POST(request: Request) {
const client = new ConvexHttpClient(convexUrl)
try {
const tenantId = payload.tenantId ?? DEFAULT_TENANT_ID
const persona = payload.accessRole ?? undefined
const collaborator = payload.collaborator ?? null
if (persona && !collaborator) {
return jsonWithCors(
{ error: "Informe os dados do colaborador/gestor ao definir o perfil de acesso." },
400,
request.headers.get("origin"),
CORS_METHODS
)
}
let metadataPayload: Record<string, unknown> | undefined = payload.metadata
? { ...(payload.metadata as Record<string, unknown>) }
: undefined
if (collaborator) {
const collaboratorMeta = {
email: collaborator.email,
name: collaborator.name ?? null,
role: persona ?? "collaborator",
}
metadataPayload = {
...(metadataPayload ?? {}),
collaborator: collaboratorMeta,
}
}
const registration = await client.mutation(api.machines.register, {
provisioningSecret: payload.provisioningSecret,
tenantId: payload.tenantId ?? DEFAULT_TENANT_ID,
tenantId,
companySlug: payload.companySlug ?? undefined,
hostname: payload.hostname,
os: payload.os,
macAddresses: payload.macAddresses,
serialNumbers: payload.serialNumbers,
metadata: payload.metadata,
metadata: metadataPayload,
registeredBy: payload.registeredBy,
})
@ -78,6 +113,7 @@ export async function POST(request: Request) {
tenantId: registration.tenantId ?? DEFAULT_TENANT_ID,
hostname: payload.hostname,
machineToken: registration.machineToken,
persona,
})
await client.mutation(api.machines.linkAuthAccount, {
@ -86,6 +122,34 @@ export async function POST(request: Request) {
authEmail: account.authEmail,
})
let assignedUserId: Id<"users"> | undefined
if (persona && collaborator) {
const ensuredUser = (await client.mutation(api.users.ensureUser, {
tenantId,
email: collaborator.email,
name: collaborator.name ?? collaborator.email,
avatarUrl: undefined,
role: persona.toUpperCase(),
companyId: registration.companyId ? (registration.companyId as Id<"companies">) : undefined,
})) as { _id?: Id<"users"> } | null
assignedUserId = ensuredUser?._id
await client.mutation(api.machines.updatePersona, {
machineId: registration.machineId as Id<"machines">,
persona,
...(assignedUserId ? { assignedUserId } : {}),
assignedUserEmail: collaborator.email,
assignedUserName: collaborator.name ?? undefined,
assignedUserRole: persona === "manager" ? "MANAGER" : "COLLABORATOR",
})
} else {
await client.mutation(api.machines.updatePersona, {
machineId: registration.machineId as Id<"machines">,
persona: "",
})
}
return jsonWithCors(
{
machineId: registration.machineId,
@ -95,6 +159,9 @@ export async function POST(request: Request) {
machineToken: registration.machineToken,
machineEmail: account.authEmail,
expiresAt: registration.expiresAt,
persona: persona ?? null,
assignedUserId: assignedUserId ?? null,
collaborator: collaborator ?? null,
},
{ status: 201 },
request.headers.get("origin"),

View file

@ -0,0 +1,77 @@
import { NextResponse } from "next/server"
import { cookies } from "next/headers"
import { ConvexHttpClient } from "convex/browser"
import { api } from "@/convex/_generated/api"
import type { Id } from "@/convex/_generated/dataModel"
import { env } from "@/lib/env"
import { assertAuthenticatedSession } from "@/lib/auth-server"
const MACHINE_CTX_COOKIE = "machine_ctx"
function decodeMachineCookie(value: string) {
try {
const json = Buffer.from(value, "base64url").toString("utf8")
return JSON.parse(json) as {
machineId: string
persona: string | null
assignedUserId: string | null
assignedUserEmail: string | null
assignedUserName: string | null
assignedUserRole: string | null
}
} catch {
return null
}
}
export async function GET() {
const session = await assertAuthenticatedSession()
if (!session || session.user?.role !== "machine") {
return NextResponse.json({ error: "Sessão de máquina não encontrada." }, { status: 403 })
}
const cookieStore = await cookies()
const cookieValue = cookieStore.get(MACHINE_CTX_COOKIE)?.value
if (!cookieValue) {
return NextResponse.json({ error: "Contexto da máquina ausente." }, { status: 404 })
}
const decoded = decodeMachineCookie(cookieValue)
if (!decoded?.machineId) {
return NextResponse.json({ error: "Contexto da máquina inválido." }, { status: 400 })
}
const convexUrl = env.NEXT_PUBLIC_CONVEX_URL
if (!convexUrl) {
return NextResponse.json({ error: "Convex não configurado." }, { status: 500 })
}
const client = new ConvexHttpClient(convexUrl)
try {
const context = (await client.query(api.machines.getContext, {
machineId: decoded.machineId as Id<"machines">,
})) as {
id: string
tenantId: string
companyId: string | null
companySlug: string | null
persona: string | null
assignedUserId: string | null
assignedUserEmail: string | null
assignedUserName: string | null
assignedUserRole: string | null
metadata: Record<string, unknown> | null
authEmail: string | null
}
return NextResponse.json({
machine: context,
cookie: decoded,
})
} catch (error) {
console.error("[machines.session] Falha ao obter contexto da máquina", error)
return NextResponse.json({ error: "Falha ao obter contexto da máquina." }, { status: 500 })
}
}

View file

@ -47,6 +47,24 @@ export async function POST(request: Request) {
response.headers.set(key, value)
})
const machineCookiePayload = {
machineId: session.machine.id,
persona: session.machine.persona,
assignedUserId: session.machine.assignedUserId,
assignedUserEmail: session.machine.assignedUserEmail,
assignedUserName: session.machine.assignedUserName,
assignedUserRole: session.machine.assignedUserRole,
}
response.cookies.set({
name: "machine_ctx",
value: Buffer.from(JSON.stringify(machineCookiePayload)).toString("base64url"),
httpOnly: true,
sameSite: "lax",
secure: true,
path: "/",
maxAge: 60 * 60 * 24 * 30,
})
applyCorsHeaders(response, request.headers.get("origin"), CORS_METHODS)
return response