import { defineTable } from 'convex/server'; import { v } from 'convex/values'; export const ticketsTables = { tickets: defineTable({ numero: v.string(), titulo: v.string(), descricao: v.string(), tipo: v.union( v.literal('reclamacao'), v.literal('elogio'), v.literal('sugestao'), v.literal('chamado') ), categoria: v.optional(v.string()), status: v.union( v.literal('aberto'), v.literal('em_andamento'), v.literal('aguardando_usuario'), v.literal('resolvido'), v.literal('encerrado'), v.literal('cancelado') ), prioridade: v.union( v.literal('baixa'), v.literal('media'), v.literal('alta'), v.literal('critica') ), solicitanteId: v.id('usuarios'), solicitanteNome: v.string(), solicitanteEmail: v.string(), responsavelId: v.optional(v.id('usuarios')), setorResponsavel: v.optional(v.string()), slaConfigId: v.optional(v.id('slaConfigs')), conversaId: v.optional(v.id('conversas')), prazoResposta: v.optional(v.number()), prazoConclusao: v.optional(v.number()), prazoEncerramento: v.optional(v.number()), timeline: v.optional( v.array( v.object({ etapa: v.string(), status: v.union( v.literal('pendente'), v.literal('em_andamento'), v.literal('concluido'), v.literal('vencido') ), prazo: v.optional(v.number()), concluidoEm: v.optional(v.number()), observacao: v.optional(v.string()) }) ) ), alertasEmitidos: v.optional( v.array( v.object({ tipo: v.union(v.literal('resposta'), v.literal('conclusao'), v.literal('encerramento')), emitidoEm: v.number() }) ) ), anexos: v.optional( v.array( v.object({ arquivoId: v.id('_storage'), nome: v.optional(v.string()), tipo: v.optional(v.string()), tamanho: v.optional(v.number()) }) ) ), tags: v.optional(v.array(v.string())), canalOrigem: v.optional(v.string()), ultimaInteracaoEm: v.number(), criadoEm: v.number(), atualizadoEm: v.number() }) .index('by_numero', ['numero']) .index('by_status', ['status']) .index('by_solicitante', ['solicitanteId', 'status']) .index('by_responsavel', ['responsavelId', 'status']) .index('by_setor', ['setorResponsavel', 'status']), ticketInteractions: defineTable({ ticketId: v.id('tickets'), autorId: v.optional(v.id('usuarios')), origem: v.union(v.literal('usuario'), v.literal('ti'), v.literal('sistema')), tipo: v.union( v.literal('mensagem'), v.literal('status'), v.literal('anexo'), v.literal('alerta') ), conteudo: v.string(), anexos: v.optional( v.array( v.object({ arquivoId: v.id('_storage'), nome: v.optional(v.string()), tipo: v.optional(v.string()), tamanho: v.optional(v.number()) }) ) ), statusAnterior: v.optional( v.union( v.literal('aberto'), v.literal('em_andamento'), v.literal('aguardando_usuario'), v.literal('resolvido'), v.literal('encerrado'), v.literal('cancelado') ) ), statusNovo: v.optional( v.union( v.literal('aberto'), v.literal('em_andamento'), v.literal('aguardando_usuario'), v.literal('resolvido'), v.literal('encerrado'), v.literal('cancelado') ) ), visibilidade: v.union(v.literal('publico'), v.literal('interno')), criadoEm: v.number() }) .index('by_ticket', ['ticketId']) .index('by_ticket_type', ['ticketId', 'tipo']) .index('by_autor', ['autorId']), slaConfigs: defineTable({ nome: v.string(), descricao: v.optional(v.string()), prioridade: v.optional( v.union(v.literal('baixa'), v.literal('media'), v.literal('alta'), v.literal('critica')) ), tempoRespostaHoras: v.number(), tempoConclusaoHoras: v.number(), tempoEncerramentoHoras: v.optional(v.number()), alertaAntecedenciaHoras: v.number(), ativo: v.boolean(), criadoPor: v.id('usuarios'), atualizadoPor: v.optional(v.id('usuarios')), criadoEm: v.number(), atualizadoEm: v.number() }) .index('by_ativo', ['ativo']) .index('by_prioridade', ['prioridade', 'ativo']) .index('by_nome', ['nome']), ticketAssignments: defineTable({ ticketId: v.id('tickets'), responsavelId: v.id('usuarios'), atribuidoPor: v.id('usuarios'), motivo: v.optional(v.string()), ativo: v.boolean(), criadoEm: v.number(), encerradoEm: v.optional(v.number()) }) .index('by_ticket', ['ticketId', 'ativo']) .index('by_responsavel', ['responsavelId', 'ativo']) };