erp-clinicas-database-v2/init/03-clinical-tables.sql
rckrdmrd cf07a84e26 Migración desde erp-clinicas/database - Estándar multi-repo v2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 08:12:00 -06:00

629 lines
24 KiB
SQL

-- ============================================================================
-- TABLAS CLÍNICAS - ERP Clínicas
-- ============================================================================
-- Módulos: CL-001 (Pacientes), CL-002 (Citas), CL-003 (Expediente)
-- Versión: 1.0.0
-- Fecha: 2025-12-09
-- ============================================================================
-- PREREQUISITOS:
-- 1. ERP-Core instalado (auth.tenants, auth.users, core.partners)
-- 2. Schema clinica creado
-- ============================================================================
-- ============================================================================
-- TYPES (ENUMs)
-- ============================================================================
DO $$ BEGIN
CREATE TYPE clinica.appointment_status AS ENUM (
'scheduled', 'confirmed', 'in_progress', 'completed', 'cancelled', 'no_show'
);
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE clinica.patient_gender AS ENUM (
'male', 'female', 'other', 'prefer_not_to_say'
);
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE clinica.blood_type AS ENUM (
'A+', 'A-', 'B+', 'B-', 'AB+', 'AB-', 'O+', 'O-', 'unknown'
);
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE clinica.consultation_status AS ENUM (
'draft', 'in_progress', 'completed', 'cancelled'
);
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
-- ============================================================================
-- CATÁLOGOS BASE
-- ============================================================================
-- Tabla: specialties (Especialidades médicas)
CREATE TABLE IF NOT EXISTS clinica.specialties (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
code VARCHAR(20) NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
consultation_duration INTEGER DEFAULT 30, -- minutos
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id),
CONSTRAINT uq_specialties_code UNIQUE (tenant_id, code)
);
-- Tabla: doctors (Médicos - extiende hr.employees)
CREATE TABLE IF NOT EXISTS clinica.doctors (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
employee_id UUID, -- FK a hr.employees (ERP Core)
user_id UUID REFERENCES auth.users(id),
specialty_id UUID NOT NULL REFERENCES clinica.specialties(id),
license_number VARCHAR(50) NOT NULL, -- Cédula profesional
license_expiry DATE,
secondary_specialties UUID[], -- Array de specialty_ids
consultation_fee DECIMAL(12,2),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id),
deleted_at TIMESTAMPTZ,
deleted_by UUID REFERENCES auth.users(id),
CONSTRAINT uq_doctors_license UNIQUE (tenant_id, license_number)
);
-- ============================================================================
-- PACIENTES (CL-001)
-- ============================================================================
-- Tabla: patients (Pacientes - extiende core.partners)
CREATE TABLE IF NOT EXISTS clinica.patients (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
partner_id UUID REFERENCES core.partners(id), -- Vinculo a partner
-- Identificación
patient_number VARCHAR(30) NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
middle_name VARCHAR(100),
-- Datos personales
birth_date DATE,
gender clinica.patient_gender,
curp VARCHAR(18),
-- Contacto
email VARCHAR(255),
phone VARCHAR(20),
mobile VARCHAR(20),
-- Dirección
street VARCHAR(255),
city VARCHAR(100),
state VARCHAR(100),
zip_code VARCHAR(10),
country VARCHAR(100) DEFAULT 'México',
-- Datos médicos básicos
blood_type clinica.blood_type DEFAULT 'unknown',
allergies TEXT[],
chronic_conditions TEXT[],
-- Seguro médico
has_insurance BOOLEAN DEFAULT FALSE,
insurance_provider VARCHAR(100),
insurance_policy VARCHAR(50),
-- Control
is_active BOOLEAN NOT NULL DEFAULT TRUE,
last_visit_date DATE,
-- Auditoría
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id),
deleted_at TIMESTAMPTZ,
deleted_by UUID REFERENCES auth.users(id),
CONSTRAINT uq_patients_number UNIQUE (tenant_id, patient_number)
);
-- Tabla: patient_contacts (Contactos de emergencia)
CREATE TABLE IF NOT EXISTS clinica.patient_contacts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
patient_id UUID NOT NULL REFERENCES clinica.patients(id) ON DELETE CASCADE,
contact_name VARCHAR(200) NOT NULL,
relationship VARCHAR(50), -- Parentesco
phone VARCHAR(20),
mobile VARCHAR(20),
email VARCHAR(255),
is_primary BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id)
);
-- Tabla: patient_insurance (Información de seguros)
CREATE TABLE IF NOT EXISTS clinica.patient_insurance (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
patient_id UUID NOT NULL REFERENCES clinica.patients(id) ON DELETE CASCADE,
insurance_provider VARCHAR(100) NOT NULL,
policy_number VARCHAR(50) NOT NULL,
group_number VARCHAR(50),
holder_name VARCHAR(200),
holder_relationship VARCHAR(50),
coverage_type VARCHAR(50),
valid_from DATE,
valid_until DATE,
is_primary BOOLEAN DEFAULT TRUE,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id)
);
-- ============================================================================
-- CITAS (CL-002)
-- ============================================================================
-- Tabla: appointment_slots (Horarios disponibles)
CREATE TABLE IF NOT EXISTS clinica.appointment_slots (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
doctor_id UUID NOT NULL REFERENCES clinica.doctors(id),
day_of_week INTEGER NOT NULL CHECK (day_of_week BETWEEN 0 AND 6), -- 0=Domingo
start_time TIME NOT NULL,
end_time TIME NOT NULL,
slot_duration INTEGER DEFAULT 30, -- minutos
max_appointments INTEGER DEFAULT 1,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id),
CONSTRAINT chk_slot_times CHECK (end_time > start_time)
);
-- Tabla: appointments (Citas médicas)
CREATE TABLE IF NOT EXISTS clinica.appointments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
-- Referencias
patient_id UUID NOT NULL REFERENCES clinica.patients(id),
doctor_id UUID NOT NULL REFERENCES clinica.doctors(id),
specialty_id UUID REFERENCES clinica.specialties(id),
-- Programación
appointment_date DATE NOT NULL,
start_time TIME NOT NULL,
end_time TIME NOT NULL,
duration INTEGER DEFAULT 30, -- minutos
-- Estado
status clinica.appointment_status NOT NULL DEFAULT 'scheduled',
-- Detalles
reason TEXT, -- Motivo de consulta
notes TEXT,
is_first_visit BOOLEAN DEFAULT FALSE,
is_follow_up BOOLEAN DEFAULT FALSE,
follow_up_to UUID REFERENCES clinica.appointments(id),
-- Recordatorios
reminder_sent BOOLEAN DEFAULT FALSE,
reminder_sent_at TIMESTAMPTZ,
-- Confirmación
confirmed_at TIMESTAMPTZ,
confirmed_by UUID REFERENCES auth.users(id),
-- Cancelación
cancelled_at TIMESTAMPTZ,
cancelled_by UUID REFERENCES auth.users(id),
cancellation_reason TEXT,
-- Auditoría
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id),
CONSTRAINT chk_appointment_times CHECK (end_time > start_time)
);
-- ============================================================================
-- EXPEDIENTE CLÍNICO (CL-003)
-- ============================================================================
-- Tabla: medical_records (Expediente clínico electrónico)
-- NOTA: Datos sensibles según NOM-024-SSA3-2012
CREATE TABLE IF NOT EXISTS clinica.medical_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
patient_id UUID NOT NULL REFERENCES clinica.patients(id),
-- Número de expediente
record_number VARCHAR(30) NOT NULL,
-- Antecedentes
family_history TEXT,
personal_history TEXT,
surgical_history TEXT,
-- Hábitos
smoking_status VARCHAR(50),
alcohol_status VARCHAR(50),
exercise_status VARCHAR(50),
diet_notes TEXT,
-- Gineco-obstétricos (si aplica)
obstetric_history JSONB,
-- Notas generales
notes TEXT,
-- Control de acceso
is_confidential BOOLEAN DEFAULT TRUE,
access_restricted BOOLEAN DEFAULT FALSE,
-- Auditoría
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id),
CONSTRAINT uq_medical_records_number UNIQUE (tenant_id, record_number),
CONSTRAINT uq_medical_records_patient UNIQUE (patient_id)
);
-- Tabla: consultations (Consultas realizadas)
CREATE TABLE IF NOT EXISTS clinica.consultations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
-- Referencias
medical_record_id UUID NOT NULL REFERENCES clinica.medical_records(id),
appointment_id UUID REFERENCES clinica.appointments(id),
doctor_id UUID NOT NULL REFERENCES clinica.doctors(id),
-- Fecha/hora
consultation_date DATE NOT NULL,
start_time TIMESTAMPTZ,
end_time TIMESTAMPTZ,
-- Estado
status clinica.consultation_status DEFAULT 'draft',
-- Motivo de consulta
chief_complaint TEXT NOT NULL, -- Motivo principal
present_illness TEXT, -- Padecimiento actual
-- Exploración física
physical_exam JSONB, -- Estructurado por sistemas
-- Plan
treatment_plan TEXT,
follow_up_instructions TEXT,
next_appointment_days INTEGER,
-- Notas
notes TEXT,
private_notes TEXT, -- Solo visible para el médico
-- Auditoría
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id)
);
-- Tabla: vital_signs (Signos vitales)
CREATE TABLE IF NOT EXISTS clinica.vital_signs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
consultation_id UUID NOT NULL REFERENCES clinica.consultations(id) ON DELETE CASCADE,
-- Signos vitales
weight_kg DECIMAL(5,2),
height_cm DECIMAL(5,2),
bmi DECIMAL(4,2) GENERATED ALWAYS AS (
CASE WHEN height_cm > 0 THEN weight_kg / ((height_cm/100) * (height_cm/100)) END
) STORED,
temperature_c DECIMAL(4,2),
blood_pressure_systolic INTEGER,
blood_pressure_diastolic INTEGER,
heart_rate INTEGER, -- latidos por minuto
respiratory_rate INTEGER, -- respiraciones por minuto
oxygen_saturation INTEGER, -- porcentaje
-- Fecha/hora de medición
measured_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
measured_by UUID REFERENCES auth.users(id),
notes TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id)
);
-- Tabla: diagnoses (Diagnósticos - CIE-10)
CREATE TABLE IF NOT EXISTS clinica.diagnoses (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
consultation_id UUID NOT NULL REFERENCES clinica.consultations(id) ON DELETE CASCADE,
-- Código CIE-10
icd10_code VARCHAR(10) NOT NULL,
icd10_description VARCHAR(255),
-- Tipo
diagnosis_type VARCHAR(20) NOT NULL DEFAULT 'primary', -- primary, secondary, differential
-- Detalles
notes TEXT,
is_chronic BOOLEAN DEFAULT FALSE,
onset_date DATE,
-- Orden
sequence INTEGER DEFAULT 1,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id)
);
-- Tabla: prescriptions (Recetas médicas)
CREATE TABLE IF NOT EXISTS clinica.prescriptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
consultation_id UUID NOT NULL REFERENCES clinica.consultations(id),
-- Número de receta
prescription_number VARCHAR(30) NOT NULL,
prescription_date DATE NOT NULL DEFAULT CURRENT_DATE,
-- Médico
doctor_id UUID NOT NULL REFERENCES clinica.doctors(id),
-- Instrucciones generales
general_instructions TEXT,
-- Vigencia
valid_until DATE,
-- Estado
is_printed BOOLEAN DEFAULT FALSE,
printed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
updated_at TIMESTAMPTZ,
updated_by UUID REFERENCES auth.users(id),
CONSTRAINT uq_prescriptions_number UNIQUE (tenant_id, prescription_number)
);
-- Tabla: prescription_items (Líneas de receta)
CREATE TABLE IF NOT EXISTS clinica.prescription_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
prescription_id UUID NOT NULL REFERENCES clinica.prescriptions(id) ON DELETE CASCADE,
-- Medicamento
product_id UUID, -- FK a inventory.products (ERP Core)
medication_name VARCHAR(255) NOT NULL,
presentation VARCHAR(100), -- Tabletas, jarabe, etc.
-- Dosificación
dosage VARCHAR(100) NOT NULL, -- "1 tableta"
frequency VARCHAR(100) NOT NULL, -- "cada 8 horas"
duration VARCHAR(100), -- "por 7 días"
quantity INTEGER, -- Cantidad a surtir
-- Instrucciones
instructions TEXT,
-- Orden
sequence INTEGER DEFAULT 1,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id)
);
-- ============================================================================
-- ÍNDICES
-- ============================================================================
-- Specialties
CREATE INDEX IF NOT EXISTS idx_specialties_tenant ON clinica.specialties(tenant_id);
-- Doctors
CREATE INDEX IF NOT EXISTS idx_doctors_tenant ON clinica.doctors(tenant_id);
CREATE INDEX IF NOT EXISTS idx_doctors_specialty ON clinica.doctors(specialty_id);
CREATE INDEX IF NOT EXISTS idx_doctors_user ON clinica.doctors(user_id);
-- Patients
CREATE INDEX IF NOT EXISTS idx_patients_tenant ON clinica.patients(tenant_id);
CREATE INDEX IF NOT EXISTS idx_patients_partner ON clinica.patients(partner_id);
CREATE INDEX IF NOT EXISTS idx_patients_name ON clinica.patients(last_name, first_name);
CREATE INDEX IF NOT EXISTS idx_patients_curp ON clinica.patients(curp);
-- Patient contacts
CREATE INDEX IF NOT EXISTS idx_patient_contacts_tenant ON clinica.patient_contacts(tenant_id);
CREATE INDEX IF NOT EXISTS idx_patient_contacts_patient ON clinica.patient_contacts(patient_id);
-- Patient insurance
CREATE INDEX IF NOT EXISTS idx_patient_insurance_tenant ON clinica.patient_insurance(tenant_id);
CREATE INDEX IF NOT EXISTS idx_patient_insurance_patient ON clinica.patient_insurance(patient_id);
-- Appointment slots
CREATE INDEX IF NOT EXISTS idx_appointment_slots_tenant ON clinica.appointment_slots(tenant_id);
CREATE INDEX IF NOT EXISTS idx_appointment_slots_doctor ON clinica.appointment_slots(doctor_id);
-- Appointments
CREATE INDEX IF NOT EXISTS idx_appointments_tenant ON clinica.appointments(tenant_id);
CREATE INDEX IF NOT EXISTS idx_appointments_patient ON clinica.appointments(patient_id);
CREATE INDEX IF NOT EXISTS idx_appointments_doctor ON clinica.appointments(doctor_id);
CREATE INDEX IF NOT EXISTS idx_appointments_date ON clinica.appointments(appointment_date);
CREATE INDEX IF NOT EXISTS idx_appointments_status ON clinica.appointments(status);
-- Medical records
CREATE INDEX IF NOT EXISTS idx_medical_records_tenant ON clinica.medical_records(tenant_id);
CREATE INDEX IF NOT EXISTS idx_medical_records_patient ON clinica.medical_records(patient_id);
-- Consultations
CREATE INDEX IF NOT EXISTS idx_consultations_tenant ON clinica.consultations(tenant_id);
CREATE INDEX IF NOT EXISTS idx_consultations_record ON clinica.consultations(medical_record_id);
CREATE INDEX IF NOT EXISTS idx_consultations_doctor ON clinica.consultations(doctor_id);
CREATE INDEX IF NOT EXISTS idx_consultations_date ON clinica.consultations(consultation_date);
-- Vital signs
CREATE INDEX IF NOT EXISTS idx_vital_signs_tenant ON clinica.vital_signs(tenant_id);
CREATE INDEX IF NOT EXISTS idx_vital_signs_consultation ON clinica.vital_signs(consultation_id);
-- Diagnoses
CREATE INDEX IF NOT EXISTS idx_diagnoses_tenant ON clinica.diagnoses(tenant_id);
CREATE INDEX IF NOT EXISTS idx_diagnoses_consultation ON clinica.diagnoses(consultation_id);
CREATE INDEX IF NOT EXISTS idx_diagnoses_icd10 ON clinica.diagnoses(icd10_code);
-- Prescriptions
CREATE INDEX IF NOT EXISTS idx_prescriptions_tenant ON clinica.prescriptions(tenant_id);
CREATE INDEX IF NOT EXISTS idx_prescriptions_consultation ON clinica.prescriptions(consultation_id);
-- Prescription items
CREATE INDEX IF NOT EXISTS idx_prescription_items_tenant ON clinica.prescription_items(tenant_id);
CREATE INDEX IF NOT EXISTS idx_prescription_items_prescription ON clinica.prescription_items(prescription_id);
-- ============================================================================
-- ROW LEVEL SECURITY
-- ============================================================================
ALTER TABLE clinica.specialties ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.doctors ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.patients ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.patient_contacts ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.patient_insurance ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.appointment_slots ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.appointments ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.medical_records ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.consultations ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.vital_signs ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.diagnoses ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.prescriptions ENABLE ROW LEVEL SECURITY;
ALTER TABLE clinica.prescription_items ENABLE ROW LEVEL SECURITY;
-- Políticas de aislamiento por tenant
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_specialties ON clinica.specialties;
CREATE POLICY tenant_isolation_specialties ON clinica.specialties
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_doctors ON clinica.doctors;
CREATE POLICY tenant_isolation_doctors ON clinica.doctors
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_patients ON clinica.patients;
CREATE POLICY tenant_isolation_patients ON clinica.patients
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_patient_contacts ON clinica.patient_contacts;
CREATE POLICY tenant_isolation_patient_contacts ON clinica.patient_contacts
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_patient_insurance ON clinica.patient_insurance;
CREATE POLICY tenant_isolation_patient_insurance ON clinica.patient_insurance
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_appointment_slots ON clinica.appointment_slots;
CREATE POLICY tenant_isolation_appointment_slots ON clinica.appointment_slots
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_appointments ON clinica.appointments;
CREATE POLICY tenant_isolation_appointments ON clinica.appointments
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_medical_records ON clinica.medical_records;
CREATE POLICY tenant_isolation_medical_records ON clinica.medical_records
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_consultations ON clinica.consultations;
CREATE POLICY tenant_isolation_consultations ON clinica.consultations
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_vital_signs ON clinica.vital_signs;
CREATE POLICY tenant_isolation_vital_signs ON clinica.vital_signs
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_diagnoses ON clinica.diagnoses;
CREATE POLICY tenant_isolation_diagnoses ON clinica.diagnoses
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_prescriptions ON clinica.prescriptions;
CREATE POLICY tenant_isolation_prescriptions ON clinica.prescriptions
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
DO $$ BEGIN
DROP POLICY IF EXISTS tenant_isolation_prescription_items ON clinica.prescription_items;
CREATE POLICY tenant_isolation_prescription_items ON clinica.prescription_items
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
EXCEPTION WHEN undefined_object THEN NULL; END $$;
-- ============================================================================
-- COMENTARIOS
-- ============================================================================
COMMENT ON TABLE clinica.specialties IS 'Catálogo de especialidades médicas';
COMMENT ON TABLE clinica.doctors IS 'Médicos y especialistas - extiende hr.employees';
COMMENT ON TABLE clinica.patients IS 'Registro de pacientes - extiende core.partners';
COMMENT ON TABLE clinica.patient_contacts IS 'Contactos de emergencia del paciente';
COMMENT ON TABLE clinica.patient_insurance IS 'Información de seguros médicos';
COMMENT ON TABLE clinica.appointment_slots IS 'Horarios disponibles por médico';
COMMENT ON TABLE clinica.appointments IS 'Citas médicas programadas';
COMMENT ON TABLE clinica.medical_records IS 'Expediente clínico electrónico (NOM-024-SSA3)';
COMMENT ON TABLE clinica.consultations IS 'Consultas médicas realizadas';
COMMENT ON TABLE clinica.vital_signs IS 'Signos vitales del paciente';
COMMENT ON TABLE clinica.diagnoses IS 'Diagnósticos según CIE-10';
COMMENT ON TABLE clinica.prescriptions IS 'Recetas médicas';
COMMENT ON TABLE clinica.prescription_items IS 'Medicamentos en receta';
-- ============================================================================
-- FIN TABLAS CLÍNICAS
-- Total: 13 tablas, 4 ENUMs
-- ============================================================================