PRIMARY primary key
FK declared foreign key
REF logical reference (no constraint)
UNIQUE unique (* = composite)
INDEX indexed
JSON longtext + json_valid()
Tabla central de identidad. Almacena credenciales (password_hash), token de sesión (login_token), rol principal (role_id), subrol opcional (subrole_id), idioma de interfaz (es / en) y estado de la cuenta. Todo perfil (client, provider, company) cuelga de un users.id.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| email | varchar(255) | NO | None | UNIQUE | Correo de acceso (login). Único. |
| password_hash | varchar(255) | NO | None | - | Hash seguro de contraseña generado con password_hash(). |
| login_token | varchar(100) | YES | NULL | UNIQUE | Token de persistencia de sesión. Único. |
| role_id | int(11) | NO | None | FK | Rol principal (admin, company, provider, client). |
| name | varchar(255) | YES | NULL | - | Nombre completo o razón social de la cuenta. |
| is_active | tinyint(1) | YES | 1 | - | Flag de registro activo (1 = activo, 0 = inactivo). |
| lang_pref | enum('es','en') | YES | 'es' | - | Idioma de la interfaz del usuario. Valores: es, en. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
| subrole_id | int(11) | YES | NULL | FK | Subrol administrativo opcional (ej. Clinical Lead). |
🔗 Foreign Key Constraints
⚡ Indexes
email(email)UNIQUE
login_token(login_token)UNIQUE
role_id(role_id)INDEX
idx_users_subrole(subrole_id)INDEX
Catálogo maestro de roles de acceso (admin, company, provider, client). Es el padre de users y de subroles.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| name | varchar(50) | NO | None | UNIQUE | Nombre único del rol. |
Subperfiles administrativos finos (ej. Clinical Lead) asociados a un rol base. Se identifican por slug único y se activan/desactivan con is_active.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| role_id | int(11) | NO | None | FK | Rol base al que pertenece el subrol. |
| name | varchar(100) | NO | None | - | Nombre visible del subrol. |
| slug | varchar(100) | NO | None | UNIQUE | Identificador único del subrol. |
| description | text | YES | NULL | - | Descripción. |
| is_active | tinyint(1) | YES | 1 | - | Flag de registro activo (1 = activo, 0 = inactivo). |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🔗 Foreign Key Constraints
⚡ Indexes
slug(slug)UNIQUE
idx_subroles_role(role_id)INDEX
Permisos granulares asignados a cada subrol (ej. PERM_ADMIN_CL_MESSAGES_READ). Clave única compuesta (subrole_id, permission) evita duplicados; se borra en cascada con el subrol.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| subrole_id | int(11) | NO | None | FK UNIQUE* | Subrol al que se concede el permiso. |
| permission | varchar(150) | NO | None | UNIQUE* | Clave del permiso (ej. PERM_ADMIN_CL_MESSAGES_READ). |
🔗 Foreign Key Constraints
⚡ Indexes
uq_subrole_perm(subrole_id, permission)UNIQUE
idx_subrole_permissions_subrole(subrole_id)INDEX
Registro de auditoría RGPD/GDPR: cada aceptación o rechazo de política de privacidad, tratamiento de datos o cookies queda con IP y User-Agent.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| user_id | int(11) | NO | None | FK | Cuenta de usuario asociada. |
| consent_type | enum('privacy_policy','data_processing','cookies') | NO | None | - | Tipo de consentimiento registrado. Valores: privacy_policy, data_processing, cookies. |
| accepted | tinyint(1) | NO | None | - | 1 = aceptado, 0 = rechazado. |
| ip_address | varchar(45) | YES | NULL | - | IP del usuario al consentir (IPv4/IPv6). |
| user_agent | text | YES | NULL | - | Navegador / dispositivo del usuario. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🔗 Foreign Key Constraints
Lista de correos pre-autorizados (allowlist) para onboarding de especialistas y administradores de empresa. Guarda rol, empresa, clasificación del proveedor, cuota de sesiones, token de invitación único y su ciclo de vida (pending → registered / revoked / expired).
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| email | varchar(255) | NO | None | INDEX | Correo autorizado a registrarse. |
| role_id | int(11) | NO | None | REF | Rol que obtendrá el usuario al registrarse. |
| company_id | int(11) | YES | NULL | REF INDEX | Empresa asociada (para administradores de empresa). |
| provider_classification | enum('counsellor','coach','unassigned') | YES | 'unassigned' | - | Clasificación preasignada del especialista. Valores: counsellor, coach, unassigned. |
| token | varchar(64) | NO | None | UNIQUE INDEX | Token único de invitación. |
| status | enum('pending','registered','revoked','expired') | YES | 'pending' | - | Ciclo de vida de la invitación. Valores: pending, registered, revoked, expired. |
| sessions_quota | int(11) | YES | 8 | - | Cuota de sesiones inicial asignada. |
| notes | text | YES | NULL | - | Notas internas u observaciones. |
| created_by_user_id | int(11) | YES | NULL | REF | Administrador que generó la invitación. |
| registered_user_id | int(11) | YES | NULL | REF | Usuario creado al completar el registro. |
| registered_at | datetime | YES | NULL | - | Fecha en que se completó el registro. |
| expires_at | datetime | YES | NULL | - | Fecha de caducidad de la invitación. |
| created_at | timestamp | YES | current_timestamp() | - | Fecha y hora de creación del registro. |
🧭 Logical References (enforced by application)
created_by_user_id ➔ users(id)NO FK CONSTRAINT registered_user_id ➔ users(id)NO FK CONSTRAINT
⚡ Indexes
token(token)UNIQUE
idx_preauth_email_role(email, role_id, status)INDEX
idx_preauth_token(token)INDEX
idx_preauth_company(company_id)INDEX
Cuentas corporativas (B2B). Incluye código de empresa, dominios de correo permitidos, contrato, cuota de sesiones por miembro, plan de facturación, gestor de cuenta (account manager) y visibilidad de facturación para HR.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| user_id | int(11) | NO | None | FK UNIQUE | Cuenta de usuario titular de la empresa. Única. |
| name | varchar(255) | NO | None | - | Razón social. |
| code | varchar(50) | YES | NULL | UNIQUE INDEX | Código corporativo único. |
| allowed_domains | varchar(500) | YES | NULL | - | Dominios de correo permitidos para el registro de empleados. |
| contact_name | varchar(255) | YES | NULL | - | Persona de contacto corporativa. |
| contact_email | varchar(255) | YES | NULL | - | Correo de contacto corporativo. |
| phone | varchar(50) | YES | NULL | - | Teléfono de contacto. |
| industry | varchar(100) | YES | NULL | - | Sector / industria. |
| country | varchar(100) | YES | NULL | - | País. |
| sessions_per_member | int(11) | YES | 8 | - | Cuota de sesiones por miembro. |
| total_members_enrolled | int(11) | YES | 0 | - | Total de miembros inscritos. |
| contract_start | date | YES | NULL | - | Inicio del contrato. |
| contract_end | date | YES | NULL | - | Fin del contrato. |
| is_active | tinyint(1) | YES | 1 | - | Cuenta corporativa activa. |
| account_manager_name | varchar(150) | YES | 'David Doyle' | - | Nombre del gestor de cuenta de MHC. |
| account_manager_email | varchar(255) | YES | 'david@mentalhealthchange.ie' | - | Correo del gestor de cuenta de MHC. |
| account_manager_user_id | int(11) | YES | NULL | REF | Usuario administrador que actúa como gestor de cuenta. |
| plan_type | enum('pay_as_you_go','monthly','yearly') | YES | 'monthly' | - | Modalidad de facturación del plan. Valores: pay_as_you_go, monthly, yearly. |
| show_billing_to_company | tinyint(1) | YES | 0 | - | 1 = HR puede ver la facturación. |
🔗 Foreign Key Constraints
🧭 Logical References (enforced by application)
account_manager_user_id ➔ users(id)NO FK CONSTRAINT
⚡ Indexes
user_id(user_id)UNIQUE
code(code)UNIQUE
idx_companies_code(code)INDEX
Administradores de una empresa (varios por empresa). Define nivel (owner, hr_admin, manager, employee), acceso por departamento, permisos de reportes/facturación/equipo/recursos y estado de aprobación. Clave única (company_id, user_id).
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| company_id | int(11) | NO | None | REF UNIQUE* INDEX | Empresa asociada. |
| user_id | int(11) | NO | None | REF UNIQUE* INDEX | Cuenta de usuario asociada. |
| admin_level | enum('owner','hr_admin','manager','employee') | NO | 'hr_admin' | - | Nivel jerárquico dentro de la empresa. Valores: owner, hr_admin, manager, employee. |
| department_access | varchar(255) | YES | NULL | - | Departamentos accesibles (lista separada por comas). |
| can_view_reports | tinyint(1) | NO | 1 | - | Permiso: ver reportes agregados. |
| can_manage_billing | tinyint(1) | NO | 0 | - | Permiso: gestionar facturación. |
| can_manage_team | tinyint(1) | NO | 1 | - | Permiso: gestionar equipo. |
| can_access_resources | tinyint(1) | NO | 1 | - | Permiso: acceder a recursos del Hub. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
| status | enum('pending_approval','approved') | NO | 'approved' | - | Estado de aprobación del administrador. Valores: pending_approval, approved. |
🧭 Logical References (enforced by application)
⚡ Indexes
uq_comp_user(company_id, user_id)UNIQUE
idx_ca_company(company_id)INDEX
idx_ca_user(user_id)INDEX
Solicitudes de acceso como administrador de empresa. Flujo pending → approved / rejected con trazabilidad de quién y cuándo aprobó.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| user_id | int(11) | NO | None | REF INDEX | Cuenta de usuario asociada. |
| company_id | int(11) | NO | None | REF INDEX | Empresa asociada. |
| requester_email | varchar(255) | NO | None | - | Correo del solicitante. |
| requester_name | varchar(255) | NO | None | - | Nombre del solicitante. |
| status | enum('pending','approved','rejected') | NO | 'pending' | INDEX | Estado de la solicitud. Valores: pending, approved, rejected. |
| requested_at | timestamp | NO | current_timestamp() | - | Fecha de la solicitud. |
| approved_by | int(11) | YES | NULL | REF | Usuario que resolvió la solicitud. |
| approved_at | timestamp | YES | NULL | - | Fecha de resolución. |
| notes | text | YES | NULL | - | Notas internas u observaciones. |
🧭 Logical References (enforced by application)
⚡ Indexes
idx_req_user(user_id)INDEX
idx_req_company(company_id)INDEX
idx_req_status(status)INDEX
Departamentos internos de cada empresa. Permite segmentar miembros (clients.department_id) y limitar el acceso de managers por departamento.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| company_id | int(11) | NO | None | REF INDEX | Empresa asociada. |
| name | varchar(150) | NO | None | - | Nombre del departamento. |
| code | varchar(50) | YES | NULL | - | Código interno del departamento. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🧭 Logical References (enforced by application)
⚡ Indexes
idx_dept_company(company_id)INDEX
Configuración de beneficios por empresa (1:1): proveedor EAP, aseguradora, número de póliza, enlace a la guía de beneficios, cupos de terapia y coaching, instrucciones personalizadas y soporte de dependientes.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| company_id | int(11) | NO | None | REF UNIQUE | Empresa asociada. |
| eap_provider_name | varchar(150) | YES | 'Mental Health Change Global EAP' | - | Programa EAP contratado. |
| insurance_partner | varchar(150) | YES | 'Irish Life Health / VHI / Laya Healthcare' | - | Aseguradora(s) asociada(s). |
| policy_number | varchar(100) | YES | NULL | - | Número de póliza. |
| custom_instructions | text | YES | NULL | - | Instrucciones personalizadas para los miembros. |
| is_active | tinyint(1) | NO | 1 | - | Flag de registro activo (1 = activo, 0 = inactivo). |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
| benefits_link_url | varchar(255) | YES | 'https://mentalhealthchange.ie/benefits-guide' | - | Enlace a la guía de beneficios. |
| therapy_session_allowance | int(11) | YES | 8 | - | Sesiones de terapia permitidas por miembro. |
| coaching_session_allowance | int(11) | YES | 8 | - | Sesiones de coaching permitidas por miembro. |
| dependents_enabled | tinyint(1) | YES | 0 | - | 1 = cobertura de dependientes habilitada. |
🧭 Logical References (enforced by application)
⚡ Indexes
uq_ben_company(company_id)UNIQUE
Tokens de invitación corporativa de un solo enlace para que los empleados se registren vinculados a su empresa. Se pueden desactivar con is_active.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| company_id | int(11) | NO | None | FK | Empresa asociada. |
| token | varchar(64) | NO | None | UNIQUE INDEX | Token de registro único. |
| is_active | tinyint(1) | YES | 1 | - | Invitación vigente. |
| created_by | int(11) | NO | None | FK | Usuario que creó el registro. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🔗 Foreign Key Constraints
⚡ Indexes
token(token)UNIQUE
company_id(company_id)INDEX
created_by(created_by)INDEX
idx_comp_inv_token(token, is_active)INDEX
Perfil del miembro (empleado). Contiene datos personales, empresa, departamento, ubicación, proveedor asignado, preferencias de servicio, temas, nivel de triaje (wellbeing / clinical / crisis_risk), bandera de riesgo, contacto de emergencia, médico de cabecera y control de cupo de sesiones (total_sessions_allowed, sessions_used).
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| user_id | int(11) | NO | None | FK UNIQUE | Cuenta de usuario del miembro. Única (relación 1:1). |
| provider_id | int(11) | YES | NULL | FK | Especialista asignado (NULL hasta el matching). |
| company_id | int(11) | NO | None | FK | Empresa empleadora del miembro. |
| name | varchar(255) | NO | None | - | Nombre completo visible. |
| first_name | varchar(100) | YES | NULL | - | Nombre de pila. |
| last_name | varchar(100) | YES | NULL | - | Apellidos. |
| dob | date | YES | NULL | - | Fecha de nacimiento. |
| employer_email | varchar(255) | YES | NULL | INDEX | Correo corporativo (verificación de dominio). |
| contact_email | varchar(255) | YES | NULL | - | Correo personal de contacto. |
| email_changed | tinyint(1) | YES | 0 | - | 1 = el miembro modificó su correo de contacto. |
| type | enum('corporate') | NO | 'corporate' | - | Tipo de miembro. Valores: corporate. |
| service_preference | enum('coaching','counselling','both') | YES | NULL | - | Servicio preferido. Valores: coaching, counselling, both. |
| primary_topic | varchar(100) | YES | NULL | - | Tema principal de bienestar. |
| secondary_topics | longtext JSON | YES | NULL | - | Temas secundarios (JSON). |
| triage_level | enum('wellbeing','clinical','crisis_risk') | YES | 'wellbeing' | - | Nivel de triaje clínico actual. Valores: wellbeing, clinical, crisis_risk. |
| crisis_risk_flag | tinyint(1) | YES | 0 | INDEX | 1 = marcado con riesgo de crisis. |
| status | enum('new_match','active','engaged','inactive') | YES | 'new_match' | INDEX | Estado del miembro en el programa. Valores: new_match, active, engaged, inactive. |
| phone | varchar(50) | YES | NULL | - | Teléfono de contacto. |
| city | varchar(100) | YES | NULL | - | Ciudad. |
| address | varchar(255) | YES | NULL | - | Dirección postal. |
| country | varchar(100) | YES | NULL | - | País. |
| total_sessions_allowed | int(11) | YES | 8 | - | Cupo total de sesiones. |
| sessions_used | int(11) | YES | 0 | - | Sesiones consumidas. |
| start_date | date | YES | NULL | - | Inicio del beneficio. |
| renewal_date | date | YES | NULL | - | Fecha de renovación del cupo. |
| notes | text | YES | NULL | - | Notas internas u observaciones. |
| next_of_kin_name | varchar(255) | YES | NULL | - | Contacto de emergencia: nombre. |
| next_of_kin_phone | varchar(50) | YES | NULL | - | Contacto de emergencia: teléfono. |
| gp_name | varchar(255) | YES | NULL | - | Médico de cabecera (GP): nombre. |
| gp_phone | varchar(50) | YES | NULL | - | Médico de cabecera (GP): teléfono. |
| intake_completed | tinyint(1) | YES | 0 | - | 1 = intake completado. |
| department_id | int(11) | YES | NULL | REF | Departamento del miembro (company_departments). |
| office_location | varchar(100) | YES | 'Dublin HQ' | - | Oficina / sede del miembro. |
🔗 Foreign Key Constraints
🧭 Logical References (enforced by application)
⚡ Indexes
user_id(user_id)UNIQUE
idx_clients_provider(provider_id)INDEX
idx_clients_company(company_id)INDEX
idx_clients_status(status)INDEX
idx_clients_employer_email(employer_email)INDEX
idx_clients_crisis_flag(crisis_risk_flag)INDEX
Intereses ponderados (weight) declarados por el miembro. Alimenta el algoritmo de matching con proveedores.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| client_id | int(11) | NO | None | FK | Miembro (cliente) asociado. |
| topic | varchar(100) | NO | None | - | Tema de interés. |
| weight | int(11) | YES | 100 | - | Peso de relevancia (0-100) para el matching. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🔗 Foreign Key Constraints
⚡ Indexes
client_id(client_id)INDEX
Temas de bienestar elegidos por el miembro en el intake, clasificados en 5 categorías (Emocional, Profesional, Relaciones, Físico, Financiero) con indicador de tema principal.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| client_id | int(11) | NO | None | FK | Miembro (cliente) asociado. |
| category | enum('Emotional','Professional','Relationships','Physical','Financial') | NO | None | - | Categoría de bienestar. Valores: Emotional, Professional, Relationships, Physical, Financial. |
| topic_name | varchar(100) | NO | None | - | Tema seleccionado. |
| is_primary | tinyint(1) | YES | 0 | - | 1 = tema principal. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🔗 Foreign Key Constraints
⚡ Indexes
client_id(client_id)INDEX
Perfil clínico del especialista (counsellor / coach). Incluye biografía con flujo de aprobación, especialidades, idiomas y temas en JSON, capacidad (max_clients), estado de onboarding y aprobación, datos bancarios y fiscales (IBAN, VAT), enlaces de videollamada (Zoom/Meet) y zona horaria.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| user_id | int(11) | NO | None | FK UNIQUE | Cuenta de usuario del especialista. Única. |
| name | varchar(255) | NO | None | - | Nombre completo visible. |
| first_name | varchar(100) | YES | NULL | - | Nombre de pila. |
| last_name | varchar(100) | YES | NULL | - | Apellidos. |
| date_of_birth | date | YES | NULL | - | Fecha de nacimiento. |
| classification | enum('counsellor','coach') | YES | 'counsellor' | - | Tipo de especialista. Valores: counsellor, coach. |
| email | varchar(255) | YES | NULL | - | Correo profesional. |
| bio | text | YES | NULL | - | Biografía profesional. |
| bio_status | enum('draft','pending_approval','approved','rejected') | YES | 'pending_approval' | - | Estado de aprobación de la biografía. Valores: draft, pending_approval, approved, rejected. |
| bio_locked | tinyint(1) | YES | 1 | - | 1 = biografía bloqueada para edición directa. |
| bio_approved_by | int(11) | YES | NULL | REF | Administrador que aprobó la biografía. |
| bio_approved_at | datetime | YES | NULL | - | Fecha de aprobación de la biografía. |
| specialties | longtext JSON | YES | NULL | - | Especialidades clínicas (JSON). |
| languages | longtext JSON | YES | NULL | - | Idiomas de atención (JSON). |
| topics_of_focus | longtext JSON | YES | NULL | - | Temas de enfoque (JSON). |
| gender | varchar(50) | YES | NULL | - | Género. |
| session_duration | int(11) | YES | 50 | - | Duración de sesión (minutos). |
| buffer_time | int(11) | YES | 30 | - | Tiempo de descanso entre sesiones (minutos). |
| max_clients | int(11) | YES | 10 | - | Capacidad máxima de miembros. |
| current_clients | int(11) | YES | 0 | - | Miembros activos actuales. |
| onboarding_step | enum('welcome','credentials','forms','documents','submitted','completed') | YES | 'completed' | - | Paso actual del onboarding. Valores: welcome, credentials, forms, documents, submitted, completed. |
| approval_status | enum('draft','submitted','in_review','changes_requested','approved','rejected') | YES | 'approved' | - | Estado de aprobación del perfil. Valores: draft, submitted, in_review, changes_requested, approved, rejected. |
| approved_by | int(11) | YES | NULL | REF | Administrador que aprobó el perfil. |
| approved_at | datetime | YES | NULL | - | Fecha de aprobación del perfil. |
| approval_notes | text | YES | NULL | - | Notas de revisión del administrador. |
| is_match_ready | tinyint(1) | YES | 1 | - | 1 = elegible para matching. |
| timezone | varchar(100) | YES | 'Europe/Dublin' | - | Zona horaria del especialista. |
| bank_iban | varchar(60) | YES | NULL | - | IBAN para el pago de honorarios. |
| bank_bic_swift | varchar(30) | YES | NULL | - | Código BIC/SWIFT. |
| bank_name | varchar(150) | YES | NULL | - | Nombre del banco. |
| bank_address | text | YES | NULL | - | Dirección del banco. |
| tax_reference_number | varchar(100) | YES | NULL | - | Número de referencia fiscal. |
| vat_status | varchar(50) | YES | 'exempt' | - | Estado de IVA/VAT. |
| vat_rate_pct | decimal(5,2) | YES | 0.00 | - | Tasa de IVA aplicable (%). |
| tax_compliance_ack | tinyint(1) | YES | 0 | - | 1 = declaración de cumplimiento fiscal aceptada. |
| vat_certificate_path | varchar(255) | YES | NULL | - | Ruta del certificado VAT. |
| video_provider | enum('zoom','meet','both') | YES | 'zoom' | - | Plataforma de videollamada preferida. Valores: zoom, meet, both. |
| zoom_link | varchar(255) | YES | NULL | - | Enlace personal de Zoom. |
| meet_link | varchar(255) | YES | NULL | - | Enlace personal de Google Meet. |
| avatar_path | varchar(255) | YES | NULL | - | Ruta de la foto de perfil. |
🔗 Foreign Key Constraints
🧭 Logical References (enforced by application)
Franjas semanales de disponibilidad del especialista (un registro por día, clave única (provider_id, day_of_week)).
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| provider_id | int(11) | NO | None | FK UNIQUE* | Especialista asociado. |
| day_of_week | tinyint(4) | NO | None | UNIQUE* | Día de la semana (numérico). |
| day_name | varchar(20) | YES | NULL | - | Nombre del día. |
| start_time | time | NO | '09:00:00' | - | Hora de inicio. |
| end_time | time | NO | '17:00:00' | - | Hora de fin. |
| active | tinyint(1) | YES | 1 | - | 1 = franja activa. |
🔗 Foreign Key Constraints
⚡ Indexes
uq_provider_day(provider_id, day_of_week)UNIQUE
idx_availability_provider(provider_id)INDEX
Solicitudes del especialista para modificar su biografía bloqueada. El administrador aprueba o rechaza con respuesta documentada.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| provider_id | int(11) | NO | None | REF | Especialista asociado. |
| proposed_bio | text | NO | None | - | Nueva biografía propuesta. |
| reason | text | NO | None | - | Motivo del cambio. |
| status | enum('pending','approved','rejected') | YES | 'pending' | - | Estado de la solicitud. Valores: pending, approved, rejected. |
| requested_at | timestamp | YES | current_timestamp() | - | Fecha de solicitud. |
| reviewed_by | int(11) | YES | NULL | REF | Administrador revisor. |
| reviewed_at | datetime | YES | NULL | - | Fecha de revisión. |
| admin_response | text | YES | NULL | - | Respuesta del administrador. |
🧭 Logical References (enforced by application)
Documentación de acreditación subida por el especialista durante el onboarding (seguro, cualificaciones, Garda vetting, IDs, certificado VAT, etc.) con verificación por parte del administrador.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| provider_id | int(11) | NO | None | REF INDEX | Especialista asociado. |
| document_type | enum('photo','insurance','qualifications','membership','id_proof','address_proof','cpd_evidence','garda_vetting','experience_proof','references','tax_vat_cert') | NO | None | - | Tipo de documento de acreditación. Valores: photo, insurance, qualifications, membership, id_proof, address_proof, cpd_evidence, garda_vetting, experience_proof, references, tax_vat_cert. |
| file_path | varchar(255) | NO | None | - | Ruta del archivo almacenado. |
| file_name | varchar(255) | NO | None | - | Nombre original del archivo. |
| file_size | int(11) | YES | 0 | - | Tamaño (bytes). |
| mime_type | varchar(100) | YES | 'application/pdf' | - | Tipo MIME. |
| verification_status | enum('pending','verified','rejected') | YES | 'pending' | - | Estado de verificación. Valores: pending, verified, rejected. |
| verified_by | int(11) | YES | NULL | REF | Administrador verificador. |
| verified_at | datetime | YES | NULL | - | Fecha de verificación. |
| rejection_reason | text | YES | NULL | - | Motivo de rechazo. |
| uploaded_at | timestamp | YES | current_timestamp() | - | Fecha de carga. |
🧭 Logical References (enforced by application)
⚡ Indexes
idx_prov_doc_type(provider_id, document_type)INDEX
Referencias profesionales aportadas por el especialista en el proceso de onboarding.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| provider_id | int(11) | NO | None | REF | Especialista asociado. |
| name | varchar(150) | NO | None | - | Nombre del referente. |
| relationship | varchar(100) | NO | None | - | Relación con el especialista. |
| email | varchar(255) | NO | None | - | Correo del referente. |
| phone | varchar(50) | YES | NULL | - | Teléfono de contacto. |
| organization | varchar(150) | YES | NULL | - | Organización del referente. |
| created_at | timestamp | YES | current_timestamp() | - | Fecha y hora de creación del registro. |
🧭 Logical References (enforced by application)
Sesiones programadas entre miembro y especialista. Incluye tipo, proveedor de video y enlace, estado, solicitudes de cambio (reprogramar/cancelar con aviso mayor o menor a 24 h), asistencia y 5 métricas de valoración del especialista.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| client_id | int(11) | NO | None | FK | Miembro (cliente) asociado. |
| provider_id | int(11) | NO | None | FK | Especialista asociado. |
| client_name | varchar(255) | YES | NULL | - | Nombre del miembro (desnormalizado para listados rápidos). |
| scheduled_at | datetime | NO | None | INDEX | Fecha y hora programada. |
| duration_min | int(11) | YES | 50 | - | Duración (minutos). |
| type | enum('therapy','coaching','intake') | YES | 'therapy' | - | Tipo de sesión. Valores: therapy, coaching, intake. |
| video_provider | enum('zoom','meet') | YES | 'zoom' | - | Plataforma de videollamada. Valores: zoom, meet. |
| video_link | varchar(255) | YES | NULL | - | Enlace de la videollamada. |
| status | enum('scheduled','completed','cancelled','late_cancel') | YES | 'scheduled' | INDEX | Estado de la cita. Valores: scheduled, completed, cancelled, late_cancel. |
| notes | text | YES | NULL | - | Notas de la cita. |
| change_request_type | enum('none','reschedule','cancel') | YES | 'none' | - | Tipo de cambio solicitado por el miembro. Valores: none, reschedule, cancel. |
| change_request_reason | text | YES | NULL | - | Motivo del cambio. |
| change_request_notice | enum('more_24h','less_24h') | YES | NULL | - | Antelación del aviso (política de 24 h). Valores: more_24h, less_24h. |
| change_request_at | datetime | YES | NULL | - | Fecha de la solicitud de cambio. |
| invoice_id | int(11) | YES | NULL | REF | Factura generada por la sesión (invoices). |
| attendance | tinyint(1) | YES | NULL | - | 1 = asistió, 0 = no asistió, NULL = sin registrar. |
| rating_quality | tinyint(1) | YES | NULL | - | Valoración 1-5: calidad de la sesión. |
| rating_connection | tinyint(1) | YES | NULL | - | Valoración 1-5: conexión con el miembro. |
| rating_progress | tinyint(1) | YES | NULL | - | Valoración 1-5: progreso percibido. |
| rating_client_prep | tinyint(1) | YES | NULL | - | Valoración 1-5: preparación del miembro. |
| rating_overall | tinyint(1) | YES | NULL | - | Valoración 1-5: satisfacción global. |
🔗 Foreign Key Constraints
🧭 Logical References (enforced by application)
⚡ Indexes
idx_appointments_provider(provider_id)INDEX
idx_appointments_client(client_id)INDEX
idx_appointments_status(status)INDEX
idx_appointments_scheduled(scheduled_at)INDEX
Resultados de cuestionarios psicométricos validados (PHQ-9, GAD-7, WHO-5) con puntaje, nivel de riesgo, recomendación de servicio y respuestas completas en JSON.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| client_id | int(11) | NO | None | FK | Miembro (cliente) asociado. |
| client_name | varchar(255) | YES | NULL | - | Nombre del miembro (desnormalizado para listados rápidos). |
| type | enum('PHQ9','GAD7','WHO5') | NO | None | - | Escala aplicada. Valores: PHQ9, GAD7, WHO5. |
| score | int(11) | NO | None | - | Puntaje total. |
| risk_level | enum('minimal','mild','moderate','moderately_severe','severe') | YES | NULL | - | Nivel de severidad interpretado. Valores: minimal, mild, moderate, moderately_severe, severe. |
| recommendation | enum('coaching','counselling','both') | YES | NULL | - | Servicio recomendado según resultado. Valores: coaching, counselling, both. |
| answers_json | longtext JSON | YES | NULL | - | Respuestas ítem a ítem (JSON). |
| administered_by | int(11) | YES | NULL | FK | Especialista que aplicó la escala (NULL = autoaplicado). |
| administered_at | datetime | NO | None | - | Fecha y hora de aplicación. |
🔗 Foreign Key Constraints
⚡ Indexes
administered_by(administered_by)INDEX
idx_questionnaires_client(client_id, type)INDEX
Cribado de riesgo de crisis de 3 preguntas (intención, seguridad, apoyo) con resultado safe / high_risk.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| client_id | int(11) | NO | None | FK | Miembro (cliente) asociado. |
| q1_intent | tinyint(1) | NO | None | - | Pregunta 1: intención. |
| q2_safety | tinyint(1) | NO | None | - | Pregunta 2: seguridad. |
| q3_support | tinyint(1) | NO | None | - | Pregunta 3: red de apoyo. |
| result | enum('safe','high_risk') | NO | None | - | Resultado del cribado. Valores: safe, high_risk. |
| notes | text | YES | NULL | - | Notas internas u observaciones. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🔗 Foreign Key Constraints
⚡ Indexes
client_id(client_id)INDEX
Alertas de seguridad y bienestar (crisis_risk, screen_wellbeing) con severidad (critical / warning / info), estado y auditoría de resolución (resolved_by, resolved_at).
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| client_id | int(11) | NO | None | FK | Miembro (cliente) asociado. |
| type | enum('crisis_risk','screen_wellbeing') | NO | None | - | Origen de la alerta. Valores: crisis_risk, screen_wellbeing. |
| severity | enum('critical','warning','info') | NO | 'warning' | - | Severidad. Valores: critical, warning, info. |
| status | enum('active','resolved') | NO | 'active' | INDEX | Estado de la alerta. Valores: active, resolved. |
| trigger_reason | varchar(255) | NO | None | - | Motivo que disparó la alerta. |
| notes | text | YES | NULL | - | Notas internas u observaciones. |
| resolved_by | int(11) | YES | NULL | FK | Usuario que resolvió la alerta. |
| resolved_at | timestamp | YES | NULL | - | Fecha de resolución. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🔗 Foreign Key Constraints
⚡ Indexes
resolved_by(resolved_by)INDEX
idx_alerts_client(client_id, status)INDEX
idx_alerts_status(status, severity)INDEX
Planes de seguridad elaborados por el especialista para miembros en riesgo: estrategias de afrontamiento, contactos de apoyo y emergencia, seguridad del entorno y confirmación por el miembro.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| client_id | int(11) | NO | None | FK | Miembro (cliente) asociado. |
| provider_id | int(11) | NO | None | FK | Especialista asociado. |
| session_id | int(11) | YES | NULL | FK | Cita (appointments) asociada. |
| coping_strategies | text | YES | NULL | - | Estrategias de afrontamiento. |
| support_contacts | text | YES | NULL | - | Contactos de apoyo. |
| emergency_contacts | text | YES | NULL | - | Contactos de emergencia. |
| environment_safety | text | YES | NULL | - | Medidas de seguridad del entorno. |
| is_confirmed | tinyint(1) | YES | 0 | - | 1 = confirmado por el miembro. |
| confirmed_at | timestamp | YES | NULL | - | Fecha de confirmación. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🔗 Foreign Key Constraints
⚡ Indexes
client_id(client_id)INDEX
provider_id(provider_id)INDEX
session_id(session_id)INDEX
Facturas de honorarios del especialista asociadas (opcionalmente) a sesión, miembro y empresa. Ciclo pending → submitted → paid; conserva registros contables con ON DELETE SET NULL.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| session_id | int(11) | YES | NULL | FK | Cita (appointments) asociada. |
| provider_id | int(11) | YES | NULL | FK | Especialista que factura. |
| client_id | int(11) | YES | NULL | FK | Miembro (cliente) asociado. |
| company_id | int(11) | YES | NULL | FK | Empresa asociada. |
| client_name | varchar(255) | YES | NULL | - | Nombre del miembro (desnormalizado para listados rápidos). |
| amount | decimal(10,2) | NO | None | - | Importe de la factura. |
| currency | varchar(10) | YES | 'EUR' | - | Moneda (ISO). |
| status | enum('pending','submitted','paid') | YES | 'pending' | INDEX | Estado de la factura. Valores: pending, submitted, paid. |
| pdf_path | varchar(255) | YES | NULL | - | Ruta del PDF generado. |
| clinical_notes | text | YES | NULL | - | Notas clínicas asociadas. |
| rating_score | tinyint(4) | YES | NULL | - | Valoración numérica de la sesión. |
| rating_feedback | text | YES | NULL | - | Comentario de valoración. |
| submitted_at | datetime | YES | NULL | - | Fecha de envío. |
| paid_at | datetime | YES | NULL | - | Fecha de pago. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
🔗 Foreign Key Constraints
⚡ Indexes
session_id(session_id)INDEX
client_id(client_id)INDEX
company_id(company_id)INDEX
idx_invoices_provider(provider_id)INDEX
idx_invoices_status(status)INDEX
Pagos registrados contra una factura (transferencia o manual) con referencia de transacción y comprobante.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| invoice_id | int(11) | NO | None | FK | Factura saldada. |
| method | enum('transfer','manual') | NO | 'transfer' | - | Método de pago. Valores: transfer, manual. |
| transaction_id | varchar(255) | YES | NULL | - | Referencia de la transacción. |
| receipt_path | varchar(255) | YES | NULL | - | Ruta del comprobante. |
| registered_at | timestamp | NO | current_timestamp() | - | Fecha de registro del pago. |
🔗 Foreign Key Constraints
⚡ Indexes
invoice_id(invoice_id)INDEX
Mensajería privada entre usuarios con borrado lógico independiente para emisor y receptor y control de lectura.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| sender_id | int(11) | NO | None | FK | Usuario emisor. |
| sender_name | varchar(255) | YES | NULL | - | Nombre del emisor (desnormalizado). |
| receiver_id | int(11) | NO | None | FK | Usuario receptor. |
| receiver_name | varchar(255) | YES | NULL | - | Nombre del receptor (desnormalizado). |
| content | text | NO | None | - | Contenido del mensaje. |
| is_read | tinyint(1) | YES | 0 | - | 1 = leído. |
| read_at | datetime | YES | NULL | - | Fecha de lectura. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
| deleted_by_sender | tinyint(1) | NO | 0 | - | Borrado lógico por el emisor. |
| deleted_by_receiver | tinyint(1) | NO | 0 | - | Borrado lógico por el receptor. |
🔗 Foreign Key Constraints
⚡ Indexes
idx_messages_receiver(receiver_id, is_read)INDEX
idx_messages_sender(sender_id)INDEX
Cola asíncrona de correos transaccionales con cuerpo HTML/texto, reintentos, registro de error y metadatos JSON.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| to_email | varchar(255) | NO | None | - | Destinatario. |
| to_name | varchar(255) | YES | NULL | - | Nombre del destinatario. |
| subject | varchar(500) | NO | None | - | Asunto. |
| body_html | longtext | NO | None | - | Cuerpo HTML. |
| body_text | text | YES | NULL | - | Cuerpo en texto plano. |
| status | enum('pending','sent','failed') | YES | 'pending' | INDEX | Estado de envío. Valores: pending, sent, failed. |
| attempts | tinyint(4) | YES | 0 | - | Intentos de envío realizados. |
| error_msg | text | YES | NULL | - | Último error de envío. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
| sent_at | timestamp | YES | NULL | - | Fecha de envío exitoso. |
| metadata | longtext JSON | YES | NULL | - | Metadatos opcionales (JSON): tipo, referencia, etc. |
⚡ Indexes
idx_email_queue_status(status, created_at)INDEX
Preguntas frecuentes segmentadas por rol destinatario (all, client, provider, company, admin), con palabras clave y orden de visualización.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| category_id | int(11) | NO | None | FK | Categoría de la FAQ. |
| target_role | enum('all','client','provider','company','admin') | NO | 'all' | INDEX | Rol destinatario. Valores: all, client, provider, company, admin. |
| question | varchar(500) | NO | None | - | Pregunta. |
| answer | text | NO | None | - | Texto de respuesta. |
| keywords | varchar(255) | YES | NULL | - | Palabras clave de búsqueda. |
| display_order | int(11) | YES | 0 | - | Orden de visualización. |
| is_active | tinyint(1) | YES | 1 | - | Flag de registro activo (1 = activo, 0 = inactivo). |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
| updated_at | timestamp | YES | NULL ON UPDATE | - | Última actualización automática. |
🔗 Foreign Key Constraints
⚡ Indexes
category_id(category_id)INDEX
idx_faqs_role_cat(target_role, category_id, is_active, display_order)INDEX
Categorías para organizar las FAQs, con slug único, icono emoji y orden visual.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| slug | varchar(50) | NO | None | UNIQUE | Identificador amigable único (URL / código). |
| label | varchar(100) | NO | None | - | Nombre visible de la categoría. |
| icon | varchar(20) | YES | '❓' | - | Icono / emoji. |
| display_order | int(11) | YES | 0 | - | Orden de visualización. |
| is_active | tinyint(1) | YES | 1 | - | Flag de registro activo (1 = activo, 0 = inactivo). |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
Biblioteca de recursos descargables del Hub para empresas (crisis & estrés, salud profesional, DEIB, plantillas, liderazgo) segmentada por audiencia, con contador de descargas y publicación.
| Column | Data Type | Nullable | Default | Key | Purpose / Description |
| id | int(11) | NO | AUTO_INC | PRIMARY | Identificador único autoincremental. |
| title | varchar(255) | NO | None | - | Título del recurso. |
| slug | varchar(255) | NO | None | UNIQUE | Identificador amigable único (URL / código). |
| category | enum('crisis_stress','professional_health','deib','templates','leadership') | NO | None | INDEX | Categoría temática. Valores: crisis_stress, professional_health, deib, templates, leadership. |
| target_audience | enum('admins','managers','employees','all') | NO | 'all' | INDEX | Audiencia destinataria. Valores: admins, managers, employees, all. |
| description | text | NO | None | - | Descripción. |
| author_title | varchar(150) | YES | 'MHC Clinical Operations Team' | - | Autor / equipo editor. |
| read_time_min | int(11) | YES | 5 | - | Tiempo de lectura (minutos). |
| file_type | varchar(20) | YES | 'PDF' | - | Formato del archivo. |
| file_url | varchar(255) | YES | NULL | - | URL / ruta del archivo. |
| tags | varchar(255) | YES | NULL | - | Etiquetas. |
| download_count | int(11) | YES | 0 | - | Número de descargas. |
| is_published | tinyint(1) | NO | 1 | - | 1 = publicado. |
| created_at | timestamp | NO | current_timestamp() | - | Fecha y hora de creación del registro. |
⚡ Indexes
slug(slug)UNIQUE
idx_res_category(category)INDEX
idx_res_audience(target_audience)INDEX