sistema-de-chamados/web/convex/rbac.ts
esdrasrenan 7946b8d017 feat: migrate auth stack and admin portal
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2025-10-05 17:25:57 -03:00

53 lines
1.7 KiB
TypeScript

import { ConvexError } from "convex/values"
import type { Id } from "./_generated/dataModel"
import type { MutationCtx, QueryCtx } from "./_generated/server"
const STAFF_ROLES = new Set(["ADMIN", "MANAGER", "AGENT", "COLLABORATOR"])
const CUSTOMER_ROLE = "CUSTOMER"
type Ctx = QueryCtx | MutationCtx
function normalizeRole(role?: string | null) {
return role?.toUpperCase() ?? null
}
async function getUser(ctx: Ctx, userId: Id<"users">) {
const user = await ctx.db.get(userId)
if (!user) {
throw new ConvexError("Usuário não encontrado")
}
return user
}
export async function requireUser(ctx: Ctx, userId: Id<"users">, tenantId?: string) {
const user = await getUser(ctx, userId)
if (tenantId && user.tenantId !== tenantId) {
throw new ConvexError("Usuário não pertence a este tenant")
}
return { user, role: normalizeRole(user.role) }
}
export async function requireStaff(ctx: Ctx, userId: Id<"users">, tenantId?: string) {
const result = await requireUser(ctx, userId, tenantId)
if (!result.role || !STAFF_ROLES.has(result.role)) {
throw new ConvexError("Acesso restrito à equipe interna")
}
return result
}
export async function requireAdmin(ctx: Ctx, userId: Id<"users">, tenantId?: string) {
const result = await requireStaff(ctx, userId, tenantId)
if (result.role !== "ADMIN") {
throw new ConvexError("Apenas administradores podem executar esta ação")
}
return result
}
export async function requireCustomer(ctx: Ctx, userId: Id<"users">, tenantId?: string) {
const result = await requireUser(ctx, userId, tenantId)
if (result.role !== CUSTOMER_ROLE) {
throw new ConvexError("Acesso restrito ao portal do cliente")
}
return result
}