ROADMAP Fase 1.2 (Compliance basico BR). Item #5: profiles ganha 3 colunas (professional_registration_type/number/uf) com CHECK constraint dos conselhos comuns (CRP, CRM, CRFa, CREFITO, CRESS, CRN, RMS, outro). Item #9: catalogo public.specialties + join M:N profile_specialties + RLS. Seed seed_050 popula 33 especialidades is_system=true (clinica, jurídica, neuropsicologia, ABA, TCC, psicanalise etc). Service specialtiesService.js no src/services pra consumo na UI. Item #8 (nome social) ja estava integrado. #6 (consent forms UI) e #7 (assinatura no portal) adiados — schemas document_templates e document_signatures existem, falta workflow UI dedicado. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
-- ============================================================================
|
||||
-- Compliance CFP — Tipo de registro profissional (ROADMAP item #5)
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Adiciona campos de registro profissional ao perfil. Necessário pra emissão
|
||||
-- de recibos/laudos válidos (CFP exige tipo, número e UF do conselho).
|
||||
--
|
||||
-- Conselhos comuns no Brasil:
|
||||
-- CRP — Psicólogo
|
||||
-- CRM — Médico
|
||||
-- CRFa — Fonoaudiólogo
|
||||
-- CREFITO — Fisioterapeuta / Terapeuta Ocupacional
|
||||
-- CRESS — Assistente Social
|
||||
-- CRN — Nutricionista
|
||||
-- RMS — Residência Multiprofissional (Saúde)
|
||||
-- outro — Catch-all (campo livre na UI)
|
||||
-- ============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE public.profiles
|
||||
ADD COLUMN IF NOT EXISTS professional_registration_type text,
|
||||
ADD COLUMN IF NOT EXISTS professional_registration_number text,
|
||||
ADD COLUMN IF NOT EXISTS professional_registration_uf text;
|
||||
|
||||
-- CHECK não pode ser ADD IF NOT EXISTS — guard com DO block
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint
|
||||
WHERE conname = 'profiles_registration_type_check'
|
||||
) THEN
|
||||
ALTER TABLE public.profiles
|
||||
ADD CONSTRAINT profiles_registration_type_check CHECK (
|
||||
professional_registration_type IS NULL
|
||||
OR professional_registration_type = ANY (ARRAY[
|
||||
'CRP',
|
||||
'CRM',
|
||||
'CRFa',
|
||||
'CREFITO',
|
||||
'CRESS',
|
||||
'CRN',
|
||||
'RMS',
|
||||
'outro'
|
||||
])
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- UF check (regex pra 2 chars uppercase ou NULL)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint
|
||||
WHERE conname = 'profiles_registration_uf_check'
|
||||
) THEN
|
||||
ALTER TABLE public.profiles
|
||||
ADD CONSTRAINT profiles_registration_uf_check CHECK (
|
||||
professional_registration_uf IS NULL
|
||||
OR professional_registration_uf ~ '^[A-Z]{2}$'
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
COMMENT ON COLUMN public.profiles.professional_registration_type IS
|
||||
'Tipo de registro profissional. Obrigatório pra emitir recibos/laudos. ROADMAP item #5.';
|
||||
COMMENT ON COLUMN public.profiles.professional_registration_number IS
|
||||
'Número do registro (ex: 06/12345 ou 123456). Formato livre — UI ajuda com mask se relevante.';
|
||||
COMMENT ON COLUMN public.profiles.professional_registration_uf IS
|
||||
'UF do conselho (2 chars uppercase). Alguns conselhos exigem regionalização (CRP 06/SP, CRP 03/BA).';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,79 @@
|
||||
-- ============================================================================
|
||||
-- Compliance CFP — Especialidades do profissional (ROADMAP item #9)
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Catálogo de especialidades/abordagens + join many-to-many com profiles.
|
||||
-- Profissional pode ter múltiplas especialidades (clínica + jurídica, etc).
|
||||
-- ============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.specialties (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
key text UNIQUE NOT NULL,
|
||||
name text NOT NULL,
|
||||
category text,
|
||||
is_system boolean DEFAULT false NOT NULL,
|
||||
active boolean DEFAULT true NOT NULL,
|
||||
created_at timestamptz DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON TABLE public.specialties IS
|
||||
'Catálogo global de especialidades/abordagens psicológicas (ROADMAP item #9). is_system=true pra entries seedadas.';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_specialties_active ON public.specialties (active, category, name);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.profile_specialties (
|
||||
profile_id uuid NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
|
||||
specialty_id uuid NOT NULL REFERENCES public.specialties(id) ON DELETE RESTRICT,
|
||||
other_label text,
|
||||
created_at timestamptz DEFAULT now() NOT NULL,
|
||||
PRIMARY KEY (profile_id, specialty_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE public.profile_specialties IS
|
||||
'M:N entre profile e specialty. other_label preenchido só quando specialty.key=outra (custom user-defined).';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_profile_specialties_profile ON public.profile_specialties (profile_id);
|
||||
|
||||
-- ──────────────────────────────────────────────────────────────────────────
|
||||
-- RLS
|
||||
-- ──────────────────────────────────────────────────────────────────────────
|
||||
|
||||
ALTER TABLE public.specialties ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.profile_specialties ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- specialties: read-only pra todos authenticated (catálogo público); só saas_admin escreve
|
||||
CREATE POLICY specialties_authenticated_read
|
||||
ON public.specialties FOR SELECT TO authenticated
|
||||
USING (active = true);
|
||||
|
||||
CREATE POLICY specialties_saas_admin_write
|
||||
ON public.specialties TO authenticated
|
||||
USING (public.is_saas_admin())
|
||||
WITH CHECK (public.is_saas_admin());
|
||||
|
||||
-- profile_specialties: cada user gerencia o próprio
|
||||
CREATE POLICY profile_specialties_owner_select
|
||||
ON public.profile_specialties FOR SELECT TO authenticated
|
||||
USING (profile_id = auth.uid());
|
||||
|
||||
CREATE POLICY profile_specialties_owner_insert
|
||||
ON public.profile_specialties FOR INSERT TO authenticated
|
||||
WITH CHECK (profile_id = auth.uid());
|
||||
|
||||
CREATE POLICY profile_specialties_owner_delete
|
||||
ON public.profile_specialties FOR DELETE TO authenticated
|
||||
USING (profile_id = auth.uid());
|
||||
|
||||
-- Tenant_admin pode VER specialties dos membros (pra cards públicos / perfil clínica)
|
||||
CREATE POLICY profile_specialties_tenant_admin_read
|
||||
ON public.profile_specialties FOR SELECT TO authenticated
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.tenant_members tm
|
||||
WHERE tm.user_id = profile_specialties.profile_id
|
||||
AND public.is_tenant_admin(tm.tenant_id)
|
||||
)
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user