import { z } from "zod"; import { adminProcedure, createTRPCRouter, invalidateRoleDefaultsCache, protectedProcedure } from "../trpc.js"; import { createAuditEntry } from "../lib/audit.js"; export const systemRoleConfigRouter = createTRPCRouter({ /** List all role configs (sorted by sortOrder) */ list: protectedProcedure.query(async ({ ctx }) => { return ctx.db.systemRoleConfig.findMany({ orderBy: { sortOrder: "asc" }, }); }), /** Update a role's default permissions, label, description, and color */ update: adminProcedure .input( z.object({ role: z.string(), label: z.string().min(1).optional(), description: z.string().nullable().optional(), color: z.string().nullable().optional(), defaultPermissions: z.array(z.string()).optional(), }), ) .mutation(async ({ ctx, input }) => { const existing = await ctx.db.systemRoleConfig.findUnique({ where: { role: input.role as never }, }); const data: Record = {}; if (input.label !== undefined) data.label = input.label; if (input.description !== undefined) data.description = input.description; if (input.color !== undefined) data.color = input.color; if (input.defaultPermissions !== undefined) data.defaultPermissions = input.defaultPermissions; const result = await ctx.db.systemRoleConfig.update({ where: { role: input.role as never }, data, }); // Invalidate cached role defaults so changes take effect immediately invalidateRoleDefaultsCache(); void createAuditEntry({ db: ctx.db, entityType: "SystemRoleConfig", entityId: input.role, entityName: result.label, action: "UPDATE", userId: ctx.dbUser?.id, before: (existing ?? {}) as unknown as Record, after: result as unknown as Record, source: "ui", }); return result; }), });