Files
sgse-app/packages/backend/convex/tables/tickets.ts

166 lines
4.3 KiB
TypeScript

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'])
};