From 5b2c682870bd23b617859395e0267b0cbe78249e Mon Sep 17 00:00:00 2001 From: killer-cf Date: Fri, 14 Nov 2025 10:47:41 -0300 Subject: [PATCH 1/4] lixo --- packages/backend/convex/_generated/api.d.ts | 36 +-- .../backend/convex/_generated/server.d.ts | 16 +- packages/backend/convex/_generated/server.js | 13 +- .../backend/convex/limparPerfisAntigos.ts | 285 ------------------ packages/backend/convex/perfisCustomizados.ts | 1 - 5 files changed, 29 insertions(+), 322 deletions(-) delete mode 100644 packages/backend/convex/limparPerfisAntigos.ts delete mode 100644 packages/backend/convex/perfisCustomizados.ts diff --git a/packages/backend/convex/_generated/api.d.ts b/packages/backend/convex/_generated/api.d.ts index 87b4b87..468ef93 100644 --- a/packages/backend/convex/_generated/api.d.ts +++ b/packages/backend/convex/_generated/api.d.ts @@ -15,8 +15,8 @@ import type * as actions_smtp from "../actions/smtp.js"; import type * as actions_utils_nodeCrypto from "../actions/utils/nodeCrypto.js"; import type * as atestadosLicencas from "../atestadosLicencas.js"; import type * as ausencias from "../ausencias.js"; -import type * as auth from "../auth.js"; import type * as auth_utils from "../auth/utils.js"; +import type * as auth from "../auth.js"; import type * as chat from "../chat.js"; import type * as configuracaoEmail from "../configuracaoEmail.js"; import type * as crons from "../crons.js"; @@ -28,7 +28,6 @@ import type * as ferias from "../ferias.js"; import type * as funcionarios from "../funcionarios.js"; import type * as healthCheck from "../healthCheck.js"; import type * as http from "../http.js"; -import type * as limparPerfisAntigos from "../limparPerfisAntigos.js"; import type * as logsAcesso from "../logsAcesso.js"; import type * as logsAtividades from "../logsAtividades.js"; import type * as logsLogin from "../logsLogin.js"; @@ -54,6 +53,14 @@ import type { FunctionReference, } from "convex/server"; +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ declare const fullApi: ApiFromModules<{ "actions/email": typeof actions_email; "actions/linkPreview": typeof actions_linkPreview; @@ -62,8 +69,8 @@ declare const fullApi: ApiFromModules<{ "actions/utils/nodeCrypto": typeof actions_utils_nodeCrypto; atestadosLicencas: typeof atestadosLicencas; ausencias: typeof ausencias; - auth: typeof auth; "auth/utils": typeof auth_utils; + auth: typeof auth; chat: typeof chat; configuracaoEmail: typeof configuracaoEmail; crons: typeof crons; @@ -75,7 +82,6 @@ declare const fullApi: ApiFromModules<{ funcionarios: typeof funcionarios; healthCheck: typeof healthCheck; http: typeof http; - limparPerfisAntigos: typeof limparPerfisAntigos; logsAcesso: typeof logsAcesso; logsAtividades: typeof logsAtividades; logsLogin: typeof logsLogin; @@ -95,30 +101,14 @@ declare const fullApi: ApiFromModules<{ "utils/getClientIP": typeof utils_getClientIP; verificarMatriculas: typeof verificarMatriculas; }>; +declare const fullApiWithMounts: typeof fullApi; -/** - * A utility for referencing Convex functions in your app's public API. - * - * Usage: - * ```js - * const myFunctionReference = api.myModule.myFunction; - * ``` - */ export declare const api: FilterApi< - typeof fullApi, + typeof fullApiWithMounts, FunctionReference >; - -/** - * A utility for referencing Convex functions in your app's internal API. - * - * Usage: - * ```js - * const myFunctionReference = internal.myModule.myFunction; - * ``` - */ export declare const internal: FilterApi< - typeof fullApi, + typeof fullApiWithMounts, FunctionReference >; diff --git a/packages/backend/convex/_generated/server.d.ts b/packages/backend/convex/_generated/server.d.ts index bec05e6..b5c6828 100644 --- a/packages/backend/convex/_generated/server.d.ts +++ b/packages/backend/convex/_generated/server.d.ts @@ -10,6 +10,7 @@ import { ActionBuilder, + AnyComponents, HttpActionBuilder, MutationBuilder, QueryBuilder, @@ -18,9 +19,15 @@ import { GenericQueryCtx, GenericDatabaseReader, GenericDatabaseWriter, + FunctionReference, } from "convex/server"; import type { DataModel } from "./dataModel.js"; +type GenericCtx = + | GenericActionCtx + | GenericMutationCtx + | GenericQueryCtx; + /** * Define a query in this Convex app's public API. * @@ -85,12 +92,11 @@ export declare const internalAction: ActionBuilder; /** * Define an HTTP action. * - * The wrapped function will be used to respond to HTTP requests received - * by a Convex deployment if the requests matches the path and method where - * this action is routed. Be sure to route your httpAction in `convex/http.js`. + * This function will be used to respond to HTTP requests received by a Convex + * deployment if the requests matches the path and method where this action + * is routed. Be sure to route your action in `convex/http.js`. * - * @param func - The function. It receives an {@link ActionCtx} as its first argument - * and a Fetch API `Request` object as its second. + * @param func - The function. It receives an {@link ActionCtx} as its first argument. * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. */ export declare const httpAction: HttpActionBuilder; diff --git a/packages/backend/convex/_generated/server.js b/packages/backend/convex/_generated/server.js index bf3d25a..4a21df4 100644 --- a/packages/backend/convex/_generated/server.js +++ b/packages/backend/convex/_generated/server.js @@ -16,6 +16,7 @@ import { internalActionGeneric, internalMutationGeneric, internalQueryGeneric, + componentsGeneric, } from "convex/server"; /** @@ -80,14 +81,10 @@ export const action = actionGeneric; export const internalAction = internalActionGeneric; /** - * Define an HTTP action. + * Define a Convex HTTP action. * - * The wrapped function will be used to respond to HTTP requests received - * by a Convex deployment if the requests matches the path and method where - * this action is routed. Be sure to route your httpAction in `convex/http.js`. - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument - * and a Fetch API `Request` object as its second. - * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. + * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object + * as its second. + * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. */ export const httpAction = httpActionGeneric; diff --git a/packages/backend/convex/limparPerfisAntigos.ts b/packages/backend/convex/limparPerfisAntigos.ts deleted file mode 100644 index 9e7d53d..0000000 --- a/packages/backend/convex/limparPerfisAntigos.ts +++ /dev/null @@ -1,285 +0,0 @@ -import { internalMutation, query } from "./_generated/server"; -import { v } from "convex/values"; - -/** - * Listar todos os perfis (roles) do sistema - */ -export const listarTodosRoles = query({ - args: {}, - returns: v.array( - v.object({ - _id: v.id("roles"), - nome: v.string(), - descricao: v.string(), - nivel: v.number(), - setor: v.optional(v.string()), - customizado: v.optional(v.boolean()), - editavel: v.optional(v.boolean()), - _creationTime: v.number(), - }) - ), - handler: async (ctx) => { - const roles = await ctx.db.query("roles").collect(); - return roles.map((role) => ({ - _id: role._id, - nome: role.nome, - descricao: role.descricao, - nivel: role.nivel, - setor: role.setor, - customizado: role.customizado, - editavel: role.editavel, - _creationTime: role._creationTime, - })); - }, -}); - -/** - * Limpar perfis antigos/duplicados - * - * CRITÉRIOS: - * - Manter apenas: ti_master (nível 0), admin (nível 2), ti_usuario (nível 2) - * - Remover: admin antigo (nível 0), ti genérico (nível 1), outros duplicados - */ -export const limparPerfisAntigos = internalMutation({ - args: {}, - returns: v.object({ - removidos: v.array( - v.object({ - nome: v.string(), - descricao: v.string(), - nivel: v.number(), - motivo: v.string(), - }) - ), - mantidos: v.array( - v.object({ - nome: v.string(), - descricao: v.string(), - nivel: v.number(), - }) - ), - }), - handler: async (ctx) => { - const roles = await ctx.db.query("roles").collect(); - - const removidos: Array<{ - nome: string; - descricao: string; - nivel: number; - motivo: string; - }> = []; - - const mantidos: Array<{ - nome: string; - descricao: string; - nivel: number; - }> = []; - - // Perfis que devem ser mantidos (apenas 1 de cada) - const perfisCorretos = new Map(); - perfisCorretos.set("ti_master", false); - perfisCorretos.set("admin", false); - perfisCorretos.set("ti_usuario", false); - - for (const role of roles) { - let deveManter = false; - let motivo = ""; - - // TI_MASTER - Manter apenas o de nível 0 - if (role.nome === "ti_master") { - if (role.nivel === 0 && !perfisCorretos.get("ti_master")) { - deveManter = true; - perfisCorretos.set("ti_master", true); - } else { - motivo = - role.nivel !== 0 - ? "TI_MASTER deve ser nível 0, este é nível " + role.nivel - : "TI_MASTER duplicado"; - } - } - // ADMIN - Manter apenas o de nível 2 - else if (role.nome === "admin") { - if (role.nivel === 2 && !perfisCorretos.get("admin")) { - deveManter = true; - perfisCorretos.set("admin", true); - } else { - motivo = - role.nivel !== 2 - ? "ADMIN deve ser nível 2, este é nível " + role.nivel - : "ADMIN duplicado"; - } - } - // TI_USUARIO - Manter apenas o de nível 2 - else if (role.nome === "ti_usuario") { - if (role.nivel === 2 && !perfisCorretos.get("ti_usuario")) { - deveManter = true; - perfisCorretos.set("ti_usuario", true); - } else { - motivo = - role.nivel !== 2 - ? "TI_USUARIO deve ser nível 2, este é nível " + role.nivel - : "TI_USUARIO duplicado"; - } - } - // Perfis genéricos antigos (remover) - else if (role.nome === "ti") { - motivo = - "Perfil genérico 'ti' obsoleto - usar 'ti_master' ou 'ti_usuario'"; - } - // Outros perfis específicos de setores (manter se forem nível >= 2) - else if ( - role.nome === "rh" || - role.nome === "financeiro" || - role.nome === "controladoria" || - role.nome === "licitacoes" || - role.nome === "compras" || - role.nome === "juridico" || - role.nome === "comunicacao" || - role.nome === "programas_esportivos" || - role.nome === "secretaria_executiva" || - role.nome === "gestao_pessoas" || - role.nome === "usuario" - ) { - if (role.nivel >= 2) { - deveManter = true; - } else { - motivo = `Perfil de setor com nível incorreto (${role.nivel}), deveria ser >= 2`; - } - } - // Perfis customizados (manter sempre) - else if (role.customizado) { - deveManter = true; - } - // Outros perfis desconhecidos - else { - motivo = "Perfil desconhecido ou obsoleto"; - } - - if (deveManter) { - mantidos.push({ - nome: role.nome, - descricao: role.descricao, - nivel: role.nivel, - }); - console.log( - `✅ MANTIDO: ${role.nome} (${role.descricao}) - Nível ${role.nivel}` - ); - } else { - // Verificar se há usuários usando este perfil - const usuariosComRole = await ctx.db - .query("usuarios") - .withIndex("by_role", (q) => q.eq("roleId", role._id)) - .collect(); - - if (usuariosComRole.length > 0) { - console.log( - `⚠️ AVISO: Não é possível remover "${role.nome}" porque ${usuariosComRole.length} usuário(s) ainda usa(m) este perfil` - ); - mantidos.push({ - nome: role.nome, - descricao: role.descricao, - nivel: role.nivel, - }); - } else { - // Remover permissões associadas - const permissoes = await ctx.db - .query("rolePermissoes") - .withIndex("by_role", (q) => q.eq("roleId", role._id)) - .collect(); - for (const perm of permissoes) { - await ctx.db.delete(perm._id); - } - - // Remover o role - await ctx.db.delete(role._id); - - removidos.push({ - nome: role.nome, - descricao: role.descricao, - nivel: role.nivel, - motivo: motivo || "Não especificado", - }); - console.log( - `🗑️ REMOVIDO: ${role.nome} (${role.descricao}) - Nível ${role.nivel} - Motivo: ${motivo}` - ); - } - } - } - - return { removidos, mantidos }; - }, -}); - -/** - * Verificar se existem perfis com níveis incorretos - */ -export const verificarNiveisIncorretos = query({ - args: {}, - returns: v.array( - v.object({ - nome: v.string(), - descricao: v.string(), - nivelAtual: v.number(), - nivelCorreto: v.number(), - problema: v.string(), - }) - ), - handler: async (ctx) => { - const roles = await ctx.db.query("roles").collect(); - const problemas: Array<{ - nome: string; - descricao: string; - nivelAtual: number; - nivelCorreto: number; - problema: string; - }> = []; - - for (const role of roles) { - // TI_MASTER deve ser nível 0 - if (role.nome === "ti_master" && role.nivel !== 0) { - problemas.push({ - nome: role.nome, - descricao: role.descricao, - nivelAtual: role.nivel, - nivelCorreto: 0, - problema: "TI_MASTER deve ter acesso total (nível 0)", - }); - } - - // ADMIN deve ser nível 2 - if (role.nome === "admin" && role.nivel !== 2) { - problemas.push({ - nome: role.nome, - descricao: role.descricao, - nivelAtual: role.nivel, - nivelCorreto: 2, - problema: "ADMIN deve ser editável (nível 2)", - }); - } - - // TI_USUARIO deve ser nível 2 - if (role.nome === "ti_usuario" && role.nivel !== 2) { - problemas.push({ - nome: role.nome, - descricao: role.descricao, - nivelAtual: role.nivel, - nivelCorreto: 2, - problema: "TI_USUARIO deve ser editável (nível 2)", - }); - } - - // Perfil genérico "ti" não deveria existir - if (role.nome === "ti") { - problemas.push({ - nome: role.nome, - descricao: role.descricao, - nivelAtual: role.nivel, - nivelCorreto: -1, // Indica que deve ser removido - problema: "Perfil genérico obsoleto - usar ti_master ou ti_usuario", - }); - } - } - - return problemas; - }, -}); diff --git a/packages/backend/convex/perfisCustomizados.ts b/packages/backend/convex/perfisCustomizados.ts deleted file mode 100644 index 8b13789..0000000 --- a/packages/backend/convex/perfisCustomizados.ts +++ /dev/null @@ -1 +0,0 @@ - From 3c371bc35ceda9ffe51071f5db6a3c5ac4ab3837 Mon Sep 17 00:00:00 2001 From: killer-cf Date: Fri, 14 Nov 2025 15:12:54 -0300 Subject: [PATCH 2/4] refactor: update permission management and role structure - Enhanced the permission management system by introducing a new base permissions structure, allowing for better organization and clarity. - Updated the role creation process to normalize role levels, limiting them to two levels: 0 (maximum access) and 1 (administrative access). - Improved the UI for permission displays, ensuring users are informed when no permissions are available. - Added alerts and messages to guide users in creating permissions when none exist. - Streamlined backend queries for permissions and roles to improve performance and maintainability. --- .../ti/painel-permissoes/+page.svelte | 48 +- .../routes/(dashboard)/ti/perfis/+page.svelte | 65 +- packages/backend/convex/permissoesAcoes.ts | 361 +++- packages/backend/convex/roles.ts | 32 +- packages/backend/convex/seed.ts | 1732 ++++++++--------- 5 files changed, 1232 insertions(+), 1006 deletions(-) diff --git a/apps/web/src/routes/(dashboard)/ti/painel-permissoes/+page.svelte b/apps/web/src/routes/(dashboard)/ti/painel-permissoes/+page.svelte index 130a768..495a86d 100644 --- a/apps/web/src/routes/(dashboard)/ti/painel-permissoes/+page.svelte +++ b/apps/web/src/routes/(dashboard)/ti/painel-permissoes/+page.svelte @@ -543,7 +543,7 @@ - {:else if catalogoQuery.data} + {:else if catalogoQuery.data && catalogoQuery.data.length > 0}
{#each catalogoQuery.data as item (item.recurso)} {@const recursoExpandido = isRecursoExpandido(roleId, item.recurso)} @@ -576,28 +576,40 @@ {#if recursoExpandido}
-
- {#each ['ver', 'listar', 'criar', 'editar', 'excluir'] as acao (acao)} - - {/each} -
+ {#if item.acoes.length === 0} +

+ Nenhuma permissão cadastrada para este recurso. +

+ {:else} +
+ {#each item.acoes as acao (acao)} + + {/each} +
+ {/if}
{/if}
{/each} + {:else} +
+ + Nenhuma permissão cadastrada ainda. Use o botão “Criar permissão” para começar. + +
{/if} diff --git a/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte b/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte index c3017c3..8958def 100644 --- a/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte +++ b/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte @@ -41,19 +41,15 @@ const stats = $derived.by(() => { if (carregando) return null; - const porNivel = { - 0: roles.filter((r) => r.nivel === 0).length, - 1: roles.filter((r) => r.nivel === 1).length, - 2: roles.filter((r) => r.nivel === 2).length, - 3: roles.filter((r) => r.nivel >= 3).length - }; + const nivelMaximo = roles.filter((r) => r.nivel === 0).length; + const nivelAdministrativo = roles.filter((r) => r.nivel === 1).length; + const niveisLegado = roles.filter((r) => r.nivel > 1).length; return { total: roles.length, - nivelMaximo: porNivel[0], - nivelAlto: porNivel[1], - nivelMedio: porNivel[2], - nivelBaixo: porNivel[3], + nivelMaximo, + nivelAdministrativo, + niveisLegado, comSetor: roles.filter((r) => r.setor).length }; }); @@ -78,10 +74,11 @@ // Filtro por nível if (filtroNivel !== '') { - if (filtroNivel === 3) { - resultado = resultado.filter((r) => r.nivel >= 3); - } else { + if (filtroNivel === 0 || filtroNivel === 1) { resultado = resultado.filter((r) => r.nivel === filtroNivel); + } else { + // Qualquer outro valor é considerado legado + resultado = resultado.filter((r) => r.nivel > 1); } } @@ -96,22 +93,19 @@ function obterCorNivel(nivel: number): string { if (nivel === 0) return 'badge-error'; if (nivel === 1) return 'badge-warning'; - if (nivel === 2) return 'badge-info'; + // Níveis > 1 são considerados legado return 'badge-ghost'; } function obterTextoNivel(nivel: number): string { if (nivel === 0) return 'Máximo'; - if (nivel === 1) return 'Alto'; - if (nivel === 2) return 'Médio'; - if (nivel === 3) return 'Baixo'; - return `Nível ${nivel}`; + if (nivel === 1) return 'Administrativo'; + return `Legado (${nivel})`; } function obterCorCardNivel(nivel: number): string { if (nivel === 0) return 'border-l-4 border-error'; if (nivel === 1) return 'border-l-4 border-warning'; - if (nivel === 2) return 'border-l-4 border-info'; return 'border-l-4 border-base-300'; } @@ -176,31 +170,24 @@ {#if stats} -
+
- 0 ? ((stats.comSetor / stats.total) * 100).toFixed(0) + '% do total' @@ -209,6 +196,18 @@ color="secondary" />
+ {#if stats.niveisLegado > 0} +
+ +
+

Perfis com níveis legados

+

+ Existem {stats.niveisLegado} perfis com nível acima de 1. Esses perfis continuarão + sendo tratados como nível 1 (administrativo) após a migração. +

+
+
+ {/if} {/if} diff --git a/packages/backend/convex/permissoesAcoes.ts b/packages/backend/convex/permissoesAcoes.ts index f9f0b3c..ee982f4 100644 --- a/packages/backend/convex/permissoesAcoes.ts +++ b/packages/backend/convex/permissoesAcoes.ts @@ -3,27 +3,271 @@ import { v } from 'convex/values'; import type { Doc } from './_generated/dataModel'; import { getCurrentUserFunction } from './auth'; -// Catálogo base de recursos e ações -// Ajuste/expanda conforme os módulos disponíveis no sistema -export const CATALOGO_RECURSOS = [ - { - recurso: 'funcionarios', - acoes: [ - 'dashboard', - 'ver', - 'listar', - 'criar', - 'editar', - 'excluir', - 'aprovar_ausencias', - 'aprovar_ferias' - ] - }, - { - recurso: 'simbolos', - acoes: ['dashboard', 'ver', 'listar', 'criar', 'editar', 'excluir'] - } -] as const; +// Catálogo de permissões base para seed controlado via mutation +const PERMISSOES_BASE = { + permissoes: [ + // Funcionários + { + nome: 'funcionarios.dashboard', + recurso: 'funcionarios', + acao: 'dashboard', + descricao: 'Acessar o painel de funcionários' + }, + { + nome: 'funcionarios.ver', + recurso: 'funcionarios', + acao: 'ver', + descricao: 'Visualizar detalhes de funcionários' + }, + { + nome: 'funcionarios.listar', + recurso: 'funcionarios', + acao: 'listar', + descricao: 'Listar funcionários' + }, + { + nome: 'funcionarios.criar', + recurso: 'funcionarios', + acao: 'criar', + descricao: 'Criar novos funcionários' + }, + { + nome: 'funcionarios.editar', + recurso: 'funcionarios', + acao: 'editar', + descricao: 'Editar dados de funcionários' + }, + { + nome: 'funcionarios.excluir', + recurso: 'funcionarios', + acao: 'excluir', + descricao: 'Excluir funcionários' + }, + { + nome: 'funcionarios.aprovar_ausencias', + recurso: 'funcionarios', + acao: 'aprovar_ausencias', + descricao: 'Aprovar ausências de funcionários' + }, + { + nome: 'funcionarios.aprovar_ferias', + recurso: 'funcionarios', + acao: 'aprovar_ferias', + descricao: 'Aprovar férias de funcionários' + }, + // Símbolos + { + nome: 'simbolos.dashboard', + recurso: 'simbolos', + acao: 'dashboard', + descricao: 'Acessar o painel de símbolos' + }, + { + nome: 'simbolos.ver', + recurso: 'simbolos', + acao: 'ver', + descricao: 'Visualizar detalhes de símbolos' + }, + { + nome: 'simbolos.listar', + recurso: 'simbolos', + acao: 'listar', + descricao: 'Listar símbolos' + }, + { + nome: 'simbolos.criar', + recurso: 'simbolos', + acao: 'criar', + descricao: 'Criar novos símbolos' + }, + { + nome: 'simbolos.editar', + recurso: 'simbolos', + acao: 'editar', + descricao: 'Editar símbolos' + }, + { + nome: 'simbolos.excluir', + recurso: 'simbolos', + acao: 'excluir', + descricao: 'Excluir símbolos' + }, + // TI - Usuários + { + nome: 'ti_usuarios.listar', + recurso: 'ti_usuarios', + acao: 'listar', + descricao: 'Listar usuários do sistema' + }, + { + nome: 'ti_usuarios.criar', + recurso: 'ti_usuarios', + acao: 'criar', + descricao: 'Criar novos usuários de acesso' + }, + { + nome: 'ti_usuarios.editar', + recurso: 'ti_usuarios', + acao: 'editar', + descricao: 'Editar usuários de acesso' + }, + { + nome: 'ti_usuarios.bloquear', + recurso: 'ti_usuarios', + acao: 'bloquear', + descricao: 'Bloquear ou desbloquear usuários' + }, + // TI - Perfis + { + nome: 'ti_perfis.listar', + recurso: 'ti_perfis', + acao: 'listar', + descricao: 'Listar perfis de acesso' + }, + { + nome: 'ti_perfis.criar', + recurso: 'ti_perfis', + acao: 'criar', + descricao: 'Criar novos perfis de acesso' + }, + { + nome: 'ti_perfis.editar', + recurso: 'ti_perfis', + acao: 'editar', + descricao: 'Editar perfis de acesso' + }, + // TI - Painel de Permissões + { + nome: 'ti_painel_permissoes.gerenciar', + recurso: 'ti_painel_permissoes', + acao: 'gerenciar', + descricao: 'Gerenciar matriz de permissões por perfil' + }, + // TI - Solicitações de Acesso + { + nome: 'ti_solicitacoes_acesso.ver', + recurso: 'ti_solicitacoes_acesso', + acao: 'ver', + descricao: 'Visualizar solicitações de acesso' + }, + { + nome: 'ti_solicitacoes_acesso.aprovar', + recurso: 'ti_solicitacoes_acesso', + acao: 'aprovar', + descricao: 'Aprovar solicitações de acesso' + }, + { + nome: 'ti_solicitacoes_acesso.reprovar', + recurso: 'ti_solicitacoes_acesso', + acao: 'reprovar', + descricao: 'Reprovar solicitações de acesso' + }, + // TI - Configurações de E-mail + { + nome: 'ti_configuracoes_email.configurar', + recurso: 'ti_configuracoes_email', + acao: 'configurar', + descricao: 'Configurar parâmetros de envio de e-mail' + }, + // TI - Monitoramento + { + nome: 'ti_monitoramento.ver', + recurso: 'ti_monitoramento', + acao: 'ver', + descricao: 'Acessar painel de monitoramento geral' + }, + { + nome: 'ti_monitoramento_emails.ver', + recurso: 'ti_monitoramento_emails', + acao: 'ver', + descricao: 'Acessar monitoramento de envio de e-mails' + }, + // TI - Notificações + { + nome: 'ti_notificacoes.configurar', + recurso: 'ti_notificacoes', + acao: 'configurar', + descricao: 'Configurar notificações do sistema' + }, + // TI - Times + { + nome: 'ti_times.gerenciar', + recurso: 'ti_times', + acao: 'gerenciar', + descricao: 'Gerenciar times/equipes de TI' + }, + // TI - Painel Administrativo + { + nome: 'ti_painel_administrativo.ver', + recurso: 'ti_painel_administrativo', + acao: 'ver', + descricao: 'Acessar painel administrativo de TI' + }, + // Financeiro + { + nome: 'financeiro.ver', + recurso: 'financeiro', + acao: 'ver', + descricao: 'Acessar telas do módulo de financeiro' + }, + // Controladoria + { + nome: 'controladoria.ver', + recurso: 'controladoria', + acao: 'ver', + descricao: 'Acessar telas do módulo de controladoria' + }, + // Licitações + { + nome: 'licitacoes.ver', + recurso: 'licitacoes', + acao: 'ver', + descricao: 'Acessar telas do módulo de licitações' + }, + // Compras + { + nome: 'compras.ver', + recurso: 'compras', + acao: 'ver', + descricao: 'Acessar telas do módulo de compras' + }, + // Jurídico + { + nome: 'juridico.ver', + recurso: 'juridico', + acao: 'ver', + descricao: 'Acessar telas do módulo jurídico' + }, + // Comunicação + { + nome: 'comunicacao.ver', + recurso: 'comunicacao', + acao: 'ver', + descricao: 'Acessar telas do módulo de comunicação' + }, + // Programas Esportivos + { + nome: 'programas_esportivos.ver', + recurso: 'programas_esportivos', + acao: 'ver', + descricao: 'Acessar telas do módulo de programas esportivos' + }, + // Secretaria Executiva + { + nome: 'secretaria_executiva.ver', + recurso: 'secretaria_executiva', + acao: 'ver', + descricao: 'Acessar telas do módulo de secretaria executiva' + }, + // Gestão de Pessoas + { + nome: 'gestao_pessoas.ver', + recurso: 'gestao_pessoas', + acao: 'ver', + descricao: 'Acessar telas do módulo de gestão de pessoas' + } + ] +} as const; export const listarRecursosEAcoes = query({ args: {}, @@ -33,10 +277,18 @@ export const listarRecursosEAcoes = query({ acoes: v.array(v.string()) }) ), - handler: async () => { - return CATALOGO_RECURSOS.map((r) => ({ - recurso: r.recurso, - acoes: [...r.acoes] + handler: async (ctx) => { + const permissoes = await ctx.db.query('permissoes').collect(); + + const recursos: Record> = {}; + for (const perm of permissoes) { + const set = (recursos[perm.recurso] ||= new Set()); + set.add(perm.acao); + } + + return Object.entries(recursos).map(([recurso, acoes]) => ({ + recurso, + acoes: Array.from(acoes).sort() })); } }); @@ -56,7 +308,7 @@ export const listarPermissoesAcoesPorRole = query({ .withIndex('by_role', (q) => q.eq('roleId', args.roleId)) .collect(); - // Carregar documentos de permissões + // Carregar documentos de permissões vinculadas a este role const actionsByResource: Record> = {}; for (const rp of rolePerms) { const perm = await ctx.db.get(rp.permissaoId); @@ -65,13 +317,10 @@ export const listarPermissoesAcoesPorRole = query({ set.add(perm.acao); } - // Normalizar para todos os recursos do catálogo - const result: Array<{ recurso: string; acoes: Array }> = []; - for (const item of CATALOGO_RECURSOS) { - const granted = Array.from(actionsByResource[item.recurso] ?? new Set()); - result.push({ recurso: item.recurso, acoes: granted }); - } - return result; + return Object.entries(actionsByResource).map(([recurso, acoes]) => ({ + recurso, + acoes: Array.from(acoes).sort() + })); } }); @@ -84,24 +333,12 @@ export const atualizarPermissaoAcao = mutation({ }, returns: v.null(), handler: async (ctx, args) => { - // Garantir documento de permissão (recurso+acao) - let permissao = await ctx.db + // Buscar documento de permissão (recurso+acao) + const permissao = await ctx.db .query('permissoes') .withIndex('by_recurso_e_acao', (q) => q.eq('recurso', args.recurso).eq('acao', args.acao)) .first(); - if (!permissao) { - const nome = `${args.recurso}.${args.acao}`; - const descricao = `Permite ${args.acao} em ${args.recurso}`; - const id = await ctx.db.insert('permissoes', { - nome, - descricao, - recurso: args.recurso, - acao: args.acao - }); - permissao = await ctx.db.get(id); - } - if (!permissao) return null; // Verificar vínculo atual @@ -128,6 +365,36 @@ export const atualizarPermissaoAcao = mutation({ } }); +export const seedPermissoesBase = mutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('🔐 Seed de permissões base...'); + + for (const perm of PERMISSOES_BASE.permissoes) { + const existente = await ctx.db + .query('permissoes') + .withIndex('by_nome', (q) => q.eq('nome', perm.nome)) + .first(); + + if (existente) { + console.log(` ℹ️ Permissão já existe: ${perm.nome}`); + continue; + } + + await ctx.db.insert('permissoes', { + nome: perm.nome, + descricao: perm.descricao, + recurso: perm.recurso, + acao: perm.acao + }); + console.log(` ✅ Permissão criada: ${perm.nome}`); + } + + return null; + } +}); + export const verificarAcao = query({ args: { usuarioId: v.id('usuarios'), diff --git a/packages/backend/convex/roles.ts b/packages/backend/convex/roles.ts index f21547e..6594a96 100644 --- a/packages/backend/convex/roles.ts +++ b/packages/backend/convex/roles.ts @@ -1,5 +1,5 @@ import { v } from 'convex/values'; -import { query, mutation } from './_generated/server'; +import { internalMutation, query, mutation } from './_generated/server'; import type { Id } from './_generated/dataModel'; import { getCurrentUserFunction } from './auth'; @@ -98,13 +98,16 @@ export const criar = mutation({ permissoesParaCopiar = permissoesOrigem.map((item) => item.permissaoId); } - const nivelAjustado = Math.min(Math.max(Math.round(args.nivel), 0), 10); + // Agora só existem níveis 0 e 1. + // 0 = máximo (acesso total), 1 = administrativo (também com acesso total). + // Qualquer valor informado diferente de 0 é normalizado para 1. + const nivelNormalizado = Math.round(args.nivel) <= 0 ? 0 : 1; const setor = args.setor?.trim(); const roleId = await ctx.db.insert('roles', { nome: nomeNormalizado, descricao: args.descricao.trim() || args.nome.trim(), - nivel: nivelAjustado, + nivel: nivelNormalizado, setor: setor && setor.length > 0 ? setor : undefined, customizado: true, criadoPor: usuarioAtual._id, @@ -123,3 +126,26 @@ export const criar = mutation({ return { sucesso: true as const, roleId }; } }); + +/** + * Migração de níveis de roles para o novo modelo (apenas 0 e 1). + * - Mantém níveis 0 e 1 como estão. + * - Converte qualquer nível > 1 para 1. + */ +export const migrarNiveisRoles = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + const roles = await ctx.db.query('roles').collect(); + + for (const role of roles) { + if (role.nivel <= 1) continue; + + await ctx.db.patch(role._id, { + nivel: 1 + }); + } + + return null; + } +}); diff --git a/packages/backend/convex/seed.ts b/packages/backend/convex/seed.ts index 3b19f67..2af404c 100644 --- a/packages/backend/convex/seed.ts +++ b/packages/backend/convex/seed.ts @@ -1,484 +1,469 @@ -import { - action, - internalAction, - internalMutation, - mutation, - query, -} from "./_generated/server"; -import { internal } from "./_generated/api"; -import { v } from "convex/values"; -import { hashPassword } from "./auth/utils"; -import { Id } from "./_generated/dataModel"; -import { createAuthUser } from "./auth"; +import { internalAction, internalMutation, mutation, query } from './_generated/server'; +import { internal, api } from './_generated/api'; +import { v } from 'convex/values'; +// import { hashPassword } from './auth/utils'; +import { Id } from './_generated/dataModel'; +import { createAuthUser } from './auth'; // Dados exportados do Convex Cloud const simbolosData = [ - { - descricao: "Cargo de Direção e Assessoramento Superior - 5", - nome: "DAS-5", - repValor: "4747.84", - tipo: "cargo_comissionado" as const, - valor: "5934.80", - vencValor: "1186.96", - }, - { - descricao: "Cargo de Direção e Assessoramento Superior - 3", - nome: "DAS-3", - repValor: "6273.92", - tipo: "cargo_comissionado" as const, - valor: "7842.40", - vencValor: "1568.48", - }, - { - descricao: "Cargo de Direção e Assessoramento Superior -2", - nome: "DAS - 2", - repValor: "7460.87", - tipo: "cargo_comissionado" as const, - valor: "9326.09", - vencValor: "1865.22", - }, - { - descricao: "Cargo de Apoio e Assessoramento - 1", - nome: "CAA-1", - repValor: "4120.43", - tipo: "cargo_comissionado" as const, - valor: "5150.54", - vencValor: "1030.11", - }, - { - descricao: "Função Gratificada de Direção e Assessoramento", - nome: "FDA", - repValor: "", - tipo: "funcao_gratificada" as const, - valor: "7460.87", - vencValor: "", - }, - { - descricao: "Função Gratificada de Supervisão - 3", - nome: "CAA - 3", - repValor: "2204.36", - tipo: "cargo_comissionado" as const, - valor: "2755.45", - vencValor: "551.09", - }, - { - descricao: "Função Gratificada de Direção e Assessoramento -1", - nome: "FDA-1", - repValor: "", - tipo: "funcao_gratificada" as const, - valor: "6273.92", - vencValor: "", - }, - { - descricao: "Função Gratificada de Direção e Assessoramento -2", - nome: "FDA -2", - repValor: "", - tipo: "funcao_gratificada" as const, - valor: "5765.22", - vencValor: "", - }, - { - descricao: "Função Gratificada de Direção e Assessoramento - 3", - nome: "FDA - 3", - repValor: "", - tipo: "funcao_gratificada" as const, - valor: "4747.83", - vencValor: "", - }, - { - descricao: "Função Gratificada de Direção e Assessoramento - 4", - nome: "FDA - 4", - repValor: "", - tipo: "funcao_gratificada" as const, - valor: "3391.31", - vencValor: "", - }, - { - descricao: "Função Gratificada de Supervisão - 1", - nome: "FGS -1 ", - repValor: "", - tipo: "funcao_gratificada" as const, - valor: "1532.08", - vencValor: "", - }, - { - descricao: "Função Gratificada de Supervisão - 2", - nome: "FGS - 2", - repValor: "", - tipo: "funcao_gratificada" as const, - valor: "934.74", - vencValor: "", - }, - { - descricao: "Função Gratificada de Supervisão - 2", - nome: "CAA - 2", - repValor: "3391.31", - tipo: "cargo_comissionado" as const, - valor: "4239.14", - vencValor: "847.83", - }, + { + descricao: 'Cargo de Direção e Assessoramento Superior - 5', + nome: 'DAS-5', + repValor: '4747.84', + tipo: 'cargo_comissionado' as const, + valor: '5934.80', + vencValor: '1186.96' + }, + { + descricao: 'Cargo de Direção e Assessoramento Superior - 3', + nome: 'DAS-3', + repValor: '6273.92', + tipo: 'cargo_comissionado' as const, + valor: '7842.40', + vencValor: '1568.48' + }, + { + descricao: 'Cargo de Direção e Assessoramento Superior -2', + nome: 'DAS - 2', + repValor: '7460.87', + tipo: 'cargo_comissionado' as const, + valor: '9326.09', + vencValor: '1865.22' + }, + { + descricao: 'Cargo de Apoio e Assessoramento - 1', + nome: 'CAA-1', + repValor: '4120.43', + tipo: 'cargo_comissionado' as const, + valor: '5150.54', + vencValor: '1030.11' + }, + { + descricao: 'Função Gratificada de Direção e Assessoramento', + nome: 'FDA', + repValor: '', + tipo: 'funcao_gratificada' as const, + valor: '7460.87', + vencValor: '' + }, + { + descricao: 'Função Gratificada de Supervisão - 3', + nome: 'CAA - 3', + repValor: '2204.36', + tipo: 'cargo_comissionado' as const, + valor: '2755.45', + vencValor: '551.09' + }, + { + descricao: 'Função Gratificada de Direção e Assessoramento -1', + nome: 'FDA-1', + repValor: '', + tipo: 'funcao_gratificada' as const, + valor: '6273.92', + vencValor: '' + }, + { + descricao: 'Função Gratificada de Direção e Assessoramento -2', + nome: 'FDA -2', + repValor: '', + tipo: 'funcao_gratificada' as const, + valor: '5765.22', + vencValor: '' + }, + { + descricao: 'Função Gratificada de Direção e Assessoramento - 3', + nome: 'FDA - 3', + repValor: '', + tipo: 'funcao_gratificada' as const, + valor: '4747.83', + vencValor: '' + }, + { + descricao: 'Função Gratificada de Direção e Assessoramento - 4', + nome: 'FDA - 4', + repValor: '', + tipo: 'funcao_gratificada' as const, + valor: '3391.31', + vencValor: '' + }, + { + descricao: 'Função Gratificada de Supervisão - 1', + nome: 'FGS -1 ', + repValor: '', + tipo: 'funcao_gratificada' as const, + valor: '1532.08', + vencValor: '' + }, + { + descricao: 'Função Gratificada de Supervisão - 2', + nome: 'FGS - 2', + repValor: '', + tipo: 'funcao_gratificada' as const, + valor: '934.74', + vencValor: '' + }, + { + descricao: 'Função Gratificada de Supervisão - 2', + nome: 'CAA - 2', + repValor: '3391.31', + tipo: 'cargo_comissionado' as const, + valor: '4239.14', + vencValor: '847.83' + } ]; const funcionariosData = [ - { - admissaoData: "01/01/2000", - cep: "50740500", - cidade: "Recife", - cpf: "04281554645", - email: "kilder@kilder.com.br", - endereco: "Rua Bernardino Alves Maia, Várzea", - matricula: "4585", - nascimento: "01/01/2000", - nome: "Madson Kilder", - rg: "123456122", - simboloNome: "DAS-3", // Será convertido para ID - simboloTipo: "cargo_comissionado" as const, - telefone: "8101234564", - uf: "PE", - }, - { - admissaoData: "01/01/2000", - cep: "50740400", - cidade: "Recife", - cpf: "05129038401", - email: "princesalves@gmail.com", - endereco: "Rua Deputado Cunha Rabelo, Várzea", - matricula: "123456", - nascimento: "05/01/1985", - nome: "Princes Alves rocha wanderley", - rg: "639541200", - simboloNome: "FDA-1", // Será convertido para ID - simboloTipo: "funcao_gratificada" as const, - telefone: "81123456455", - uf: "PE", - }, - { - admissaoData: "01/10/2025", - cep: "50740400", - cidade: "Recife", - cpf: "06102637496", - email: "deyvison.wanderley@gmail.com", - endereco: "Rua Deputado Cunha Rabelo, Várzea", - matricula: "256220", - nascimento: "16/03/1985", - nome: "Deyvison de França Wanderley", - rg: "6347974", - simboloNome: "CAA-1", // Será convertido para ID - simboloTipo: "cargo_comissionado" as const, - telefone: "81994235551", - uf: "PE", - }, + { + admissaoData: '01/01/2000', + cep: '50740500', + cidade: 'Recife', + cpf: '04281554645', + email: 'kilder@kilder.com.br', + endereco: 'Rua Bernardino Alves Maia, Várzea', + matricula: '4585', + nascimento: '01/01/2000', + nome: 'Madson Kilder', + rg: '123456122', + simboloNome: 'DAS-3', // Será convertido para ID + simboloTipo: 'cargo_comissionado' as const, + telefone: '8101234564', + uf: 'PE' + }, + { + admissaoData: '01/01/2000', + cep: '50740400', + cidade: 'Recife', + cpf: '05129038401', + email: 'princesalves@gmail.com', + endereco: 'Rua Deputado Cunha Rabelo, Várzea', + matricula: '123456', + nascimento: '05/01/1985', + nome: 'Princes Alves rocha wanderley', + rg: '639541200', + simboloNome: 'FDA-1', // Será convertido para ID + simboloTipo: 'funcao_gratificada' as const, + telefone: '81123456455', + uf: 'PE' + }, + { + admissaoData: '01/10/2025', + cep: '50740400', + cidade: 'Recife', + cpf: '06102637496', + email: 'deyvison.wanderley@gmail.com', + endereco: 'Rua Deputado Cunha Rabelo, Várzea', + matricula: '256220', + nascimento: '16/03/1985', + nome: 'Deyvison de França Wanderley', + rg: '6347974', + simboloNome: 'CAA-1', // Será convertido para ID + simboloTipo: 'cargo_comissionado' as const, + telefone: '81994235551', + uf: 'PE' + } ]; const solicitacoesAcessoData = [ - { - dataResposta: 1761445098933, - dataSolicitacao: 1761445038329, - email: "severino@gmail.com", - matricula: "3231", - nome: "Severino Gates", - observacoes: "Aprovação realizada por Deyvison", - status: "aprovado" as const, - telefone: "(81) 9942-3551", - }, - { - dataSolicitacao: 1761445187258, - email: "michaeljackson@gmail.com", - matricula: "123321", - nome: "Michael Jackson", - status: "pendente" as const, - telefone: "(81) 99423-5551", - }, + { + dataResposta: 1761445098933, + dataSolicitacao: 1761445038329, + email: 'severino@gmail.com', + matricula: '3231', + nome: 'Severino Gates', + observacoes: 'Aprovação realizada por Deyvison', + status: 'aprovado' as const, + telefone: '(81) 9942-3551' + }, + { + dataSolicitacao: 1761445187258, + email: 'michaeljackson@gmail.com', + matricula: '123321', + nome: 'Michael Jackson', + status: 'pendente' as const, + telefone: '(81) 99423-5551' + } ]; /** * Seed inicial do banco de dados com os dados exportados do Convex Cloud */ export const seedCreateRoles = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("🔐 Criando roles..."); - const ensureRole = async ( - nome: string, - descricao: string, - nivel: number, - setor?: string, - editavel?: boolean - ) => { - const existing = await ctx.db - .query("roles") - .withIndex("by_nome", (q) => q.eq("nome", nome)) - .first(); - if (existing) { - console.log(` ℹ️ Role já existe: ${nome}`); - return existing._id; - } - const id = await ctx.db.insert("roles", { - nome, - descricao, - nivel, - setor, - customizado: false, - editavel, - }); - console.log(` ✅ Role criada: ${nome}`); - return id; - }; + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('🔐 Criando roles...'); + const ensureRole = async ( + nome: string, + descricao: string, + nivel: number, + setor?: string, + editavel?: boolean + ) => { + const existing = await ctx.db + .query('roles') + .withIndex('by_nome', (q) => q.eq('nome', nome)) + .first(); + if (existing) { + console.log(` ℹ️ Role já existe: ${nome}`); + return existing._id; + } + const id = await ctx.db.insert('roles', { + nome, + descricao, + nivel, + setor, + customizado: false, + editavel + }); + console.log(` ✅ Role criada: ${nome}`); + return id; + }; - await ensureRole("ti_master", "TI Master", 0, "ti", false); - await ensureRole("admin", "Administrador Geral", 2, "administrativo", true); - await ensureRole("ti_usuario", "TI Usuário", 2, "ti", true); - await ensureRole("rh", "Recursos Humanos", 2, "recursos_humanos", false); - await ensureRole("financeiro", "Financeiro", 2, "financeiro", false); - await ensureRole("usuario", "Usuário Padrão", 3, undefined, false); - // Encadeia próxima etapa - await ctx.scheduler.runAfter(0, internal.seed.seedCreateSimbolos, {}); - return null; - }, + // Níveis agora são apenas 0 e 1. + // 0 = máximo, 1 = administrativo (ambos com acesso total). + await ensureRole('ti_master', 'TI Master', 0, 'ti', false); + await ensureRole('admin', 'Administrador Geral', 1, 'administrativo', true); + await ensureRole('ti_usuario', 'TI Usuário', 1, 'ti', true); + await ensureRole('rh', 'Recursos Humanos', 1, 'recursos_humanos', false); + await ensureRole('financeiro', 'Financeiro', 1, 'financeiro', false); + await ensureRole('usuario', 'Usuário Padrão', 1, undefined, false); + // Encadeia próximas etapas + await ctx.scheduler.runAfter(0, internal.seed.seedCreateSimbolos, {}); + await ctx.scheduler.runAfter(0, internal.seed.seedCreatePermissoesBase, {}); + return null; + } +}); + +export const seedCreatePermissoesBase = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('🔐 Criando permissões base...'); + await ctx.runMutation(api.permissoesAcoes.seedPermissoesBase, {}); + return null; + } }); export const seedCreateSimbolos = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("💰 Criando símbolos..."); - const existentes = await ctx.db.query("simbolos").collect(); - const nomesExistentes = new Set(existentes.map((s) => s.nome)); - for (const simbolo of simbolosData) { - if (nomesExistentes.has(simbolo.nome)) { - console.log(` ℹ️ Símbolo já existe: ${simbolo.nome}`); - continue; - } - await ctx.db.insert("simbolos", { - nome: simbolo.nome, - descricao: simbolo.descricao, - tipo: simbolo.tipo, - valor: simbolo.valor, - repValor: simbolo.repValor || "", - vencValor: simbolo.vencValor || "", - }); - console.log(` ✅ Símbolo criado: ${simbolo.nome}`); - } - // Encadeia próxima etapa - await ctx.scheduler.runAfter(0, internal.seed.seedCreateFuncionarios, {}); - return null; - }, + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('💰 Criando símbolos...'); + const existentes = await ctx.db.query('simbolos').collect(); + const nomesExistentes = new Set(existentes.map((s) => s.nome)); + for (const simbolo of simbolosData) { + if (nomesExistentes.has(simbolo.nome)) { + console.log(` ℹ️ Símbolo já existe: ${simbolo.nome}`); + continue; + } + await ctx.db.insert('simbolos', { + nome: simbolo.nome, + descricao: simbolo.descricao, + tipo: simbolo.tipo, + valor: simbolo.valor, + repValor: simbolo.repValor || '', + vencValor: simbolo.vencValor || '' + }); + console.log(` ✅ Símbolo criado: ${simbolo.nome}`); + } + // Encadeia próxima etapa + await ctx.scheduler.runAfter(0, internal.seed.seedCreateFuncionarios, {}); + return null; + } }); export const seedCreateFuncionarios = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("👥 Criando funcionários..."); - const simbolos = await ctx.db.query("simbolos").collect(); - const simbolosMap = new Map>(); - for (const s of simbolos) { - simbolosMap.set(s.nome, s._id as Id<"simbolos">); - } + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('👥 Criando funcionários...'); + const simbolos = await ctx.db.query('simbolos').collect(); + const simbolosMap = new Map>(); + for (const s of simbolos) { + simbolosMap.set(s.nome, s._id as Id<'simbolos'>); + } - for (const funcionario of funcionariosData) { - // Evitar duplicar por CPF - const existente = await ctx.db - .query("funcionarios") - .withIndex("by_cpf", (q) => q.eq("cpf", funcionario.cpf)) - .first(); - if (existente) { - console.log( - ` ℹ️ Funcionário já existe (CPF ${funcionario.cpf}): ${existente.nome}` - ); - continue; - } - const simboloId = simbolosMap.get(funcionario.simboloNome); - if (!simboloId) { - console.log(` ❌ Símbolo não encontrado: ${funcionario.simboloNome}`); - continue; - } - await ctx.db.insert("funcionarios", { - admissaoData: funcionario.admissaoData, - cep: funcionario.cep, - cidade: funcionario.cidade, - cpf: funcionario.cpf, - email: funcionario.email, - endereco: funcionario.endereco, - matricula: funcionario.matricula, - nascimento: funcionario.nascimento, - nome: funcionario.nome, - rg: funcionario.rg, - simboloId: simboloId as Id<"simbolos">, - simboloTipo: funcionario.simboloTipo, - telefone: funcionario.telefone, - uf: funcionario.uf, - }); - console.log(` ✅ Funcionário criado: ${funcionario.nome}`); - } - // Encadeia próxima etapa - await ctx.scheduler.runAfter( - 0, - internal.seed.seedCreateUsuariosParaFuncionarios, - {} - ); - return null; - }, + for (const funcionario of funcionariosData) { + // Evitar duplicar por CPF + const existente = await ctx.db + .query('funcionarios') + .withIndex('by_cpf', (q) => q.eq('cpf', funcionario.cpf)) + .first(); + if (existente) { + console.log(` ℹ️ Funcionário já existe (CPF ${funcionario.cpf}): ${existente.nome}`); + continue; + } + const simboloId = simbolosMap.get(funcionario.simboloNome); + if (!simboloId) { + console.log(` ❌ Símbolo não encontrado: ${funcionario.simboloNome}`); + continue; + } + await ctx.db.insert('funcionarios', { + admissaoData: funcionario.admissaoData, + cep: funcionario.cep, + cidade: funcionario.cidade, + cpf: funcionario.cpf, + email: funcionario.email, + endereco: funcionario.endereco, + matricula: funcionario.matricula, + nascimento: funcionario.nascimento, + nome: funcionario.nome, + rg: funcionario.rg, + simboloId: simboloId as Id<'simbolos'>, + simboloTipo: funcionario.simboloTipo, + telefone: funcionario.telefone, + uf: funcionario.uf + }); + console.log(` ✅ Funcionário criado: ${funcionario.nome}`); + } + // Encadeia próxima etapa + await ctx.scheduler.runAfter(0, internal.seed.seedCreateUsuariosParaFuncionarios, {}); + return null; + } }); export const seedCreateUsuariosParaFuncionarios = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("👤 Criando usuários para funcionários..."); - // Agenda criação por funcionário para evitar timeout - let delay = 0; - for (const funcionario of funcionariosData) { - await ctx.scheduler.runAfter( - delay, - internal.seed.seedCreateUsuarioParaFuncionario, - { - matricula: funcionario.matricula, - nome: funcionario.nome, - email: funcionario.email, - } - ); - delay += 50; - } - // Agenda próxima etapa após as criações individuais - await ctx.scheduler.runAfter( - delay + 300, - internal.seed.seedInserirSolicitacoesAcesso, - {} - ); - return null; - }, + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('👤 Criando usuários para funcionários...'); + // Agenda criação por funcionário para evitar timeout + let delay = 0; + for (const funcionario of funcionariosData) { + await ctx.scheduler.runAfter(delay, internal.seed.seedCreateUsuarioParaFuncionario, { + matricula: funcionario.matricula, + nome: funcionario.nome, + email: funcionario.email + }); + delay += 50; + } + // Agenda próxima etapa após as criações individuais + await ctx.scheduler.runAfter(delay + 300, internal.seed.seedInserirSolicitacoesAcesso, {}); + return null; + } }); export const seedCreateUsuarioParaFuncionario = internalMutation({ - args: { - matricula: v.string(), - nome: v.string(), - email: v.string(), - }, - returns: v.null(), - handler: async (ctx, args) => { - // Role "usuario" - const roleUsuario = await ctx.db - .query("roles") - .withIndex("by_nome", (q) => q.eq("nome", "usuario")) - .first(); - if (!roleUsuario) { - console.log(' ❌ Role "usuario" não encontrada'); - return null; - } + args: { + matricula: v.string(), + nome: v.string(), + email: v.string() + }, + returns: v.null(), + handler: async (ctx, args) => { + // Role "usuario" + const roleUsuario = await ctx.db + .query('roles') + .withIndex('by_nome', (q) => q.eq('nome', 'usuario')) + .first(); + if (!roleUsuario) { + console.log(' ❌ Role "usuario" não encontrada'); + return null; + } - const funcionarioDoc = await ctx.db - .query("funcionarios") - .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula)) - .first(); - if (!funcionarioDoc) { - console.log( - ` ❌ Funcionário não encontrado pela matrícula: ${args.matricula}` - ); - return null; - } + const funcionarioDoc = await ctx.db + .query('funcionarios') + .withIndex('by_matricula', (q) => q.eq('matricula', args.matricula)) + .first(); + if (!funcionarioDoc) { + console.log(` ❌ Funcionário não encontrado pela matrícula: ${args.matricula}`); + return null; + } - const usuarioExistente = await ctx.db - .query("usuarios") - .withIndex("by_email", (q) => q.eq("email", args.email)) - .first(); - if (usuarioExistente) { - console.log(` ℹ️ Usuário já existe para ${args.email}`); - return null; - } + const usuarioExistente = await ctx.db + .query('usuarios') + .withIndex('by_email', (q) => q.eq('email', args.email)) + .first(); + if (usuarioExistente) { + console.log(` ℹ️ Usuário já existe para ${args.email}`); + return null; + } - const authUserId = await createAuthUser(ctx, { - nome: args.nome, - email: args.email, - password: "Mudar@123", - }); + const authUserId = await createAuthUser(ctx, { + nome: args.nome, + email: args.email, + password: 'Mudar@123' + }); - await ctx.db.insert("usuarios", { - authId: authUserId, - nome: args.nome, - email: args.email, - funcionarioId: funcionarioDoc._id as Id<"funcionarios">, - roleId: roleUsuario._id, - ativo: true, - primeiroAcesso: true, - criadoEm: Date.now(), - atualizadoEm: Date.now(), - }); - console.log(` ✅ Usuário criado: ${args.nome} (senha: Mudar@123)`); - return null; - }, + await ctx.db.insert('usuarios', { + authId: authUserId, + nome: args.nome, + email: args.email, + funcionarioId: funcionarioDoc._id as Id<'funcionarios'>, + roleId: roleUsuario._id, + ativo: true, + primeiroAcesso: true, + criadoEm: Date.now(), + atualizadoEm: Date.now() + }); + console.log(` ✅ Usuário criado: ${args.nome} (senha: Mudar@123)`); + return null; + } }); export const seedInserirSolicitacoesAcesso = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("📋 Inserindo solicitações de acesso..."); - for (const solicitacao of solicitacoesAcessoData) { - // Evitar duplicidade por matrícula - const existente = await ctx.db - .query("solicitacoesAcesso") - .withIndex("by_matricula", (q) => - q.eq("matricula", solicitacao.matricula) - ) - .first(); - if (existente) { - console.log( - ` ℹ️ Solicitação já existe p/ matrícula ${solicitacao.matricula}` - ); - continue; - } - const dadosSolicitacao: { - nome: string; - matricula: string; - email: string; - telefone: string; - status: "pendente" | "aprovado" | "rejeitado"; - dataSolicitacao: number; - dataResposta?: number; - observacoes?: string; - } = { - nome: solicitacao.nome, - matricula: solicitacao.matricula, - email: solicitacao.email, - telefone: solicitacao.telefone, - status: solicitacao.status, - dataSolicitacao: solicitacao.dataSolicitacao, - }; + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('📋 Inserindo solicitações de acesso...'); + for (const solicitacao of solicitacoesAcessoData) { + // Evitar duplicidade por matrícula + const existente = await ctx.db + .query('solicitacoesAcesso') + .withIndex('by_matricula', (q) => q.eq('matricula', solicitacao.matricula)) + .first(); + if (existente) { + console.log(` ℹ️ Solicitação já existe p/ matrícula ${solicitacao.matricula}`); + continue; + } + const dadosSolicitacao: { + nome: string; + matricula: string; + email: string; + telefone: string; + status: 'pendente' | 'aprovado' | 'rejeitado'; + dataSolicitacao: number; + dataResposta?: number; + observacoes?: string; + } = { + nome: solicitacao.nome, + matricula: solicitacao.matricula, + email: solicitacao.email, + telefone: solicitacao.telefone, + status: solicitacao.status, + dataSolicitacao: solicitacao.dataSolicitacao + }; - if (solicitacao.dataResposta) { - dadosSolicitacao.dataResposta = solicitacao.dataResposta; - } + if (solicitacao.dataResposta) { + dadosSolicitacao.dataResposta = solicitacao.dataResposta; + } - if (solicitacao.observacoes) { - dadosSolicitacao.observacoes = solicitacao.observacoes; - } + if (solicitacao.observacoes) { + dadosSolicitacao.observacoes = solicitacao.observacoes; + } - await ctx.db.insert("solicitacoesAcesso", dadosSolicitacao); - console.log( - ` ✅ Solicitação criada: ${solicitacao.nome} (${solicitacao.status})` - ); - } - console.log("✨ Seed concluído!"); - return null; - }, + await ctx.db.insert('solicitacoesAcesso', dadosSolicitacao); + console.log(` ✅ Solicitação criada: ${solicitacao.nome} (${solicitacao.status})`); + } + console.log('✨ Seed concluído!'); + return null; + } }); export const seedDatabase = internalAction({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("🌱 Iniciando seed do banco de dados (action)..."); - await ctx.runMutation(internal.seed.seedCreateRoles, {}); - await ctx.runMutation(internal.seed.seedCreateSimbolos, {}); - await ctx.runMutation(internal.seed.seedCreateFuncionarios, {}); - await ctx.runMutation(internal.seed.seedCreateUsuariosParaFuncionarios, {}); - await ctx.runMutation(internal.seed.seedInserirSolicitacoesAcesso, {}); - console.log("✨ Seed do banco de dados concluído com sucesso pela action!"); - return null; - }, + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('🌱 Iniciando seed do banco de dados (action)...'); + await ctx.runMutation(internal.seed.seedCreateRoles, {}); + await ctx.runMutation(internal.seed.seedCreateSimbolos, {}); + await ctx.runMutation(internal.seed.seedCreateFuncionarios, {}); + await ctx.runMutation(internal.seed.seedCreateUsuariosParaFuncionarios, {}); + await ctx.runMutation(internal.seed.seedInserirSolicitacoesAcesso, {}); + console.log('✨ Seed do banco de dados concluído com sucesso pela action!'); + return null; + } }); /** @@ -486,275 +471,243 @@ export const seedDatabase = internalAction({ * Permite executar via CLI: `npx convex run seed:popularBanco` */ export const popularBanco = mutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log( - "🌱 Executando popularBanco (wrapper público para seedDatabase)..." - ); - // Agenda apenas a primeira etapa; as demais serão encadeadas internamente - await ctx.scheduler.runAfter(0, internal.seed.seedCreateRoles, {}); - console.log("✅ Seed iniciado (etapa 1 agendada)"); - return null; - }, + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('🌱 Executando popularBanco (wrapper público para seedDatabase)...'); + // Agenda apenas a primeira etapa; as demais serão encadeadas internamente + await ctx.scheduler.runAfter(0, internal.seed.seedCreateRoles, {}); + console.log('✅ Seed iniciado (etapa 1 agendada)'); + return null; + } }); /** * Limpar todos os dados do banco */ export const clearDatabase = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("🗑️ Limpando banco de dados..."); + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log('🗑️ Limpando banco de dados...'); - // Limpar em ordem (respeitando dependências) + // Limpar em ordem (respeitando dependências) - // 1. Tabelas de logs e auditoria - const logsAcesso = await ctx.db.query("logsAcesso").collect(); - for (const log of logsAcesso) { - await ctx.db.delete(log._id); - } - console.log(` ✅ ${logsAcesso.length} logs de acesso removidos`); + // 1. Tabelas de logs e auditoria + const logsAcesso = await ctx.db.query('logsAcesso').collect(); + for (const log of logsAcesso) { + await ctx.db.delete(log._id); + } + console.log(` ✅ ${logsAcesso.length} logs de acesso removidos`); - const logsLogin = await ctx.db.query("logsLogin").collect(); - for (const log of logsLogin) { - await ctx.db.delete(log._id); - } - console.log(` ✅ ${logsLogin.length} logs de login removidos`); + const logsLogin = await ctx.db.query('logsLogin').collect(); + for (const log of logsLogin) { + await ctx.db.delete(log._id); + } + console.log(` ✅ ${logsLogin.length} logs de login removidos`); - const logsAtividades = await ctx.db.query("logsAtividades").collect(); - for (const log of logsAtividades) { - await ctx.db.delete(log._id); - } - console.log(` ✅ ${logsAtividades.length} logs de atividades removidos`); + const logsAtividades = await ctx.db.query('logsAtividades').collect(); + for (const log of logsAtividades) { + await ctx.db.delete(log._id); + } + console.log(` ✅ ${logsAtividades.length} logs de atividades removidos`); - // 2. Sistema de chat - const leituras = await ctx.db.query("leituras").collect(); - for (const leitura of leituras) { - await ctx.db.delete(leitura._id); - } - console.log(` ✅ ${leituras.length} leituras removidas`); + // 2. Sistema de chat + const leituras = await ctx.db.query('leituras').collect(); + for (const leitura of leituras) { + await ctx.db.delete(leitura._id); + } + console.log(` ✅ ${leituras.length} leituras removidas`); - const mensagens = await ctx.db.query("mensagens").collect(); - for (const mensagem of mensagens) { - await ctx.db.delete(mensagem._id); - } - console.log(` ✅ ${mensagens.length} mensagens removidas`); + const mensagens = await ctx.db.query('mensagens').collect(); + for (const mensagem of mensagens) { + await ctx.db.delete(mensagem._id); + } + console.log(` ✅ ${mensagens.length} mensagens removidas`); - const digitando = await ctx.db.query("digitando").collect(); - for (const d of digitando) { - await ctx.db.delete(d._id); - } - console.log(` ✅ ${digitando.length} registros de digitando removidos`); + const digitando = await ctx.db.query('digitando').collect(); + for (const d of digitando) { + await ctx.db.delete(d._id); + } + console.log(` ✅ ${digitando.length} registros de digitando removidos`); - const conversas = await ctx.db.query("conversas").collect(); - for (const conversa of conversas) { - await ctx.db.delete(conversa._id); - } - console.log(` ✅ ${conversas.length} conversas removidas`); + const conversas = await ctx.db.query('conversas').collect(); + for (const conversa of conversas) { + await ctx.db.delete(conversa._id); + } + console.log(` ✅ ${conversas.length} conversas removidas`); - // 3. Notificações - const notificacoes = await ctx.db.query("notificacoes").collect(); - for (const notificacao of notificacoes) { - await ctx.db.delete(notificacao._id); - } - console.log(` ✅ ${notificacoes.length} notificações removidas`); + // 3. Notificações + const notificacoes = await ctx.db.query('notificacoes').collect(); + for (const notificacao of notificacoes) { + await ctx.db.delete(notificacao._id); + } + console.log(` ✅ ${notificacoes.length} notificações removidas`); - const notificacoesEmail = await ctx.db.query("notificacoesEmail").collect(); - for (const email of notificacoesEmail) { - await ctx.db.delete(email._id); - } - console.log( - ` ✅ ${notificacoesEmail.length} notificações de email removidas` - ); + const notificacoesEmail = await ctx.db.query('notificacoesEmail').collect(); + for (const email of notificacoesEmail) { + await ctx.db.delete(email._id); + } + console.log(` ✅ ${notificacoesEmail.length} notificações de email removidas`); - const notificacoesFerias = await ctx.db - .query("notificacoesFerias") - .collect(); - for (const notif of notificacoesFerias) { - await ctx.db.delete(notif._id); - } - console.log( - ` ✅ ${notificacoesFerias.length} notificações de férias removidas` - ); + const notificacoesFerias = await ctx.db.query('notificacoesFerias').collect(); + for (const notif of notificacoesFerias) { + await ctx.db.delete(notif._id); + } + console.log(` ✅ ${notificacoesFerias.length} notificações de férias removidas`); - // 4. Férias - const ferias = await ctx.db - .query("ferias") - .collect(); - for (const feriasRegistro of ferias) { - await ctx.db.delete(feriasRegistro._id); - } - console.log( - ` ✅ ${ferias.length} registros de férias removidos` - ); + // 4. Férias + const ferias = await ctx.db.query('ferias').collect(); + for (const feriasRegistro of ferias) { + await ctx.db.delete(feriasRegistro._id); + } + console.log(` ✅ ${ferias.length} registros de férias removidos`); - // 5. Atestados - const atestados = await ctx.db.query("atestados").collect(); - for (const atestado of atestados) { - await ctx.db.delete(atestado._id); - } - console.log(` ✅ ${atestados.length} atestados removidos`); + // 5. Atestados + const atestados = await ctx.db.query('atestados').collect(); + for (const atestado of atestados) { + await ctx.db.delete(atestado._id); + } + console.log(` ✅ ${atestados.length} atestados removidos`); - // 6. Times e membros - const timesMembros = await ctx.db.query("timesMembros").collect(); - for (const membro of timesMembros) { - await ctx.db.delete(membro._id); - } - console.log(` ✅ ${timesMembros.length} membros de times removidos`); + // 6. Times e membros + const timesMembros = await ctx.db.query('timesMembros').collect(); + for (const membro of timesMembros) { + await ctx.db.delete(membro._id); + } + console.log(` ✅ ${timesMembros.length} membros de times removidos`); - const times = await ctx.db.query("times").collect(); - for (const time of times) { - await ctx.db.delete(time._id); - } - console.log(` ✅ ${times.length} times removidos`); + const times = await ctx.db.query('times').collect(); + for (const time of times) { + await ctx.db.delete(time._id); + } + console.log(` ✅ ${times.length} times removidos`); - // 7. Cursos - const cursos = await ctx.db.query("cursos").collect(); - for (const curso of cursos) { - await ctx.db.delete(curso._id); - } - console.log(` ✅ ${cursos.length} cursos removidos`); + // 7. Cursos + const cursos = await ctx.db.query('cursos').collect(); + for (const curso of cursos) { + await ctx.db.delete(curso._id); + } + console.log(` ✅ ${cursos.length} cursos removidos`); - // 8. Bloqueios de usuários - const bloqueiosUsuarios = await ctx.db.query("bloqueiosUsuarios").collect(); - for (const bloqueio of bloqueiosUsuarios) { - await ctx.db.delete(bloqueio._id); - } - console.log( - ` ✅ ${bloqueiosUsuarios.length} bloqueios de usuários removidos` - ); + // 8. Bloqueios de usuários + const bloqueiosUsuarios = await ctx.db.query('bloqueiosUsuarios').collect(); + for (const bloqueio of bloqueiosUsuarios) { + await ctx.db.delete(bloqueio._id); + } + console.log(` ✅ ${bloqueiosUsuarios.length} bloqueios de usuários removidos`); - // 9. Perfis customizados + // 9. Perfis customizados - // 10. Templates de mensagens - const templatesMensagens = await ctx.db - .query("templatesMensagens") - .collect(); - for (const template of templatesMensagens) { - await ctx.db.delete(template._id); - } - console.log( - ` ✅ ${templatesMensagens.length} templates de mensagens removidos` - ); + // 10. Templates de mensagens + const templatesMensagens = await ctx.db.query('templatesMensagens').collect(); + for (const template of templatesMensagens) { + await ctx.db.delete(template._id); + } + console.log(` ✅ ${templatesMensagens.length} templates de mensagens removidos`); - // 11. Configurações - const configuracaoEmail = await ctx.db.query("configuracaoEmail").collect(); - for (const config of configuracaoEmail) { - await ctx.db.delete(config._id); - } - console.log( - ` ✅ ${configuracaoEmail.length} configurações de email removidas` - ); + // 11. Configurações + const configuracaoEmail = await ctx.db.query('configuracaoEmail').collect(); + for (const config of configuracaoEmail) { + await ctx.db.delete(config._id); + } + console.log(` ✅ ${configuracaoEmail.length} configurações de email removidas`); - const configuracaoAcesso = await ctx.db - .query("configuracaoAcesso") - .collect(); - for (const config of configuracaoAcesso) { - await ctx.db.delete(config._id); - } - console.log( - ` ✅ ${configuracaoAcesso.length} configurações de acesso removidas` - ); + const configuracaoAcesso = await ctx.db.query('configuracaoAcesso').collect(); + for (const config of configuracaoAcesso) { + await ctx.db.delete(config._id); + } + console.log(` ✅ ${configuracaoAcesso.length} configurações de acesso removidas`); - // 12. Monitoramento - const alertHistory = await ctx.db.query("alertHistory").collect(); - for (const alert of alertHistory) { - await ctx.db.delete(alert._id); - } - console.log(` ✅ ${alertHistory.length} histórico de alertas removido`); + // 12. Monitoramento + const alertHistory = await ctx.db.query('alertHistory').collect(); + for (const alert of alertHistory) { + await ctx.db.delete(alert._id); + } + console.log(` ✅ ${alertHistory.length} histórico de alertas removido`); - const alertConfigurations = await ctx.db - .query("alertConfigurations") - .collect(); - for (const alert of alertConfigurations) { - await ctx.db.delete(alert._id); - } - console.log( - ` ✅ ${alertConfigurations.length} configurações de alertas removidas` - ); + const alertConfigurations = await ctx.db.query('alertConfigurations').collect(); + for (const alert of alertConfigurations) { + await ctx.db.delete(alert._id); + } + console.log(` ✅ ${alertConfigurations.length} configurações de alertas removidas`); - const systemMetrics = await ctx.db.query("systemMetrics").collect(); - for (const metric of systemMetrics) { - await ctx.db.delete(metric._id); - } - console.log(` ✅ ${systemMetrics.length} métricas do sistema removidas`); + const systemMetrics = await ctx.db.query('systemMetrics').collect(); + for (const metric of systemMetrics) { + await ctx.db.delete(metric._id); + } + console.log(` ✅ ${systemMetrics.length} métricas do sistema removidas`); - // 13. Sessões - const sessoes = await ctx.db.query("sessoes").collect(); - for (const sessao of sessoes) { - await ctx.db.delete(sessao._id); - } - console.log(` ✅ ${sessoes.length} sessões removidas`); + // 13. Sessões + const sessoes = await ctx.db.query('sessoes').collect(); + for (const sessao of sessoes) { + await ctx.db.delete(sessao._id); + } + console.log(` ✅ ${sessoes.length} sessões removidas`); - // 14. Menu-permissões personalizadas + // 14. Menu-permissões personalizadas - // 15. Menu-permissões + // 15. Menu-permissões - // 16. Role-permissões - const rolePermissoes = await ctx.db.query("rolePermissoes").collect(); - for (const rp of rolePermissoes) { - await ctx.db.delete(rp._id); - } - console.log(` ✅ ${rolePermissoes.length} role-permissões removidas`); + // 16. Role-permissões + const rolePermissoes = await ctx.db.query('rolePermissoes').collect(); + for (const rp of rolePermissoes) { + await ctx.db.delete(rp._id); + } + console.log(` ✅ ${rolePermissoes.length} role-permissões removidas`); - // 17. Permissões - const permissoes = await ctx.db.query("permissoes").collect(); - for (const permissao of permissoes) { - await ctx.db.delete(permissao._id); - } - console.log(` ✅ ${permissoes.length} permissões removidas`); + // 17. Permissões + const permissoes = await ctx.db.query('permissoes').collect(); + for (const permissao of permissoes) { + await ctx.db.delete(permissao._id); + } + console.log(` ✅ ${permissoes.length} permissões removidas`); - // 18. Usuários (deve vir antes de roles se houver referência) - const usuarios = await ctx.db.query("usuarios").collect(); - for (const usuario of usuarios) { - await ctx.db.delete(usuario._id); - } - console.log(` ✅ ${usuarios.length} usuários removidos`); + // 18. Usuários (deve vir antes de roles se houver referência) + const usuarios = await ctx.db.query('usuarios').collect(); + for (const usuario of usuarios) { + await ctx.db.delete(usuario._id); + } + console.log(` ✅ ${usuarios.length} usuários removidos`); - // 19. Funcionários - const funcionarios = await ctx.db.query("funcionarios").collect(); - for (const funcionario of funcionarios) { - await ctx.db.delete(funcionario._id); - } - console.log(` ✅ ${funcionarios.length} funcionários removidos`); + // 19. Funcionários + const funcionarios = await ctx.db.query('funcionarios').collect(); + for (const funcionario of funcionarios) { + await ctx.db.delete(funcionario._id); + } + console.log(` ✅ ${funcionarios.length} funcionários removidos`); - // 20. Solicitações de acesso - const solicitacoesAcesso = await ctx.db - .query("solicitacoesAcesso") - .collect(); - for (const solicitacao of solicitacoesAcesso) { - await ctx.db.delete(solicitacao._id); - } - console.log( - ` ✅ ${solicitacoesAcesso.length} solicitações de acesso removidas` - ); + // 20. Solicitações de acesso + const solicitacoesAcesso = await ctx.db.query('solicitacoesAcesso').collect(); + for (const solicitacao of solicitacoesAcesso) { + await ctx.db.delete(solicitacao._id); + } + console.log(` ✅ ${solicitacoesAcesso.length} solicitações de acesso removidas`); - // 21. Símbolos - const simbolos = await ctx.db.query("simbolos").collect(); - for (const simbolo of simbolos) { - await ctx.db.delete(simbolo._id); - } - console.log(` ✅ ${simbolos.length} símbolos removidos`); + // 21. Símbolos + const simbolos = await ctx.db.query('simbolos').collect(); + for (const simbolo of simbolos) { + await ctx.db.delete(simbolo._id); + } + console.log(` ✅ ${simbolos.length} símbolos removidos`); - // 22. Roles (deve vir por último se outras tabelas referenciam) - const roles = await ctx.db.query("roles").collect(); - for (const role of roles) { - await ctx.db.delete(role._id); - } - console.log(` ✅ ${roles.length} roles removidas`); + // 22. Roles (deve vir por último se outras tabelas referenciam) + const roles = await ctx.db.query('roles').collect(); + for (const role of roles) { + await ctx.db.delete(role._id); + } + console.log(` ✅ ${roles.length} roles removidas`); - // 23. Todos (tabela de exemplo) - const todos = await ctx.db.query("todos").collect(); - for (const todo of todos) { - await ctx.db.delete(todo._id); - } - console.log(` ✅ ${todos.length} todos removidos`); + // 23. Todos (tabela de exemplo) + const todos = await ctx.db.query('todos').collect(); + for (const todo of todos) { + await ctx.db.delete(todo._id); + } + console.log(` ✅ ${todos.length} todos removidos`); - console.log("✨ Banco de dados completamente limpo!"); - return null; - }, + console.log('✨ Banco de dados completamente limpo!'); + return null; + } }); /** @@ -762,286 +715,255 @@ export const clearDatabase = internalMutation({ * ATENÇÃO: Esta função deleta TODOS os dados do banco! */ export const limparBanco = mutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - // Executa diretamente a limpeza (mesmo código da internalMutation) - console.log("🗑️ Limpando banco de dados..."); + args: {}, + returns: v.null(), + handler: async (ctx) => { + // Executa diretamente a limpeza (mesmo código da internalMutation) + console.log('🗑️ Limpando banco de dados...'); - // Limpar em ordem (respeitando dependências) + // Limpar em ordem (respeitando dependências) - // 1. Tabelas de logs e auditoria - const logsAcesso = await ctx.db.query("logsAcesso").collect(); - for (const log of logsAcesso) { - await ctx.db.delete(log._id); - } - console.log(` ✅ ${logsAcesso.length} logs de acesso removidos`); + // 1. Tabelas de logs e auditoria + const logsAcesso = await ctx.db.query('logsAcesso').collect(); + for (const log of logsAcesso) { + await ctx.db.delete(log._id); + } + console.log(` ✅ ${logsAcesso.length} logs de acesso removidos`); - const logsLogin = await ctx.db.query("logsLogin").collect(); - for (const log of logsLogin) { - await ctx.db.delete(log._id); - } - console.log(` ✅ ${logsLogin.length} logs de login removidos`); + const logsLogin = await ctx.db.query('logsLogin').collect(); + for (const log of logsLogin) { + await ctx.db.delete(log._id); + } + console.log(` ✅ ${logsLogin.length} logs de login removidos`); - const logsAtividades = await ctx.db.query("logsAtividades").collect(); - for (const log of logsAtividades) { - await ctx.db.delete(log._id); - } - console.log(` ✅ ${logsAtividades.length} logs de atividades removidos`); + const logsAtividades = await ctx.db.query('logsAtividades').collect(); + for (const log of logsAtividades) { + await ctx.db.delete(log._id); + } + console.log(` ✅ ${logsAtividades.length} logs de atividades removidos`); - // 2. Sistema de chat - const leituras = await ctx.db.query("leituras").collect(); - for (const leitura of leituras) { - await ctx.db.delete(leitura._id); - } - console.log(` ✅ ${leituras.length} leituras removidas`); + // 2. Sistema de chat + const leituras = await ctx.db.query('leituras').collect(); + for (const leitura of leituras) { + await ctx.db.delete(leitura._id); + } + console.log(` ✅ ${leituras.length} leituras removidas`); - const mensagens = await ctx.db.query("mensagens").collect(); - for (const mensagem of mensagens) { - await ctx.db.delete(mensagem._id); - } - console.log(` ✅ ${mensagens.length} mensagens removidas`); + const mensagens = await ctx.db.query('mensagens').collect(); + for (const mensagem of mensagens) { + await ctx.db.delete(mensagem._id); + } + console.log(` ✅ ${mensagens.length} mensagens removidas`); - const digitando = await ctx.db.query("digitando").collect(); - for (const d of digitando) { - await ctx.db.delete(d._id); - } - console.log(` ✅ ${digitando.length} registros de digitando removidos`); + const digitando = await ctx.db.query('digitando').collect(); + for (const d of digitando) { + await ctx.db.delete(d._id); + } + console.log(` ✅ ${digitando.length} registros de digitando removidos`); - const conversas = await ctx.db.query("conversas").collect(); - for (const conversa of conversas) { - await ctx.db.delete(conversa._id); - } - console.log(` ✅ ${conversas.length} conversas removidas`); + const conversas = await ctx.db.query('conversas').collect(); + for (const conversa of conversas) { + await ctx.db.delete(conversa._id); + } + console.log(` ✅ ${conversas.length} conversas removidas`); - // 3. Notificações - const notificacoes = await ctx.db.query("notificacoes").collect(); - for (const notificacao of notificacoes) { - await ctx.db.delete(notificacao._id); - } - console.log(` ✅ ${notificacoes.length} notificações removidas`); + // 3. Notificações + const notificacoes = await ctx.db.query('notificacoes').collect(); + for (const notificacao of notificacoes) { + await ctx.db.delete(notificacao._id); + } + console.log(` ✅ ${notificacoes.length} notificações removidas`); - const notificacoesEmail = await ctx.db.query("notificacoesEmail").collect(); - for (const email of notificacoesEmail) { - await ctx.db.delete(email._id); - } - console.log( - ` ✅ ${notificacoesEmail.length} notificações de email removidas` - ); + const notificacoesEmail = await ctx.db.query('notificacoesEmail').collect(); + for (const email of notificacoesEmail) { + await ctx.db.delete(email._id); + } + console.log(` ✅ ${notificacoesEmail.length} notificações de email removidas`); - const notificacoesFerias = await ctx.db - .query("notificacoesFerias") - .collect(); - for (const notif of notificacoesFerias) { - await ctx.db.delete(notif._id); - } - console.log( - ` ✅ ${notificacoesFerias.length} notificações de férias removidas` - ); + const notificacoesFerias = await ctx.db.query('notificacoesFerias').collect(); + for (const notif of notificacoesFerias) { + await ctx.db.delete(notif._id); + } + console.log(` ✅ ${notificacoesFerias.length} notificações de férias removidas`); - // 4. Férias - const ferias = await ctx.db - .query("ferias") - .collect(); - for (const feriasRegistro of ferias) { - await ctx.db.delete(feriasRegistro._id); - } - console.log( - ` ✅ ${ferias.length} registros de férias removidos` - ); + // 4. Férias + const ferias = await ctx.db.query('ferias').collect(); + for (const feriasRegistro of ferias) { + await ctx.db.delete(feriasRegistro._id); + } + console.log(` ✅ ${ferias.length} registros de férias removidos`); - // 5. Atestados - const atestados = await ctx.db.query("atestados").collect(); - for (const atestado of atestados) { - await ctx.db.delete(atestado._id); - } - console.log(` ✅ ${atestados.length} atestados removidos`); + // 5. Atestados + const atestados = await ctx.db.query('atestados').collect(); + for (const atestado of atestados) { + await ctx.db.delete(atestado._id); + } + console.log(` ✅ ${atestados.length} atestados removidos`); - // 6. Times e membros - const timesMembros = await ctx.db.query("timesMembros").collect(); - for (const membro of timesMembros) { - await ctx.db.delete(membro._id); - } - console.log(` ✅ ${timesMembros.length} membros de times removidos`); + // 6. Times e membros + const timesMembros = await ctx.db.query('timesMembros').collect(); + for (const membro of timesMembros) { + await ctx.db.delete(membro._id); + } + console.log(` ✅ ${timesMembros.length} membros de times removidos`); - const times = await ctx.db.query("times").collect(); - for (const time of times) { - await ctx.db.delete(time._id); - } - console.log(` ✅ ${times.length} times removidos`); + const times = await ctx.db.query('times').collect(); + for (const time of times) { + await ctx.db.delete(time._id); + } + console.log(` ✅ ${times.length} times removidos`); - // 7. Cursos - const cursos = await ctx.db.query("cursos").collect(); - for (const curso of cursos) { - await ctx.db.delete(curso._id); - } - console.log(` ✅ ${cursos.length} cursos removidos`); + // 7. Cursos + const cursos = await ctx.db.query('cursos').collect(); + for (const curso of cursos) { + await ctx.db.delete(curso._id); + } + console.log(` ✅ ${cursos.length} cursos removidos`); - // 8. Bloqueios de usuários - const bloqueiosUsuarios = await ctx.db.query("bloqueiosUsuarios").collect(); - for (const bloqueio of bloqueiosUsuarios) { - await ctx.db.delete(bloqueio._id); - } - console.log( - ` ✅ ${bloqueiosUsuarios.length} bloqueios de usuários removidos` - ); + // 8. Bloqueios de usuários + const bloqueiosUsuarios = await ctx.db.query('bloqueiosUsuarios').collect(); + for (const bloqueio of bloqueiosUsuarios) { + await ctx.db.delete(bloqueio._id); + } + console.log(` ✅ ${bloqueiosUsuarios.length} bloqueios de usuários removidos`); - // 9. Perfis customizados (já está no código da internalMutation mas vazio) + // 9. Perfis customizados (já está no código da internalMutation mas vazio) - // 10. Templates de mensagens - const templatesMensagens = await ctx.db - .query("templatesMensagens") - .collect(); - for (const template of templatesMensagens) { - await ctx.db.delete(template._id); - } - console.log( - ` ✅ ${templatesMensagens.length} templates de mensagens removidos` - ); + // 10. Templates de mensagens + const templatesMensagens = await ctx.db.query('templatesMensagens').collect(); + for (const template of templatesMensagens) { + await ctx.db.delete(template._id); + } + console.log(` ✅ ${templatesMensagens.length} templates de mensagens removidos`); - // 11. Configurações - const configuracaoEmail = await ctx.db.query("configuracaoEmail").collect(); - for (const config of configuracaoEmail) { - await ctx.db.delete(config._id); - } - console.log( - ` ✅ ${configuracaoEmail.length} configurações de email removidas` - ); + // 11. Configurações + const configuracaoEmail = await ctx.db.query('configuracaoEmail').collect(); + for (const config of configuracaoEmail) { + await ctx.db.delete(config._id); + } + console.log(` ✅ ${configuracaoEmail.length} configurações de email removidas`); - const configuracaoAcesso = await ctx.db - .query("configuracaoAcesso") - .collect(); - for (const config of configuracaoAcesso) { - await ctx.db.delete(config._id); - } - console.log( - ` ✅ ${configuracaoAcesso.length} configurações de acesso removidas` - ); + const configuracaoAcesso = await ctx.db.query('configuracaoAcesso').collect(); + for (const config of configuracaoAcesso) { + await ctx.db.delete(config._id); + } + console.log(` ✅ ${configuracaoAcesso.length} configurações de acesso removidas`); - // 12. Monitoramento - const alertHistory = await ctx.db.query("alertHistory").collect(); - for (const alert of alertHistory) { - await ctx.db.delete(alert._id); - } - console.log(` ✅ ${alertHistory.length} histórico de alertas removido`); + // 12. Monitoramento + const alertHistory = await ctx.db.query('alertHistory').collect(); + for (const alert of alertHistory) { + await ctx.db.delete(alert._id); + } + console.log(` ✅ ${alertHistory.length} histórico de alertas removido`); - const alertConfigurations = await ctx.db - .query("alertConfigurations") - .collect(); - for (const alert of alertConfigurations) { - await ctx.db.delete(alert._id); - } - console.log( - ` ✅ ${alertConfigurations.length} configurações de alertas removidas` - ); + const alertConfigurations = await ctx.db.query('alertConfigurations').collect(); + for (const alert of alertConfigurations) { + await ctx.db.delete(alert._id); + } + console.log(` ✅ ${alertConfigurations.length} configurações de alertas removidas`); - const systemMetrics = await ctx.db.query("systemMetrics").collect(); - for (const metric of systemMetrics) { - await ctx.db.delete(metric._id); - } - console.log(` ✅ ${systemMetrics.length} métricas do sistema removidas`); + const systemMetrics = await ctx.db.query('systemMetrics').collect(); + for (const metric of systemMetrics) { + await ctx.db.delete(metric._id); + } + console.log(` ✅ ${systemMetrics.length} métricas do sistema removidas`); - // 13. Sessões - const sessoes = await ctx.db.query("sessoes").collect(); - for (const sessao of sessoes) { - await ctx.db.delete(sessao._id); - } - console.log(` ✅ ${sessoes.length} sessões removidas`); + // 13. Sessões + const sessoes = await ctx.db.query('sessoes').collect(); + for (const sessao of sessoes) { + await ctx.db.delete(sessao._id); + } + console.log(` ✅ ${sessoes.length} sessões removidas`); - // 14. Menu-permissões personalizadas (já está no código da internalMutation mas vazio) + // 14. Menu-permissões personalizadas (já está no código da internalMutation mas vazio) - // 15. Menu-permissões (já está no código da internalMutation mas vazio) + // 15. Menu-permissões (já está no código da internalMutation mas vazio) - // 16. Role-permissões - const rolePermissoes = await ctx.db.query("rolePermissoes").collect(); - for (const rp of rolePermissoes) { - await ctx.db.delete(rp._id); - } - console.log(` ✅ ${rolePermissoes.length} role-permissões removidas`); + // 16. Role-permissões + const rolePermissoes = await ctx.db.query('rolePermissoes').collect(); + for (const rp of rolePermissoes) { + await ctx.db.delete(rp._id); + } + console.log(` ✅ ${rolePermissoes.length} role-permissões removidas`); - // 17. Permissões - const permissoes = await ctx.db.query("permissoes").collect(); - for (const permissao of permissoes) { - await ctx.db.delete(permissao._id); - } - console.log(` ✅ ${permissoes.length} permissões removidas`); + // 17. Permissões + const permissoes = await ctx.db.query('permissoes').collect(); + for (const permissao of permissoes) { + await ctx.db.delete(permissao._id); + } + console.log(` ✅ ${permissoes.length} permissões removidas`); - // 18. Usuários (deve vir antes de roles se houver referência) - const usuarios = await ctx.db.query("usuarios").collect(); - for (const usuario of usuarios) { - await ctx.db.delete(usuario._id); - } - console.log(` ✅ ${usuarios.length} usuários removidos`); + // 18. Usuários (deve vir antes de roles se houver referência) + const usuarios = await ctx.db.query('usuarios').collect(); + for (const usuario of usuarios) { + await ctx.db.delete(usuario._id); + } + console.log(` ✅ ${usuarios.length} usuários removidos`); - // 19. Funcionários - const funcionarios = await ctx.db.query("funcionarios").collect(); - for (const funcionario of funcionarios) { - await ctx.db.delete(funcionario._id); - } - console.log(` ✅ ${funcionarios.length} funcionários removidos`); + // 19. Funcionários + const funcionarios = await ctx.db.query('funcionarios').collect(); + for (const funcionario of funcionarios) { + await ctx.db.delete(funcionario._id); + } + console.log(` ✅ ${funcionarios.length} funcionários removidos`); - // 20. Solicitações de acesso - const solicitacoesAcesso = await ctx.db - .query("solicitacoesAcesso") - .collect(); - for (const solicitacao of solicitacoesAcesso) { - await ctx.db.delete(solicitacao._id); - } - console.log( - ` ✅ ${solicitacoesAcesso.length} solicitações de acesso removidas` - ); + // 20. Solicitações de acesso + const solicitacoesAcesso = await ctx.db.query('solicitacoesAcesso').collect(); + for (const solicitacao of solicitacoesAcesso) { + await ctx.db.delete(solicitacao._id); + } + console.log(` ✅ ${solicitacoesAcesso.length} solicitações de acesso removidas`); - // 21. Símbolos - const simbolos = await ctx.db.query("simbolos").collect(); - for (const simbolo of simbolos) { - await ctx.db.delete(simbolo._id); - } - console.log(` ✅ ${simbolos.length} símbolos removidos`); + // 21. Símbolos + const simbolos = await ctx.db.query('simbolos').collect(); + for (const simbolo of simbolos) { + await ctx.db.delete(simbolo._id); + } + console.log(` ✅ ${simbolos.length} símbolos removidos`); - // 22. Roles (deve vir por último se outras tabelas referenciam) - const roles = await ctx.db.query("roles").collect(); - for (const role of roles) { - await ctx.db.delete(role._id); - } - console.log(` ✅ ${roles.length} roles removidas`); + // 22. Roles (deve vir por último se outras tabelas referenciam) + const roles = await ctx.db.query('roles').collect(); + for (const role of roles) { + await ctx.db.delete(role._id); + } + console.log(` ✅ ${roles.length} roles removidas`); - // 23. Todos (tabela de exemplo) - const todos = await ctx.db.query("todos").collect(); - for (const todo of todos) { - await ctx.db.delete(todo._id); - } - console.log(` ✅ ${todos.length} todos removidos`); + // 23. Todos (tabela de exemplo) + const todos = await ctx.db.query('todos').collect(); + for (const todo of todos) { + await ctx.db.delete(todo._id); + } + console.log(` ✅ ${todos.length} todos removidos`); - console.log("✨ Banco de dados completamente limpo!"); - return null; - }, + console.log('✨ Banco de dados completamente limpo!'); + return null; + } }); /** * Query para verificar quantos registros existem no banco */ export const verificarBanco = query({ - args: {}, - returns: v.object({ - usuarios: v.number(), - funcionarios: v.number(), - roles: v.number(), - simbolos: v.number(), - total: v.number(), - }), - handler: async (ctx) => { - const usuarios = await ctx.db.query("usuarios").collect(); - const funcionarios = await ctx.db.query("funcionarios").collect(); - const roles = await ctx.db.query("roles").collect(); - const simbolos = await ctx.db.query("simbolos").collect(); + args: {}, + returns: v.object({ + usuarios: v.number(), + funcionarios: v.number(), + roles: v.number(), + simbolos: v.number(), + total: v.number() + }), + handler: async (ctx) => { + const usuarios = await ctx.db.query('usuarios').collect(); + const funcionarios = await ctx.db.query('funcionarios').collect(); + const roles = await ctx.db.query('roles').collect(); + const simbolos = await ctx.db.query('simbolos').collect(); - return { - usuarios: usuarios.length, - funcionarios: funcionarios.length, - roles: roles.length, - simbolos: simbolos.length, - total: - usuarios.length + funcionarios.length + roles.length + simbolos.length, - }; - }, + return { + usuarios: usuarios.length, + funcionarios: funcionarios.length, + roles: roles.length, + simbolos: simbolos.length, + total: usuarios.length + funcionarios.length + roles.length + simbolos.length + }; + } }); From b503045b41d35d17885e6864f606ba5eb87a916c Mon Sep 17 00:00:00 2001 From: killer-cf Date: Fri, 14 Nov 2025 16:15:21 -0300 Subject: [PATCH 3/4] refactor: integrate ProtectedRoute component across dashboard pages - Added the ProtectedRoute component to various dashboard pages to enforce authentication and role-based access control. - Updated allowedRoles and maxLevel parameters for specific routes to align with the new permission management structure. - Enhanced user experience by ensuring consistent access checks across the application. --- .../src/lib/components/ProtectedRoute.svelte | 129 +++++++++--------- apps/web/src/routes/(dashboard)/+page.svelte | 3 + .../routes/(dashboard)/compras/+page.svelte | 3 + .../(dashboard)/comunicacao/+page.svelte | 3 + .../(dashboard)/controladoria/+page.svelte | 3 + .../(dashboard)/financeiro/+page.svelte | 3 + .../routes/(dashboard)/juridico/+page.svelte | 3 + .../(dashboard)/licitacoes/+page.svelte | 3 + .../routes/(dashboard)/perfil/+page.svelte | 3 + .../programas-esportivos/+page.svelte | 3 + .../routes/(dashboard)/ti/perfis/+page.svelte | 2 +- .../ti/personalizar-permissoes/+page.svelte | 2 +- .../ti/solicitacoes-acesso/+page.svelte | 2 +- .../routes/(dashboard)/ti/times/+page.svelte | 2 +- .../(dashboard)/ti/usuarios/+page.svelte | 2 +- 15 files changed, 95 insertions(+), 71 deletions(-) diff --git a/apps/web/src/lib/components/ProtectedRoute.svelte b/apps/web/src/lib/components/ProtectedRoute.svelte index e12eace..6bcf57a 100644 --- a/apps/web/src/lib/components/ProtectedRoute.svelte +++ b/apps/web/src/lib/components/ProtectedRoute.svelte @@ -1,80 +1,77 @@ {#if isChecking} -
-
- -

Verificando permissões...

-
-
+
+
+ +

Verificando permissões...

+
+
{:else if hasAccess} - {@render children()} + {@render children()} {/if} diff --git a/apps/web/src/routes/(dashboard)/+page.svelte b/apps/web/src/routes/(dashboard)/+page.svelte index 0c7070b..fa79b22 100644 --- a/apps/web/src/routes/(dashboard)/+page.svelte +++ b/apps/web/src/routes/(dashboard)/+page.svelte @@ -7,6 +7,7 @@ import { resolve } from "$app/paths"; import { UserPlus, Mail } from "lucide-svelte"; import { useAuth } from "@mmailaender/convex-better-auth-svelte/svelte"; + import ProtectedRoute from "$lib/components/ProtectedRoute.svelte"; let { data } = $props(); @@ -128,6 +129,7 @@ } +
{#if showAlert} @@ -823,6 +825,7 @@
{/if} +