Files
pn-new-crm/src/lib/validators/roles.ts
Matt 905852b8a5 feat(permissions): carve out dedicated payments resource
Payments (deposit / balance / refund records on an interest) used to
share `invoices.record_payment`, which forces a port that doesn't
issue invoices at all to still navigate the invoicing permission
group to grant its sales reps payment-recording rights. Splitting
the resource lets admins gate the two surfaces independently.

The new resource has three actions:
  - view   — gates the UI affordance (API reads still go through
             `interests.view`)
  - record — POST / PATCH a payment
  - delete — DELETE a payment record

Seed maps updated for all six system roles; existing role rows +
per-user permission overrides are backfilled by migration 0064 so
upgrades don't silently lose access. Two call sites (POST /interests/
[id]/payments, PATCH /payments/[id]) → payments.record; one
(DELETE /payments/[id]) → payments.delete. The PermissionGates on the
payments-section UI swap to the new keys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 03:46:01 +02:00

37 lines
1.1 KiB
TypeScript

import { z } from 'zod';
const permissionGroupSchema = z.record(z.string(), z.boolean());
const rolePermissionsSchema = z.object({
clients: permissionGroupSchema,
interests: permissionGroupSchema,
berths: permissionGroupSchema,
documents: permissionGroupSchema,
expenses: permissionGroupSchema,
invoices: permissionGroupSchema,
payments: permissionGroupSchema,
files: permissionGroupSchema,
email: permissionGroupSchema,
reminders: permissionGroupSchema,
calendar: permissionGroupSchema,
reports: permissionGroupSchema,
document_templates: permissionGroupSchema,
admin: permissionGroupSchema,
});
export const createRoleSchema = z.object({
name: z.string().min(1).max(100),
description: z.string().max(500).optional(),
permissions: rolePermissionsSchema,
});
export type CreateRoleInput = z.infer<typeof createRoleSchema>;
export const updateRoleSchema = z.object({
name: z.string().min(1).max(100).optional(),
description: z.string().max(500).nullable().optional(),
permissions: rolePermissionsSchema.optional(),
});
export type UpdateRoleInput = z.infer<typeof updateRoleSchema>;