padronizacao: foundation Fase 0+0.5 — blueprints + auditoria + clinical_notes

Pre-MVP: 3 blueprints canonicos (repository, composable, quick-create
overlay), AUDIT_BASELINE com 51 divergencias em 6 modulos, estrategia
PADRONIZACAO de 4 fases, DESIGN_BILLING_ORCHESTRATOR. Schema clinical
notes pronto pra Fase B (4 migrations + seed templates). AgendaEvent
Dialog.vue.bak deletado (lixo de refator anterior).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-21 04:19:45 -03:00
parent 5b345c5598
commit f94a4ae97f
12 changed files with 2857 additions and 3522 deletions
@@ -0,0 +1,117 @@
-- ============================================================================
-- Trigger de versionamento automático de clinical_notes
-- ----------------------------------------------------------------------------
-- A cada INSERT ou UPDATE relevante em clinical_notes, cria snapshot completo
-- em clinical_note_versions. Função é SECURITY DEFINER pra bypassar a RLS
-- (que bloqueia INSERT direto em clinical_note_versions).
--
-- Versionamento dispara em:
-- • INSERT — registra criação (version_number = 1)
-- • UPDATE em content_text, content_structured ou title — registra edição
--
-- Mudanças em pinned/is_draft NÃO disparam versionamento (mudança de UI/state,
-- não de conteúdo).
-- ============================================================================
BEGIN;
CREATE OR REPLACE FUNCTION public.fn_clinical_note_version()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
next_version integer;
reason text;
BEGIN
SELECT COALESCE(MAX(version_number), 0) + 1
INTO next_version
FROM public.clinical_note_versions
WHERE note_id = NEW.id;
IF TG_OP = 'INSERT' THEN
reason := 'criacao';
ELSIF TG_OP = 'UPDATE' THEN
IF NEW.deleted_at IS NOT NULL AND OLD.deleted_at IS NULL THEN
reason := 'soft_delete';
ELSIF NEW.deleted_at IS NULL AND OLD.deleted_at IS NOT NULL THEN
reason := 'restore';
ELSE
reason := 'edicao';
END IF;
ELSE
reason := 'desconhecido';
END IF;
INSERT INTO public.clinical_note_versions (
note_id,
tenant_id,
version_number,
title,
content_text,
content_structured,
change_reason,
created_at,
created_by
) VALUES (
NEW.id,
NEW.tenant_id,
next_version,
NEW.title,
NEW.content_text,
NEW.content_structured,
reason,
now(),
COALESCE(NEW.updated_by, NEW.created_by)
);
RETURN NEW;
END;
$$;
COMMENT ON FUNCTION public.fn_clinical_note_version() IS
'Snapshot completo de clinical_notes a cada INSERT/UPDATE relevante. SECURITY DEFINER bypassa RLS pra escrever em clinical_note_versions (que bloqueia INSERT direto).';
CREATE TRIGGER trg_clinical_notes_version_insert
AFTER INSERT ON public.clinical_notes
FOR EACH ROW
EXECUTE FUNCTION public.fn_clinical_note_version();
CREATE TRIGGER trg_clinical_notes_version_update
AFTER UPDATE OF content_text, content_structured, title, deleted_at
ON public.clinical_notes
FOR EACH ROW
WHEN (
OLD.content_text IS DISTINCT FROM NEW.content_text
OR OLD.content_structured IS DISTINCT FROM NEW.content_structured
OR OLD.title IS DISTINCT FROM NEW.title
OR OLD.deleted_at IS DISTINCT FROM NEW.deleted_at
)
EXECUTE FUNCTION public.fn_clinical_note_version();
-- ──────────────────────────────────────────────────────────────────────────
-- Trigger para updated_at automático
-- ──────────────────────────────────────────────────────────────────────────
CREATE OR REPLACE FUNCTION public.fn_clinical_notes_updated_at()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW.updated_at := now();
RETURN NEW;
END;
$$;
CREATE TRIGGER trg_clinical_notes_updated_at
BEFORE UPDATE ON public.clinical_notes
FOR EACH ROW
EXECUTE FUNCTION public.fn_clinical_notes_updated_at();
CREATE TRIGGER trg_clinical_note_templates_updated_at
BEFORE UPDATE ON public.clinical_note_templates
FOR EACH ROW
EXECUTE FUNCTION public.fn_clinical_notes_updated_at();
COMMIT;