Files
DeskcommCRM/app/actions/settings/updateModuloDaInstalacao.ts
T
melgarafaelandClaude Opus 5 a8ab2cf0bf feat(banco-externo): chave da instalação, desligada por padrão (doc 37)
O #1372 entrou como "sem conexão cadastrada nada acontece": a tela de
cadastrar banco externo aparecia para toda empresa e não havia chave da
instalação. O doc 37 decidiu "módulo opcional da instalação, desligado
por padrão", e o doc 24 manda todo liga/desliga ter tela de admin.

- lib/instalacao/modulos.ts: a chave mora em platform_config (0341),
  linha MODULO_BANCO_EXTERNO; só `ligado` liga, falha fechada. Não é
  coluna de platform_settings: criar a linha daquele singleton faria
  signup_mode nascer 'aberto' e vencer o SIGNUP_MODE do .env.
- /admin/sistema ganha o cartão "Módulos opcionais" (platform admin,
  auditado como platform.modulo_updated).
- Desligado: a porta some do menu/hub/⌘K (NavMetadata.modulo), a tela
  e as 8 rotas de /api/v1/external-db respondem 404, abrirAcesso recusa
  (é o ponto que as ferramentas do #1457 já usam), e capacidade com
  `modulo` no catálogo não é oferecida ao agente, ao MCP externo nem à
  tela de capacidades.
- 0384: instalação que já tinha conexão nasce LIGADA; `on conflict do
  nothing` para a reaplicação do baseline nunca reescrever a escolha.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019G7fFaatqXpzHA77xP9onS
2026-09-22 13:02:26 -03:00

65 lines
2.0 KiB
TypeScript

"use server";
import { headers } from "next/headers";
import { revalidatePath } from "next/cache";
import { z } from "zod";
import { audit } from "@/lib/audit";
import { requirePlatformAdmin } from "@/lib/auth/requirePlatformAdmin";
import {
MODULOS_OPCIONAIS,
gravarModulo,
moduloLigado,
} from "@/lib/instalacao/modulos";
import { createAdminClient } from "@/lib/supabase/admin";
export type UpdateModuloResult = { ok: true } | { ok: false; error: string };
const entradaSchema = z.object({
modulo: z.enum(MODULOS_OPCIONAIS),
ligado: z.boolean(),
});
/**
* Liga ou desliga um MÓDULO OPCIONAL da instalação (doc 37 para o banco
* externo; doc 24 para "todo liga/desliga tem tela").
*
* `is_platform_admin`, e não `admin` do tenant, pelo mesmo motivo de
* `updateComportamento.ts`: o módulo vale para TODAS as empresas do servidor, e
* abrir a porta de saída para o banco de outro sistema é decisão de quem
* responde pelo servidor.
*
* Auditado porque "desde quando as empresas podiam ligar um banco de fora?" não
* tem resposta em nenhuma outra tabela — a linha guarda o estado, não o
* histórico.
*/
export async function updateModuloDaInstalacao(
input: z.infer<typeof entradaSchema>,
): Promise<UpdateModuloResult> {
const { user } = await requirePlatformAdmin();
const parsed = entradaSchema.safeParse(input);
if (!parsed.success) return { ok: false, error: "invalid_input" };
const { modulo, ligado } = parsed.data;
const db = createAdminClient();
const antes = await moduloLigado(db, modulo);
if (!(await gravarModulo(db, modulo, ligado, user.id))) {
return { ok: false, error: "write_failed" };
}
const hdrs = await headers();
await audit({
action: "platform.modulo_updated",
actorUserId: user.id,
resourceType: "platform_config",
metadata: { modulo, de: antes, para: ligado },
requestId: hdrs.get("x-request-id"),
ip: hdrs.get("x-forwarded-for")?.split(",")[0]?.trim() ?? null,
userAgent: hdrs.get("user-agent"),
});
revalidatePath("/admin/sistema");
return { ok: true };
}