/** * tickets.schema.ts * * Schemas Zod para validação de entrada e saída do módulo de tickets. * Usados tanto pelo Fastify (validação automática de requests) * quanto pelo TypeScript (inferência de tipos). */ import { z } from 'zod'; import { TICKET_PRIORITIES, TICKET_STATUSES } from '@/db/schema.js'; // ─── Criação de Ticket ──────────────────────────────────────────────────────── export const createTicketBodySchema = z.object({ title: z .string({ required_error: 'Título é obrigatório' }) .min(5, 'Título deve ter no mínimo 5 caracteres') .max(150, 'Título deve ter no máximo 150 caracteres') .trim(), description: z .string({ required_error: 'Descrição é obrigatória' }) .min(10, 'Descrição deve ter no mínimo 10 caracteres') .trim(), priority: z.enum(TICKET_PRIORITIES).default('medium'), categoryId: z.number().int().positive().optional(), // Em uma implementação real, o creatorId viria do token JWT. // Por ora, aceita no body para facilitar o desenvolvimento iterativo. creatorId: z .number({ required_error: 'creatorId é obrigatório' }) .int() .positive(), }); export type CreateTicketBody = z.infer; // ─── Listagem de Tickets (filtros + paginação) ──────────────────────────────── export const listTicketsQuerySchema = z.object({ status: z.enum(TICKET_STATUSES).optional(), priority: z.enum(TICKET_PRIORITIES).optional(), assigneeId: z.coerce.number().int().positive().optional(), creatorId: z.coerce.number().int().positive().optional(), categoryId: z.coerce.number().int().positive().optional(), // Paginação page: z.coerce.number().int().min(1).default(1), limit: z.coerce.number().int().min(1).max(100).default(20), }); export type ListTicketsQuery = z.infer; // ─── Parâmetros de rota ─────────────────────────────────────────────────────── export const ticketParamsSchema = z.object({ id: z.coerce.number().int().positive(), }); export type TicketParams = z.infer; // ─── Shape de resposta ──────────────────────────────────────────────────────── export const ticketResponseSchema = z.object({ id: z.number(), title: z.string(), description: z.string(), status: z.enum(TICKET_STATUSES), priority: z.enum(TICKET_PRIORITIES), creatorId: z.number(), assigneeId: z.number().nullable(), categoryId: z.number().nullable(), dueAt: z.string().nullable(), resolvedAt: z.string().nullable(), createdAt: z.string(), updatedAt: z.string(), }); export const listTicketsResponseSchema = z.object({ data: z.array(ticketResponseSchema), meta: z.object({ page: z.number(), limit: z.number(), total: z.number(), totalPages: z.number(), }), });