Diccionario de Datos — ExpressMX
Documento normativo que describe cada entidad del modelo relacional implementado en PostgreSQL (Neon).
Fuente de verdad: docs/architecture/schema-consolidated.sql (resultado de 00.sql + migrations/001-006).
Generado: 2026-05-05.
Convenciones:
- Cada tabla se documenta con: descripción del dominio, columnas (nombre, tipo PostgreSQL, nullable, default, descripción semántica, ejemplos), restricciones (PK, FK, UK, CHECK), índices principales, volumen estimado y politicas RLS asociadas cuando aplican.
- Los tipos enumerados se reciclan a lo largo del documento; su definición se concentra en la sección 0.
- Todas las claves primarias son UUID generadas por
gen_random_uuid(), salvo cuando se indica explícitamente lo contrario (por ejemplo claves compuestas o referencias 1:1 conauth.users). - El esquema implícito es
public, salvo el esquemaauthempleado para la integración con Supabase / Neon.
0. Tipos enumerados
| Enum | Valores | Uso |
|---|---|---|
rol_usuario |
cliente, prestador, admin | Discriminador de rol en usuarios.rol. |
tipo_documento |
ine, domicilio, certificacion, curp | Tipo de archivo en documentos_prestador. |
estatus_documento |
pendiente, aprobado, rechazado | Ciclo de revisión de documentos. |
dia_semana |
lun, mar, mie, jue, vie, sab, dom | Disponibilidad semanal de prestadores. |
estatus_orden |
solicitada, asignada, en_camino, en_progreso, completada, cancelada | Máquina de estados de la orden. |
metodo_pago |
tarjeta, efectivo, transferencia | Forma de pago elegida por el cliente. |
estatus_pago |
pendiente, procesado, fallido, reembolsado | Ciclo del pago en pasarela. |
estatus_deposito |
pendiente, depositado | Conciliación con el prestador. |
tipo_descuento |
porcentaje, monto_fijo | Política de cupón. |
tipo_notif |
push, sms, email | Canal técnico de notificación. |
canal_notif |
orden, promo, sistema | Categoría lógica de notificación. |
estatus_zona |
activa, en_expansion, suspendida | Estado operativo de la zona de cobertura. |
tipo_ajuste |
multiplicador, monto_fijo | Tipo de tarifa por zona. |
cat_ticket |
cobro_incorrecto, no_show, dano_propiedad, queja_servicio, otro | Categoría base del ticket. |
prioridad_ticket |
baja, media, alta, critica | Prioridad operativa. |
estatus_ticket |
abierto, en_revision, resuelto, escalado | Estatus v1 del ticket. |
estatus_ticket_v2 |
nuevo, en_progreso, en_espera_cliente, en_espera_tercero, resuelto, cerrado, cancelado, investigacion, error_conocido, fix_en_progreso | Estatus extendido ITIL (fase 2). |
tipo_autor_msg |
usuario, agente, sistema | Origen del mensaje de ticket. |
estatus_factura |
timbrada, cancelada | Ciclo de la factura CFDI. |
estatus_reembolso |
solicitado, aprobado, rechazado, procesado | Ciclo del reembolso. |
segmento_banner |
todos, nuevos, recurrentes | Segmento al que aplica un banner. |
estatus_corte |
generado, revisado, depositado | Ciclo del corte de pago al prestador. |
estatus_cargo_extra |
propuesto, aceptado, rechazado | Ciclo del cargo extra propuesto en orden. |
tipo_ticket |
incidente, solicitud, problema, cambio | Discriminador ITIL del ticket. |
tier_soporte |
l1, l2, l3 | Tier de escalamiento. |
codigo_resolucion |
resuelto_directo, kb_resuelto, reembolso_emitido, duplicado, no_aplica, no_reproducible, sin_respuesta_cliente | Código obligatorio al cerrar ticket. |
escalation_motivo |
fuera_alcance, requiere_autorizacion, requiere_dev, sla_breach, cliente_solicitud | Motivo del escalamiento. |
estado_csat |
pendiente, enviado, respondido, expirado | Ciclo de la encuesta CSAT. |
estado_mim |
declarado, mitigando, resuelto, pir_pendiente, cerrado | Ciclo del Major Incident. |
audiencia_kb |
cliente, agente_l1, agente_l2_l3, admin | Audiencia objetivo de un artículo de KB. |
1. auth.users
Tabla espejo de Supabase / Neon que provee identidad cruda. Garantiza que cada perfil aplicativo se corresponda con una cuenta autenticada real. Está aislada en el esquema auth.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
Identificador único del usuario en la capa de autenticación. | 8b6a59e0-... |
| TEXT | Sí | — | Correo del usuario. UNIQUE. | cliente@ex.com |
|
| raw_user_meta_data | JSONB | Sí | '{}'::jsonb |
Metadatos enviados al firmar (nombre, rol, código invitación, CURP, fecha de nacimiento). | {"rol":"cliente"} |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Fecha de creación. | 2026-04-12T10:01:00Z |
Restricciones: PRIMARY KEY (id), UNIQUE (email).
Índices: implícito por PK y por UNIQUE.
Volumen esperado: 1 por usuario (decenas de miles en producción media).
RLS: no aplica (esquema gestionado por la capa Supabase).
2. usuarios
Perfil aplicativo del usuario. Cada fila comparte el id con auth.users. Diferencia rol y agencia, soporta restricciones blandas (pausa) y normativa CURP.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK; FK a auth.users(id) ON DELETE CASCADE. |
8b6a59e0-... |
| nombre | TEXT | No | — | Nombre(s) de pila. | María |
| apellidos | TEXT | No | — | Apellidos. | Hernández López |
| TEXT | No | — | Correo único. | m.hernandez@expr.mx |
|
| telefono | TEXT | Sí | — | Teléfono de contacto, formato libre. | +5215512345678 |
| rol | rol_usuario | No | 'cliente' |
Rol funcional. | prestador |
| avatar_url | TEXT | Sí | — | URL del avatar. | https://cdn/u/1.png |
| curp | TEXT | Sí | — | Clave Única de Registro de Población. | HELM860612MDFRPR04 |
| fecha_nacimiento | DATE | Sí | — | Fecha de nacimiento. | 1986-06-12 |
| activo | BOOLEAN | Sí | TRUE |
Cuenta vigente. | TRUE |
| recibe_ordenes | BOOLEAN | No | TRUE |
Pausa blanda para prestadores. | FALSE |
| motivo_restriccion | TEXT | Sí | — | Texto libre con motivo de la pausa. | Documentos vencidos |
| restringido_en | TIMESTAMPTZ | Sí | — | Cuándo se aplicó la pausa. | 2026-04-30T18:00:00Z |
| restringido_por | UUID | Sí | — | Admin que aplicó la pausa. | a1... |
| agencia_id | UUID | Sí | — | FK a agencias(id) ON DELETE SET NULL. |
c4... |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Fecha de alta. | — |
| updated_at | TIMESTAMPTZ | Sí | NOW() |
Última actualización. | — |
Restricciones: PRIMARY KEY (id); FK id → auth.users(id) ON DELETE CASCADE; FK agencia_id → agencias(id) ON DELETE SET NULL; UNIQUE (email); UNIQUE (curp); CHECK curp ~ '^[A-Z]{4}[0-9]{6}[HM][A-Z]{5}[0-9A-Z][0-9]$' OR curp IS NULL.
Índices: idx_usuarios_agencia (agencia_id).
Volumen esperado: 30k–250k filas en operación; crece linealmente con altas.
RLS: habilitada. Policies ver_mi_perfil, admin_ve_usuarios, usuarios_select_admin_scoped (Zero Trust con tiene_permiso('usuarios.listar_completo') y tiene_acceso_perfil), editar_mi_perfil.
3. user_credentials
Almacena el hash bcrypt de la contraseña local cuando no se utiliza un proveedor externo de autenticación.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| user_id | UUID | No | — | PK y FK 1:1 a usuarios(id) ON DELETE CASCADE. |
8b... |
| password_hash | TEXT | No | — | Hash bcrypt cost 8. | $2b$08$... |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta del hash. | — |
| updated_at | TIMESTAMPTZ | Sí | NOW() |
Última rotación. | — |
Restricciones: PRIMARY KEY (user_id), FK user_id → usuarios(id) ON DELETE CASCADE.
Índices: implícito.
Volumen: 1 por usuario con autenticación local.
RLS: no aplicada (acceso por funciones server-only y service role).
4. password_reset_tokens
Tokens temporales para reseteo de contraseña, generados por correo y consumidos una sola vez.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| user_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| token | TEXT | No | — | Token aleatorio largo. UNIQUE. | reset_… |
| expires_at | TIMESTAMPTZ | No | — | Fecha de caducidad. | — |
| used | BOOLEAN | Sí | FALSE |
Marca de uso. | FALSE |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Generación. | — |
Restricciones: PK (id); FK user_id → usuarios(id) ON DELETE CASCADE; UNIQUE (token).
Índices: idx_password_reset_tokens_token (token), idx_password_reset_tokens_user_id (user_id).
Volumen: efímero (decenas a centenares por día).
RLS: no aplicada.
5. roles_admin
Catálogo de roles administrativos del backoffice. Sustenta el RBAC granular.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| nombre | TEXT | No | — | Nombre interno único. | super_admin |
| descripcion | TEXT | Sí | — | Descripción de alcance del rol. | — |
| activo | BOOLEAN | Sí | TRUE |
Si se puede asignar. | TRUE |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id); UNIQUE (nombre).
Índices: implícito.
Volumen: bajo (≈ 6 roles base + agregados).
RLS: habilitada. Policy admin_ve_roles (solo si es_admin()).
Datos seed: super_admin, admin, soporte, finanzas, operaciones, lector_basico.
6. permisos
Catálogo de permisos atómicos del backoffice. Cada permiso pertenece a un módulo lógico.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| clave | TEXT | No | — | Clave única, formato modulo.accion. |
usuarios.listar_completo |
| descripcion | TEXT | Sí | — | Descripción funcional. | — |
| modulo | TEXT | No | — | Agrupador lógico. | soporte |
Restricciones: PK (id); UNIQUE (clave).
Índices: implícito.
Volumen: ≈ 45 permisos definidos en seed (00.sql + migrations 004 y 006).
RLS: habilitada. Policy admin_ve_permisos (es_admin()).
7. usuarios_admin
Tabla de asignación 1:1 entre usuarios y roles_admin. Marca quién puede acceder al backoffice y qué rol ejerce.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| usuario_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. UNIQUE. |
— |
| rol_id | UUID | No | — | FK a roles_admin(id) ON DELETE RESTRICT. |
— |
| activo | BOOLEAN | Sí | TRUE |
Si la asignación está vigente. | — |
| ultimo_acceso | TIMESTAMPTZ | Sí | — | Última sesión en backoffice. | — |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id); UNIQUE (usuario_id); FKs ya descritas.
Índices: implícitos.
Volumen: bajo (decenas a baja centena).
RLS: habilitada. Policy admin_ve_admins (es_admin()).
8. roles_permisos
Tabla asociativa muchos-a-muchos entre roles y permisos. Cumple BCNF (toda dependencia funcional gira alrededor de la PK compuesta).
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK sintética. | — |
| rol_id | UUID | No | — | FK a roles_admin(id) ON DELETE CASCADE. |
— |
| permiso_id | UUID | No | — | FK a permisos(id) ON DELETE CASCADE. |
— |
Restricciones: PK (id); UNIQUE (rol_id, permiso_id).
Índices: implícito por UNIQUE.
Volumen: producto cartesiano controlado (≈ 110 filas en seed).
RLS: habilitada. Policy admin_ve_rp.
9. categorias_servicio
Categorías generales del catálogo (limpieza, plomería, etc.). Encabezan la jerarquía de servicios.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| nombre | TEXT | No | — | Nombre comercial. | Limpieza |
| descripcion | TEXT | Sí | — | Texto descriptivo. | — |
| icono_url | TEXT | Sí | — | URL del icono. | — |
| orden_despliegue | INT | Sí | 0 |
Orden visual. | 1 |
| activa | BOOLEAN | Sí | TRUE |
Si se publica al cliente. | TRUE |
Restricciones: PK (id).
Índices: implícito.
Volumen: bajo (decenas).
RLS: habilitada. Policies leer_categorias (todos), admin_crea_cat, admin_edita_cat (admin).
10. servicios
Servicios concretos ofertados por el marketplace. Pertenecen a una categoría.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| categoria_id | UUID | No | — | FK a categorias_servicio(id) ON DELETE RESTRICT. |
— |
| nombre | TEXT | No | — | Nombre comercial del servicio. | Limpieza profunda |
| descripcion | TEXT | Sí | — | Descripción detallada. | — |
| precio_base | NUMERIC(10,2) | No | — | Precio piso en MXN. | 450.00 |
| precio_maximo | NUMERIC(10,2) | Sí | — | Precio techo (orientativo). | 900.00 |
| duracion_estimada_min | INT | Sí | — | Duración estándar en minutos. | 120 |
| activo | BOOLEAN | Sí | TRUE |
Si se publica al cliente. | TRUE |
Restricciones: PK (id); FK descrita.
Índices: idx_serv_cat (categoria_id).
Volumen: bajo (cientos).
RLS: habilitada. Policies leer_servicios, admin_crea_serv, admin_edita_serv.
11. servicios_prestador
Tabla asociativa que define qué servicios ofrece cada prestador y a qué precio personalizado opcional.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| prestador_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| servicio_id | UUID | No | — | FK a servicios(id) ON DELETE CASCADE. |
— |
| precio_custom | NUMERIC(10,2) | Sí | — | Tarifa personalizada del prestador. | 600.00 |
| activo | BOOLEAN | No | TRUE |
Si el prestador acepta este servicio. | TRUE |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
Restricciones: PK (id); UNIQUE (prestador_id, servicio_id); FKs.
Índices: idx_serv_prest_prestador, idx_serv_prest_servicio, idx_serv_prest_activo parcial donde activo = TRUE.
Volumen: medio (decenas de miles si la base de prestadores es amplia).
RLS: habilitada. Policies serv_prest_select_all, serv_prest_insert_own, serv_prest_update_own, serv_prest_delete_own.
12. comisiones_plataforma
Reglas de comisión por categoría con vigencia y posible escalonado por volumen mensual.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| categoria_id | UUID | No | — | FK a categorias_servicio(id) ON DELETE RESTRICT. |
— |
| porcentaje_base | NUMERIC(5,2) | No | — | Comisión base. | 15.00 |
| porcentaje_volumen | NUMERIC(5,2) | Sí | — | Comisión cuando se rebasa el umbral. | 12.00 |
| umbral_ordenes_mes | INT | Sí | — | Mínimo de órdenes mensuales para aplicar volumen. | 100 |
| vigencia_inicio | DATE | No | — | Inicio de vigencia. | — |
| vigencia_fin | DATE | Sí | — | Fin de vigencia. | — |
| activa | BOOLEAN | Sí | TRUE |
Si la regla está vigente. | — |
Restricciones: PK (id); FK descrita.
Índices: implícito.
Volumen: bajo.
RLS: habilitada. Policy admin_ve_comisiones.
13. zonas_cobertura
Zonas geográficas en las que opera la plataforma. Soportan radio circular y polígono opcional.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| nombre | TEXT | No | — | Nombre comercial. | CDMX Norte |
| centro_lat | NUMERIC(10,7) | No | — | Latitud del centro. | 19.5325000 |
| centro_lng | NUMERIC(10,7) | No | — | Longitud del centro. | -99.1500000 |
| radio_km | NUMERIC(6,2) | Sí | — | Radio en kilómetros. | 15.00 |
| poligono_coords | JSONB | Sí | — | Polígono GeoJSON-like. | — |
| estatus | estatus_zona | Sí | 'activa' |
Estado operativo. | activa |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id).
Índices: implícito.
Volumen: bajo (decenas).
RLS: habilitada. Policies ver_zonas (todos), admin_zona (admin INSERT).
14. agencias
Agencias o contratistas a quienes se asocian usuarios (B2B). Permite agrupar prestadores bajo un paraguas comercial.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| nombre | TEXT | No | — | Razón social. | Servicios Premier SA |
| rfc | TEXT | Sí | — | RFC. | SPR123456ABC |
| telefono | TEXT | Sí | — | Teléfono comercial. | — |
| TEXT | Sí | — | Correo. | — | |
| activa | BOOLEAN | No | TRUE |
Si está vigente. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
| updated_at | TIMESTAMPTZ | No | NOW() |
Actualización. | — |
Restricciones: PK (id).
Índices: implícito.
Volumen: bajo.
RLS: habilitada. Policies agencias_select_auth, agencias_manage_admin.
15. tarifas_zona
Ajustes de precio por servicio dentro de una zona, con vigencia.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| zona_id | UUID | No | — | FK a zonas_cobertura(id) ON DELETE CASCADE. |
— |
| servicio_id | UUID | No | — | FK a servicios(id) ON DELETE CASCADE. |
— |
| tipo_ajuste | tipo_ajuste | No | — | Multiplicador o monto fijo. | multiplicador |
| valor | NUMERIC(10,2) | No | — | Valor del ajuste. | 1.20 |
| vigencia_inicio | DATE | No | — | Inicio. | — |
| vigencia_fin | DATE | Sí | — | Fin. | — |
| activa | BOOLEAN | Sí | TRUE |
Vigente. | — |
Restricciones: PK (id); FKs.
Índices: implícito.
Volumen: bajo.
RLS: habilitada. Policy admin_ve_tarifas.
16. cupones
Códigos promocionales con descuento porcentual o monto fijo. Soportan límites de uso y restricción a primera compra.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| codigo | TEXT | No | — | Código alfanumérico único. | BIENVENIDA20 |
| tipo_descuento | tipo_descuento | No | — | Modalidad. | porcentaje |
| valor | NUMERIC(10,2) | No | — | Valor del descuento. | 20.00 |
| fecha_inicio | DATE | No | — | Inicio de vigencia. | — |
| fecha_expiracion | DATE | No | — | Fin de vigencia. | — |
| usos_maximos | INT | Sí | 1 |
Tope de redenciones. | 100 |
| usos_actuales | INT | Sí | 0 |
Contador acumulado. | 12 |
| solo_primera_compra | BOOLEAN | Sí | FALSE |
Si solo aplica a la primera orden. | — |
| categoria_id | UUID | Sí | — | FK opcional a categorias_servicio(id) ON DELETE SET NULL. |
— |
Restricciones: PK (id); UNIQUE (codigo); CHECK (usos_actuales <= usos_maximos); CHECK (fecha_expiracion >= fecha_inicio); FK descrita.
Índices: implícito.
Volumen: bajo a medio (cientos).
RLS: habilitada. Policies ver_cupones (todos), admin_cupones (admin INSERT).
17. banners_promocionales
Banners publicitarios mostrados en home con segmentación por audiencia y orden de prioridad.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| titulo | TEXT | No | — | Título visible. | — |
| imagen_url | TEXT | No | — | URL del recurso gráfico. | — |
| url_destino | TEXT | Sí | — | Deep link al hacer tap. | — |
| fecha_inicio | DATE | No | — | Inicio. | — |
| fecha_fin | DATE | No | — | Fin. | — |
| orden_prioridad | INT | Sí | 0 |
Orden visual. | — |
| segmento | segmento_banner | Sí | 'todos' |
Audiencia. | nuevos |
| activo | BOOLEAN | Sí | TRUE |
Si se publica. | — |
| creado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
Restricciones: PK (id); CHECK (fecha_fin >= fecha_inicio); FK descrita.
Índices: implícito.
Volumen: bajo.
RLS: habilitada. Policies ver_banners, admin_crea_banner.
18. config_sistema
Almacén de parámetros de configuración runtime (clave/valor). Soporta auditoría blanda con modificado_por.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| clave | TEXT | No | — | Clave única. | iva_pct |
| valor | TEXT | No | — | Valor crudo (string). | 16 |
| tipo_dato | TEXT | Sí | 'string' |
Hint de casting. | decimal |
| descripcion | TEXT | Sí | — | Descripción humana. | — |
| modificado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| updated_at | TIMESTAMPTZ | Sí | NOW() |
Última edición. | — |
Restricciones: PK (id); UNIQUE (clave).
Índices: implícito.
Volumen: bajo (decenas).
RLS: habilitada. Policies admin_ve_config, admin_edita_config.
Seed: tiempo_max_asignacion_min, radio_busqueda_km, docs_min_prestador, comision_default_pct, iva_pct, tope_reembolso_agente.
19. invitaciones_prestadores
Códigos de invitación de un solo uso para registrar prestadores. Soportan revocación.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| codigo | TEXT | No | — | Código alfanumérico. UNIQUE. | H7K3PQRS |
| creado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| creado_en | TIMESTAMPTZ | No | NOW() |
Fecha de generación. | — |
| expira_en | TIMESTAMPTZ | No | NOW() + INTERVAL '14 days' |
Caducidad. | — |
| usado_en | TIMESTAMPTZ | Sí | — | Cuándo se redimió. | — |
| usado_por | UUID | Sí | — | FK a auth.users(id) ON DELETE SET NULL. |
— |
| revocada_en | TIMESTAMPTZ | Sí | — | Fecha de revocación. | — |
| revocada_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| notas | TEXT | Sí | — | Notas operativas. | — |
Restricciones: PK (id); UNIQUE (codigo); FKs.
Índices: idx_invitaciones_codigo, idx_invitaciones_disponibles (expira_en) WHERE usado_en IS NULL.
Volumen: bajo a medio.
RLS: habilitada. Policy invitaciones_admin_all.
20. documentos_prestador
Documentos legales del prestador (INE, comprobante de domicilio, certificaciones, CURP) y su revisión.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| prestador_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| tipo | tipo_documento | No | — | Tipo del documento. | ine |
| archivo_url | TEXT | No | — | URL al objeto en storage. | — |
| estatus | estatus_documento | Sí | 'pendiente' |
Estado de la revisión. | aprobado |
| fecha_expiracion | DATE | Sí | — | Caducidad del documento. | — |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Subida. | — |
Restricciones: PK (id); FK descrita.
Índices: idx_docs_prest (prestador_id).
Volumen: medio (3+ documentos por prestador).
RLS: habilitada. Policies ver_mis_docs, subir_doc, admin_ve_docs, admin_revisa_doc.
21. disponibilidad_prestador
Bloques semanales de disponibilidad horaria del prestador y zona declarada.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| prestador_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| dia | dia_semana | No | — | Día de la semana. | mar |
| hora_inicio | TIME | No | — | Hora inicio (24h). | 08:00 |
| hora_fin | TIME | No | — | Hora fin. | 18:00 |
| zona_lat | NUMERIC(10,7) | Sí | — | Lat declarada. | — |
| zona_lng | NUMERIC(10,7) | Sí | — | Lng declarada. | — |
| radio_cobertura_km | NUMERIC(6,2) | Sí | 10.0 |
Radio. | — |
Restricciones: PK (id); FK descrita; CHECK (hora_fin > hora_inicio).
Índices: idx_disp_prest (prestador_id).
Volumen: bajo a medio.
RLS: habilitada. Policies leer_disp, crear_disp, editar_disp, borrar_disp.
22. direcciones
Direcciones registradas por el usuario, con coordenadas opcionales y bandera de predeterminada.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| usuario_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| alias | TEXT | Sí | — | Etiqueta. | Casa |
| calle | TEXT | No | — | Calle. | Av. Reforma |
| numero_ext | TEXT | No | — | Número exterior. | 123 |
| numero_int | TEXT | Sí | — | Número interior. | 4B |
| colonia | TEXT | No | — | Colonia. | Juárez |
| cp | TEXT | No | — | Código postal. | 06600 |
| ciudad | TEXT | No | — | Ciudad. | CDMX |
| estado | TEXT | No | — | Estado. | Ciudad de México |
| latitud | NUMERIC(10,7) | Sí | — | Lat. | — |
| longitud | NUMERIC(10,7) | Sí | — | Lng. | — |
| referencia | TEXT | Sí | — | Texto libre. | Frente al parque |
| predeterminada | BOOLEAN | Sí | FALSE |
Marca primaria. | — |
Restricciones: PK (id); FK descrita.
Índices: idx_dir_user (usuario_id).
Volumen: medio.
RLS: habilitada. Policies ver_mis_dirs, crear_dir, editar_dir, borrar_dir.
23. ordenes_servicio
Entidad central del marketplace: una solicitud de servicio. Mantiene la máquina de estados y los pines de cierre dual.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| cliente_id | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| prestador_id | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| servicio_id | UUID | No | — | FK a servicios(id) ON DELETE RESTRICT. |
— |
| direccion_id | UUID | No | — | FK a direcciones(id) ON DELETE RESTRICT. |
— |
| cupon_id | UUID | Sí | — | FK a cupones(id) ON DELETE SET NULL. |
— |
| estatus | estatus_orden | Sí | 'solicitada' |
Estado actual. | en_progreso |
| fecha_programada | TIMESTAMPTZ | No | — | Fecha objetivo. | — |
| notas_cliente | TEXT | Sí | — | Texto libre. | — |
| notas_prestador | TEXT | Sí | — | Texto libre. | — |
| monto_total | NUMERIC(10,2) | No | — | Monto cobrado. | 560.00 |
| descuento | NUMERIC(10,2) | Sí | 0 |
Descuento aplicado. | 40.00 |
| pin_cliente | VARCHAR(6) | Sí | — | PIN generado por trigger. | 483921 |
| pin_prestador | VARCHAR(6) | Sí | — | PIN generado por trigger. | 812345 |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
| updated_at | TIMESTAMPTZ | Sí | NOW() |
Última actualización. | — |
Restricciones: PK (id); FKs ya descritas.
Índices: idx_ord_cliente, idx_ord_prestador, idx_ord_estatus, idx_ord_fecha (fecha_programada DESC).
Triggers: trg_generar_pines_orden (BEFORE INSERT genera ambos PIN), trg_asignar_prestador_auto_after_insert (AFTER INSERT empareja prestador), trg_updated_at.
Volumen: alto (cientos de miles a millones).
RLS: habilitada. Policies cliente_ve_ordenes, prestador_ve_ordenes, admin_ve_ordenes, cliente_crea_orden, admin_edita_orden, ordenes_update_prestador.
24. historial_estatus_orden
Bitácora inmutable de transiciones de estatus de la orden, alimentada por los triggers de la máquina de estados.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| orden_id | UUID | No | — | FK a ordenes_servicio(id) ON DELETE CASCADE. |
— |
| estatus_anterior | estatus_orden | Sí | — | Estado previo. | solicitada |
| estatus_nuevo | estatus_orden | No | — | Estado nuevo. | asignada |
| cambiado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| nota | TEXT | Sí | — | Texto libre. | — |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Marca temporal. | — |
Restricciones: PK (id); FKs.
Índices: idx_hist_orden (orden_id).
Volumen: 4–7 filas por orden (alto agregado).
RLS: habilitada. Policies historial_select_participante, historial_insert_participante, admin_ve_historial.
25. evidencias_orden
Fotografías subidas por el prestador para evidenciar la ejecución del servicio.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| orden_id | UUID | No | — | FK a ordenes_servicio(id) ON DELETE CASCADE. |
— |
| url_foto | TEXT | No | — | URL del recurso. | — |
| subida_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
Restricciones: PK (id); FK descrita.
Índices: idx_evidencias_orden (orden_id).
Volumen: 0–10 por orden.
RLS: habilitada. Policies evidencias_select_participante, evidencias_select_admin, evidencias_insert_prestador, evidencias_delete_admin.
26. cargos_extra_orden
Cargos adicionales propuestos por el prestador durante la ejecución (materiales extra, tiempo adicional). Requieren aceptación o rechazo del cliente.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| orden_id | UUID | No | — | FK a ordenes_servicio(id) ON DELETE CASCADE. |
— |
| descripcion | TEXT | No | — | Descripción del cargo. | — |
| monto | NUMERIC(10,2) | No | — | Monto en MXN. | 150.00 |
| estatus | estatus_cargo_extra | No | 'propuesto' |
Estado. | aceptado |
| propuesto_por | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| resuelto_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| resuelto_at | TIMESTAMPTZ | Sí | — | Cuándo se resolvió. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
Restricciones: PK (id); CHECK (monto > 0); FKs.
Índices: idx_cargos_extra_orden (orden_id).
Volumen: 0–3 por orden.
RLS: habilitada. Policies cargos_extra_insert_prestador, cargos_extra_select_participante, cargos_extra_select_admin. Función resolver_cargo_extra aplica la lógica de aceptación.
27. pagos
Cobro al cliente. Una orden puede generar uno o más pagos (reintentos), pero la conciliación primaria es 1:1.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| orden_id | UUID | No | — | FK a ordenes_servicio(id) ON DELETE RESTRICT. |
— |
| monto | NUMERIC(10,2) | No | — | Monto cobrado. | 560.00 |
| metodo | metodo_pago | No | — | Método utilizado. | tarjeta |
| estatus | estatus_pago | Sí | 'pendiente' |
Estado del pago. | procesado |
| referencia_pasarela | TEXT | Sí | — | Identificador externo. | pi_3O… |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id); FK descrita.
Índices: idx_pago_orden (orden_id).
Volumen: alto.
RLS: habilitada. Policies ver_mis_pagos, admin_ve_pagos.
28. transacciones_prestador
Desglose de cada pago entre la parte que recibe el prestador y la comisión de la plataforma. Es la base del corte de pagos.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| orden_id | UUID | No | — | FK a ordenes_servicio(id) ON DELETE RESTRICT. |
— |
| prestador_id | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| pago_id | UUID | No | — | FK a pagos(id) ON DELETE RESTRICT. |
— |
| monto_prestador | NUMERIC(10,2) | No | — | Monto neto al prestador. | 476.00 |
| comision_plataforma | NUMERIC(10,2) | No | — | Monto retenido. | 84.00 |
| estatus_deposito | estatus_deposito | Sí | 'pendiente' |
Si ya se pagó al prestador. | depositado |
| referencia_bancaria | TEXT | Sí | — | SPEI / referencia. | — |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id); FKs.
Índices: idx_trans_prest (prestador_id).
Volumen: alto.
RLS: habilitada. Policies prestador_ve_trans, admin_ve_trans.
29. cortes_pago
Agrupación de transacciones por prestador en una fecha de corte (típicamente quincenal).
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| prestador_id | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| fecha_corte | DATE | No | — | Fecha de cierre. | — |
| fecha_deposito | DATE | Sí | — | Fecha real de depósito. | — |
| monto_total | NUMERIC(12,2) | No | — | Suma del corte. | — |
| num_transacciones | INT | Sí | 0 |
Cantidad incluida. | — |
| estatus | estatus_corte | Sí | 'generado' |
Ciclo. | depositado |
| referencia_bancaria | TEXT | Sí | — | Referencia. | — |
| aprobado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id); FKs.
Índices: idx_corte_prest (prestador_id).
Volumen: 24 cortes/año por prestador.
RLS: habilitada. Policies admin_ve_cortes, prestador_ve_cortes.
30. facturas
Facturas CFDI emitidas. Se asocian a una orden o a un corte de pagos.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| orden_id | UUID | Sí | — | FK a ordenes_servicio(id) ON DELETE SET NULL. |
— |
| corte_id | UUID | Sí | — | FK a cortes_pago(id) ON DELETE SET NULL. |
— |
| rfc_emisor | TEXT | No | — | RFC emisor. | — |
| rfc_receptor | TEXT | No | — | RFC receptor. | — |
| uuid_cfdi | TEXT | Sí | — | UUID CFDI 4.0. UNIQUE. | — |
| subtotal | NUMERIC(12,2) | No | — | Subtotal. | — |
| iva | NUMERIC(12,2) | No | — | IVA. | — |
| total | NUMERIC(12,2) | No | — | Total. | — |
| pdf_url | TEXT | Sí | — | URL del PDF. | — |
| xml_url | TEXT | Sí | — | URL del XML. | — |
| estatus | estatus_factura | Sí | 'timbrada' |
Estado. | cancelada |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Emisión. | — |
Restricciones: PK (id); UNIQUE (uuid_cfdi); FKs.
Índices: implícito.
Volumen: medio a alto.
RLS: habilitada. Policy admin_ve_facturas.
31. calificaciones
Valoración de 1 a 5 estrellas asociada a una orden, cruzada entre cliente y prestador.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| orden_id | UUID | No | — | FK a ordenes_servicio(id) ON DELETE CASCADE. |
— |
| calificador_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. Quien califica. |
— |
| calificado_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. Quien recibe. |
— |
| puntuacion | SMALLINT | No | — | Estrellas (1–5). | 5 |
| comentario | TEXT | Sí | — | Texto libre. | — |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id); UNIQUE (orden_id, calificador_id); CHECK (puntuacion BETWEEN 1 AND 5); FKs.
Índices: idx_calif_quien (calificado_id).
Volumen: hasta 2 por orden.
RLS: habilitada. Policies leer_califs (todos), crear_calif (solo el calificador).
32. notificaciones
Bandeja de notificaciones por usuario. Puede consumirse de forma asíncrona por canal técnico (push/sms/email).
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| usuario_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| tipo | tipo_notif | No | — | Canal técnico. | push |
| titulo | TEXT | No | — | Título. | — |
| cuerpo | TEXT | Sí | — | Cuerpo. | — |
| canal | canal_notif | Sí | 'sistema' |
Categoría lógica. | orden |
| leida | BOOLEAN | Sí | FALSE |
Marca de lectura. | FALSE |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id); FK descrita.
Índices: idx_notif_user, idx_notif_no_leidas (usuario_id, leida) WHERE leida = FALSE.
Volumen: alto.
RLS: habilitada. Policies ver_mis_notifs, marcar_leida.
33. tickets_soporte
Ticket de soporte (versión consolidada con campos ITIL). Discrimina por tipo (incidente, solicitud, problema, cambio) y mantiene tier actual y grupo asignado. Soporta autorreferencia para vincular incidentes recurrentes a un problema raíz.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| usuario_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| orden_id | UUID | Sí | — | FK a ordenes_servicio(id) ON DELETE SET NULL. |
— |
| agente_id | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| categoria | cat_ticket | No | — | Categoría base. | cobro_incorrecto |
| prioridad | prioridad_ticket | Sí | 'media' |
Prioridad operativa. | alta |
| estatus | estatus_ticket | Sí | 'abierto' |
Estatus v1. | — |
| asunto | TEXT | No | — | Asunto del ticket. | — |
| tipo | tipo_ticket | No | 'incidente' |
Discriminador ITIL. | problema |
| tier_actual | tier_soporte | No | 'l1' |
Tier vigente. | l2 |
| grupo_asignado | TEXT | No | — | Grupo lógico (soporte_l1, etc.). |
— |
| resolucion_codigo | codigo_resolucion | Sí | — | Código de cierre. | kb_resuelto |
| resolucion_notas | TEXT | Sí | — | Notas de cierre (≥10 chars). | — |
| cerrado_at | TIMESTAMPTZ | Sí | — | Fecha de cierre. | — |
| cerrado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| problem_id | UUID | Sí | — | Self-FK a tickets_soporte(id). |
— |
| workaround_md | TEXT | Sí | — | Solo tipo='problema'. Markdown del workaround. |
— |
| causa_raiz_md | TEXT | Sí | — | Solo tipo='problema'. RCA. |
— |
| fix_permanente_md | TEXT | Sí | — | Solo tipo='problema'. Plan de fix. |
— |
| es_major_incident | BOOLEAN | No | FALSE |
Flag MIM. | — |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
| updated_at | TIMESTAMPTZ | Sí | NOW() |
Actualización. | — |
Restricciones: PK (id); FKs descritas; CHECK chk_problem_fields_only_for_problem (los campos workaround_md/causa_raiz_md/fix_permanente_md solo se llenan si tipo='problema'); CHECK chk_resolucion_required_when_closed (al cerrar/resolver, código y notas obligatorios); CHECK chk_problem_no_self (no autorreferenciarse).
Índices: idx_tkt_user, idx_tkt_agente, idx_tkt_status, idx_tickets_tipo_estatus, idx_tickets_tier_grupo, idx_tickets_problem parcial, idx_tickets_major_incident parcial, idx_tickets_grupo_estatus.
Volumen: medio a alto.
RLS: habilitada. Policies ver_mis_tickets, agente_ve_tickets, admin_ve_tickets, crear_ticket.
34. mensajes_ticket
Hilo de mensajes asociados a un ticket. Soporta mensajes internos (no visibles al cliente) y referencias a respuestas predefinidas (canned_responses).
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| ticket_id | UUID | No | — | FK a tickets_soporte(id) ON DELETE CASCADE. |
— |
| autor_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| tipo_autor | tipo_autor_msg | No | — | Tipo lógico del autor. | agente |
| contenido | TEXT | No | — | Cuerpo del mensaje. | — |
| adjunto_url | TEXT | Sí | — | URL adjunto. | — |
| es_interno | BOOLEAN | No | FALSE |
Visible solo a agentes. | — |
| canned_response_id | UUID | Sí | — | FK a canned_responses(id) ON DELETE SET NULL. |
— |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id); FKs descritas (la FK a canned_responses se añade después por dependencia diferida).
Índices: idx_msg_tkt (ticket_id), idx_mensajes_ticket_visible (ticket_id, es_interno, created_at).
Volumen: alto.
RLS: habilitada. Policies leer_msgs, admin_lee_msgs, escribir_msg.
35. reembolsos
Solicitudes de reembolso vinculadas a un pago. Pueden originarse desde un ticket.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| pago_id | UUID | No | — | FK a pagos(id) ON DELETE RESTRICT. |
— |
| ticket_id | UUID | Sí | — | FK a tickets_soporte(id) ON DELETE SET NULL. |
— |
| monto | NUMERIC(10,2) | No | — | Monto a reembolsar. | — |
| motivo | TEXT | No | — | Texto libre. | — |
| aprobado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| estatus | estatus_reembolso | Sí | 'solicitado' |
Estado. | procesado |
| referencia_pasarela | TEXT | Sí | — | Identificador externo. | — |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Alta. | — |
Restricciones: PK (id); FKs descritas.
Índices: implícito.
Volumen: medio.
RLS: habilitada. Policy admin_ve_reembolsos.
36. pins_soporte
PIN persistente del administrador (un PIN por admin) para abrir accesos break-glass a perfiles de usuario. Soporta bloqueo tras intentos fallidos.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| admin_id | UUID | No | — | PK y FK 1:1 a usuarios(id) ON DELETE CASCADE. |
— |
| pin_hash | TEXT | No | — | Hash bcrypt del PIN. | — |
| intentos_fallidos | INTEGER | No | 0 |
Contador de fallos consecutivos. | — |
| bloqueado_hasta | TIMESTAMPTZ | Sí | — | Si está bloqueado, hasta cuándo. | — |
| rotado_en | TIMESTAMPTZ | No | NOW() |
Última rotación. | — |
| rotado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
Restricciones: PK (admin_id); FKs.
Índices: implícito.
Volumen: bajo (1 por admin).
RLS: habilitada. Policy pins_soporte_select_propio (sólo el dueño).
37. accesos_perfil_usuario
Acceso temporal break-glass: registro inmutable de cuándo un admin abrió un perfil de usuario, con motivo, IP, user agent y caducidad.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| admin_id | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| usuario_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| motivo | TEXT | No | — | Texto justificativo (≥10 chars). | — |
| expira_en | TIMESTAMPTZ | No | — | Caducidad. | — |
| revocado_en | TIMESTAMPTZ | Sí | — | Revocación. | — |
| ip_address | INET | Sí | — | IP origen. | — |
| user_agent | TEXT | Sí | — | UA del navegador. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
Restricciones: PK (id); FKs; CHECK (length(btrim(motivo)) >= 10).
Índices: idx_accesos_admin_activo (admin_id, expira_en) WHERE revocado_en IS NULL, idx_accesos_usuario.
Volumen: medio.
RLS: habilitada. Policy accesos_select_propio_o_super.
38. pins_soporte_cliente
PIN one-shot generado por el cliente desde su app móvil para autorizar al agente a abrir su perfil. Caduca a los 15 minutos por defecto.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| cliente_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| pin_hash | TEXT | No | — | Hash bcrypt del PIN. | — |
| generado_en | TIMESTAMPTZ | No | NOW() |
Generación. | — |
| expira_en | TIMESTAMPTZ | No | NOW() + INTERVAL '15 minutes' |
Caducidad. | — |
| usado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| usado_en | TIMESTAMPTZ | Sí | — | Cuándo se consumió. | — |
Restricciones: PK (id); FKs.
Índices: idx_pins_soporte_cliente (cliente_id) WHERE usado_en IS NULL, idx_pins_soporte_vigentes (expira_en) WHERE usado_en IS NULL.
Volumen: efímero.
RLS: habilitada (sin policies abiertas; acceso vía funciones SECURITY DEFINER).
39. casos_soporte_abiertos
Caso vigente que prueba que un agente está autorizado a operar sobre un cliente vía PIN. Caduca a las 4 horas y se asocia opcionalmente a un ticket.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| agente_id | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| cliente_id | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| pin_id | UUID | No | — | FK a pins_soporte_cliente(id) ON DELETE RESTRICT. |
— |
| ticket_id | UUID | Sí | — | FK a tickets_soporte(id) ON DELETE SET NULL. |
— |
| abierto_en | TIMESTAMPTZ | No | NOW() |
Apertura. | — |
| expira_en | TIMESTAMPTZ | No | NOW() + INTERVAL '4 hours' |
Caducidad. | — |
| cerrado_en | TIMESTAMPTZ | Sí | — | Cierre manual. | — |
| motivo_cierre | TEXT | Sí | — | Razón. | — |
| notas | TEXT | Sí | — | Notas. | — |
Restricciones: PK (id); FKs.
Índices: idx_casos_soporte_agente_activo (agente_id, expira_en) WHERE cerrado_en IS NULL, idx_casos_soporte_cliente, idx_caso_ticket (ticket_id) WHERE ticket_id IS NOT NULL.
Volumen: medio.
RLS: habilitada (policies a nivel función).
40. escalation_log_ticket
Bitácora de escalamientos entre tiers. Fuerza una hipótesis textual mínima de 20 caracteres y la lista de KB consultados.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| ticket_id | UUID | No | — | FK a tickets_soporte(id) ON DELETE CASCADE. |
— |
| from_tier | tier_soporte | No | — | Tier de origen. | l1 |
| to_tier | tier_soporte | No | — | Tier destino. | l2 |
| motivo | escalation_motivo | No | — | Motivo. | requiere_dev |
| hipotesis | TEXT | No | — | Hipótesis. | — |
| kb_consultados | UUID[] | No | '{}' |
KB revisados. | — |
| from_user | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| to_grupo | TEXT | No | — | Grupo destino. | — |
| to_user | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| ocurrido_at | TIMESTAMPTZ | No | NOW() |
Marca temporal. | — |
Restricciones: PK (id); CHECK (length(hipotesis) >= 20); FKs.
Índices: idx_escalation_ticket (ticket_id, ocurrido_at DESC).
Volumen: bajo a medio.
RLS: habilitada (policies de defense-in-depth, lógica en aplicación).
41. sla_calendars
Calendarios laborales (horarios y festivos) que alimentan el cálculo de los SLA.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| nombre | TEXT | No | — | Nombre único. | CDMX_lun_vie_9_18 |
| timezone | TEXT | No | 'America/Mexico_City' |
Zona horaria. | — |
| config_jsonb | JSONB | No | — | Estructura {mon:[{start,end}], holidays:[...]}. |
— |
| activo | BOOLEAN | No | TRUE |
Vigente. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
| updated_at | TIMESTAMPTZ | No | NOW() |
Actualización. | — |
Restricciones: PK (id); UNIQUE (nombre).
Índices: implícito.
Volumen: muy bajo.
RLS: habilitada. Policies sla_cal_select, sla_cal_mutate.
42. sla_policies
Políticas SLA por combinación tipo+prioridad+categoría con tiempos First Response (FRT) y Time To Resolve (TTR).
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| nombre | TEXT | No | — | Nombre único. | incident_critica |
| tipo | tipo_ticket | No | — | Tipo ITIL. | incidente |
| prioridad | prioridad_ticket | No | — | Prioridad. | critica |
| categoria | cat_ticket | Sí | — | Filtro opcional por categoría. | — |
| frt_minutos | INTEGER | No | — | Tiempo objetivo de primera respuesta. | 15 |
| ttr_minutos | INTEGER | No | — | Tiempo objetivo de resolución. | 240 |
| business_hours_only | BOOLEAN | No | TRUE |
Si solo cuenta horario laboral. | — |
| calendar_id | UUID | Sí | — | FK a sla_calendars(id) ON DELETE RESTRICT. |
— |
| activo | BOOLEAN | No | TRUE |
Vigente. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
| updated_at | TIMESTAMPTZ | No | NOW() |
Actualización. | — |
Restricciones: PK (id); UNIQUE (nombre); CHECK (frt_minutos > 0); CHECK (ttr_minutos > 0); FK descrita.
Índices: idx_sla_policies_match (tipo, prioridad, categoria, activo) WHERE activo = TRUE.
Volumen: bajo (≈ 12 reglas seed).
RLS: habilitada. Policies sla_pol_select, sla_pol_mutate.
43. ticket_sla_state
Estado SLA por ticket (1:1). Calcula breaches automáticos vía columnas generadas y soporta pausas.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| ticket_id | UUID | No | — | PK y FK 1:1 a tickets_soporte(id) ON DELETE CASCADE. |
— |
| policy_id | UUID | No | — | FK a sla_policies(id) ON DELETE RESTRICT. |
— |
| frt_due_at | TIMESTAMPTZ | No | — | Vencimiento FRT. | — |
| ttr_due_at | TIMESTAMPTZ | No | — | Vencimiento TTR. | — |
| primer_respuesta_at | TIMESTAMPTZ | Sí | — | Cuándo respondió un agente por primera vez. | — |
| resuelto_at | TIMESTAMPTZ | Sí | — | Cuándo se resolvió. | — |
| paused_since | TIMESTAMPTZ | Sí | — | Pausa actual (espera al cliente). | — |
| paused_total_secs | INTEGER | No | 0 |
Acumulado de pausas. | — |
| notified_50 | BOOLEAN | No | FALSE |
Notificación al 50% del SLA. | — |
| notified_80 | BOOLEAN | No | FALSE |
Notificación al 80%. | — |
| notified_100 | BOOLEAN | No | FALSE |
Notificación de breach. | — |
| breached_frt | BOOLEAN | — | GENERATED | TRUE si la primera respuesta llegó tarde. |
— |
| breached_ttr | BOOLEAN | — | GENERATED | TRUE si la resolución llegó tarde. |
— |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
| updated_at | TIMESTAMPTZ | No | NOW() |
Actualización. | — |
Restricciones: PK (ticket_id); FKs; CHECK (paused_total_secs >= 0).
Índices: idx_sla_state_frt_pending, idx_sla_state_ttr_pending, idx_sla_state_notify_pending.
Volumen: 1 por ticket.
RLS: habilitada. Policies sla_state_select, sla_state_mutate.
44. kb_articles
Artículos de la base de conocimiento. Multilingüe (tsvector spanish), versionados, con audiencia segmentada y métricas de utilidad.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| slug | TEXT | No | — | Slug humano único. | como-cancelar-orden |
| titulo | TEXT | No | — | Título. | — |
| contenido_md | TEXT | No | — | Cuerpo Markdown. | — |
| resumen | TEXT | Sí | — | Resumen breve. | — |
| categoria | cat_ticket | Sí | — | Categoría base. | — |
| tipo_aplica | tipo_ticket[] | No | '{}' |
Tipos a los que aplica. | {incidente,solicitud} |
| audiencia | audiencia_kb[] | No | '{cliente,agente_l1,agente_l2_l3}' |
Audiencias. | — |
| tier_minimo | tier_soporte | No | 'l1' |
Tier mínimo. | — |
| publicado | BOOLEAN | No | FALSE |
Publicado al público interno/externo. | — |
| version | INTEGER | No | 1 |
Versión correlativa. | — |
| view_count | INTEGER | No | 0 |
Contador de vistas (denormalizado). | — |
| helpful_count | INTEGER | No | 0 |
Contador de pulgar arriba. | — |
| not_helpful_count | INTEGER | No | 0 |
Contador de pulgar abajo. | — |
| autor_id | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| publicado_en | TIMESTAMPTZ | Sí | — | Cuándo se publicó. | — |
| search_vector | tsvector | — | GENERATED | Índice de búsqueda con pesos A>B>C. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
| updated_at | TIMESTAMPTZ | No | NOW() |
Actualización. | — |
Restricciones: PK (id); UNIQUE (slug); CHECK (version >= 1); CHECK (view_count >= 0); CHECK (helpful_count >= 0); CHECK (not_helpful_count >= 0); FK descrita.
Índices: idx_kb_search GIN(search_vector), idx_kb_published (publicado, categoria) WHERE publicado, idx_kb_slug, idx_kb_audiencia GIN(audiencia), idx_kb_tipo_aplica GIN(tipo_aplica).
Volumen: medio (cientos a miles de artículos).
RLS: habilitada. Policies kb_select, kb_mutate.
45. kb_article_history
Historial de versiones de artículos KB. Una fila por versión publicada.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| article_id | UUID | No | — | FK a kb_articles(id) ON DELETE CASCADE. |
— |
| version | INTEGER | No | — | Número de versión. | — |
| titulo | TEXT | No | — | Título en esa versión. | — |
| contenido_md | TEXT | No | — | Cuerpo en esa versión. | — |
| resumen | TEXT | Sí | — | Resumen. | — |
| modificado_por | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| modificado_at | TIMESTAMPTZ | No | NOW() |
Cuándo se modificó. | — |
Restricciones: PK (id); UNIQUE (article_id, version); FKs.
Índices: idx_kb_history_article (article_id, version DESC).
Volumen: medio.
RLS: habilitada. Policy kb_hist_select.
46. kb_views
Eventos de visualización de un artículo KB. Permite calcular tasa de deflexión (KB resolvió sin abrir ticket).
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| article_id | UUID | No | — | FK a kb_articles(id) ON DELETE CASCADE. |
— |
| viewer_user_id | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| ticket_id | UUID | Sí | — | FK a tickets_soporte(id) ON DELETE SET NULL. |
— |
| session_id | TEXT | Sí | — | Sesión anónima. | — |
| helpful | BOOLEAN | Sí | — | Voto al final del artículo. | — |
| deflected | BOOLEAN | Sí | — | Si evitó la apertura del ticket. | — |
| viewed_at | TIMESTAMPTZ | No | NOW() |
Marca temporal. | — |
Restricciones: PK (id); FKs.
Índices: idx_kb_views_article (article_id, viewed_at DESC), idx_kb_views_ticket (ticket_id) WHERE ticket_id IS NOT NULL.
Volumen: alto.
RLS: habilitada. Policies kb_views_insert, kb_views_select.
47. csat_surveys
Encuestas CSAT/CES emitidas al cliente al cerrarse un ticket. Se permite una encuesta por ticket (UNIQUE).
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| ticket_id | UUID | No | — | FK a tickets_soporte(id) ON DELETE CASCADE. |
— |
| cliente_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| agente_id | UUID | Sí | — | FK a usuarios(id) ON DELETE SET NULL. |
— |
| estado | estado_csat | No | 'pendiente' |
Ciclo. | respondido |
| csat_score | INTEGER | Sí | — | Puntaje 1–5. | 5 |
| ces_score | INTEGER | Sí | — | Customer Effort Score 1–7. | — |
| comentario | TEXT | Sí | — | Texto libre. | — |
| enviado_at | TIMESTAMPTZ | Sí | — | Cuándo se envió. | — |
| respondido_at | TIMESTAMPTZ | Sí | — | Cuándo se respondió. | — |
| expira_at | TIMESTAMPTZ | No | — | Caducidad (7 días por norma). | — |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
Restricciones: PK (id); CHECK (csat_score BETWEEN 1 AND 5); CHECK (ces_score BETWEEN 1 AND 7); FKs.
Índices: UNIQUE idx_csat_ticket (ticket_id), idx_csat_pending, idx_csat_cliente, idx_csat_agente.
Volumen: 1 por ticket cerrado.
RLS: habilitada. Policies csat_select, csat_update_cliente, csat_insert.
48. major_incidents
Major Incidents declarados (MIM workflow). Llevan timeline público y exigen pir_url para cerrar.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| titulo | TEXT | No | — | Título. | — |
| descripcion | TEXT | No | — | Descripción inicial. | — |
| estado | estado_mim | No | 'declarado' |
Ciclo. | mitigando |
| declarado_por | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| declarado_at | TIMESTAMPTZ | No | NOW() |
Marca de declaración. | — |
| mitigado_at | TIMESTAMPTZ | Sí | — | Mitigación efectiva. | — |
| resuelto_at | TIMESTAMPTZ | Sí | — | Resolución. | — |
| pir_url | TEXT | Sí | — | Post-Incident Review (obligatorio para cerrar). | — |
| servicios_afectados | TEXT[] | No | '{}' |
Lista de servicios. | — |
| zonas_afectadas | UUID[] | No | '{}' |
Lista de IDs de zona. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
| updated_at | TIMESTAMPTZ | No | NOW() |
Actualización. | — |
Restricciones: PK (id); FK descrita.
Índices: idx_mim_estado_activos parcial, idx_mim_declarado_at.
Volumen: bajo.
RLS: habilitada. Policies mim_select, mim_mutate.
49. major_incident_updates
Updates publicados durante un Major Incident para alimentar el timeline público.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| major_incident_id | UUID | No | — | FK a major_incidents(id) ON DELETE CASCADE. |
— |
| contenido_md | TEXT | No | — | Cuerpo Markdown. | — |
| estado_en_momento | estado_mim | No | — | Estado del MIM en ese momento. | — |
| publicado_por | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| publicado_at | TIMESTAMPTZ | No | NOW() |
Marca. | — |
Restricciones: PK (id); FKs.
Índices: idx_mim_update (major_incident_id, publicado_at DESC).
Volumen: medio (varios por MIM).
RLS: habilitada. Policies mim_upd_select, mim_upd_insert.
50. ticket_major_incident_link
Tabla asociativa que vincula un ticket con un Major Incident, con auditoría de quién y cuándo. Tiene PK compuesta.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| ticket_id | UUID | No | — | FK a tickets_soporte(id) ON DELETE CASCADE. |
— |
| major_incident_id | UUID | No | — | FK a major_incidents(id) ON DELETE CASCADE. |
— |
| vinculado_at | TIMESTAMPTZ | No | NOW() |
Marca. | — |
| vinculado_por | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
Restricciones: PRIMARY KEY (ticket_id, major_incident_id); FKs.
Índices: idx_tmim_mim (major_incident_id).
Volumen: bajo.
RLS: habilitada. Policies tmim_select, tmim_mutate.
51. canned_responses
Plantillas de respuestas predefinidas para agentes. Soportan variables interpoladas ({{cliente.nombre}}).
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| slug | TEXT | No | — | Slug único. | — |
| titulo | TEXT | No | — | Título visible. | — |
| contenido_md | TEXT | No | — | Cuerpo Markdown con variables. | — |
| categoria | cat_ticket | Sí | — | Filtro categoría. | — |
| tipo_aplica | tipo_ticket[] | No | '{}' |
Tipos a los que aplica. | — |
| variables_disponibles | TEXT[] | No | '{cliente.nombre,orden.id,agente.nombre}' |
Lista de variables permitidas. | — |
| scope_grupo | TEXT | Sí | — | Grupo (soporte_l1, etc.) que puede usarla. |
— |
| uso_count | INTEGER | No | 0 |
Contador de uso. | — |
| activo | BOOLEAN | No | TRUE |
Vigente. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
Alta. | — |
| updated_at | TIMESTAMPTZ | No | NOW() |
Actualización. | — |
Restricciones: PK (id); UNIQUE (slug); CHECK (uso_count >= 0).
Índices: idx_canned_categoria, idx_canned_scope, idx_canned_tipo GIN(tipo_aplica).
Volumen: bajo a medio.
RLS: habilitada. Policies canned_select, canned_mutate.
52. logs_auditoria
Bitácora central de auditoría del backoffice. Cada acción admin se almacena con valor previo y nuevo (JSONB) y opcionalmente se correlaciona con caso o ticket.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| admin_id | UUID | No | — | FK a usuarios(id) ON DELETE RESTRICT. |
— |
| accion | TEXT | No | — | Verbo en pasado o slug. | usuario.restringir |
| entidad | TEXT | No | — | Nombre lógico. | usuarios |
| entidad_id | UUID | Sí | — | ID de la entidad. | — |
| valor_anterior | JSONB | Sí | — | Snapshot previo. | — |
| valor_nuevo | JSONB | Sí | — | Snapshot nuevo. | — |
| ip_address | INET | Sí | — | IP origen. | — |
| user_agent | TEXT | Sí | — | UA del navegador. | — |
| caso_id | UUID | Sí | — | FK a casos_soporte_abiertos(id) ON DELETE SET NULL. |
— |
| ticket_id | UUID | Sí | — | FK a tickets_soporte(id) ON DELETE SET NULL. |
— |
| created_at | TIMESTAMPTZ | Sí | NOW() |
Marca temporal. | — |
Restricciones: PK (id); FKs.
Índices: idx_log_admin, idx_log_fecha (created_at DESC), idx_log_caso (caso_id) WHERE caso_id IS NOT NULL, idx_log_ticket (ticket_id) WHERE ticket_id IS NOT NULL.
Volumen: alto (cada acción admin escribe una fila).
RLS: habilitada. Policy admin_ve_logs.
53. pagos (extension migracion 007)
Columnas adicionales en pagos para integración Stripe (PaymentIntent + webhook como fuente de verdad). Ver descripción base en sección de pagos.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| payment_intent_id | TEXT | Sí | — | ID pi_… de Stripe. UNIQUE parcial cuando NOT NULL. |
pi_3ABC123def456 |
| customer_id_pasarela | TEXT | Sí | — | ID cus_… de Stripe (denormalizado para queries de soporte). |
cus_NfHAH123 |
| webhook_received_at | TIMESTAMPTZ | Sí | — | Marca temporal del último webhook procesado para este pago. | — |
| raw_status | TEXT | Sí | — | Estado crudo de Stripe (requires_payment_method, succeeded, canceled, etc) para depuración. |
succeeded |
Índices: uq_pagos_payment_intent (payment_intent_id) WHERE payment_intent_id IS NOT NULL, idx_pagos_customer_pasarela (customer_id_pasarela).
RLS: hereda la del registro original.
54. pagos_metodos_guardados
Métodos de pago guardados por usuario (flujo Stripe SetupIntent). Permite cobros 1-tap en pagos posteriores sin volver a pedir CVV.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| usuario_id | UUID | No | — | FK a usuarios(id) ON DELETE CASCADE. |
— |
| payment_method_id | TEXT | No | — | ID pm_… de Stripe. UNIQUE. |
pm_1Abc23xyz |
| brand | TEXT | Sí | — | Marca de tarjeta. | visa |
| last4 | TEXT | Sí | — | Últimos 4 dígitos. | 4242 |
| exp_month | SMALLINT | Sí | — | Mes de expiración. | 12 |
| exp_year | SMALLINT | Sí | — | Año de expiración. | 2027 |
| predeterminado | BOOLEAN | No | false |
Marca el método por defecto del cliente. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
— | — |
| deleted_at | TIMESTAMPTZ | Sí | — | Soft delete cuando se desadjunta de Stripe. | — |
Restricciones: PK (id); uq_metodo_pasarela UNIQUE (payment_method_id); FK ON DELETE CASCADE.
Índices: idx_metodos_usuario (usuario_id) WHERE deleted_at IS NULL.
RLS: habilitada. Policy ver_mis_metodos: usuario_id = (SELECT auth_uid()) AND deleted_at IS NULL.
55. webhook_events
Tabla de idempotencia y bitácora de eventos de webhook entrantes. Garantiza que cada event.id de Stripe (o futuros proveedores) se procese una sola vez.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| id | UUID | No | gen_random_uuid() |
PK. | — |
| proveedor | TEXT | No | — | Origen del evento. | stripe, facturama |
| external_id | TEXT | No | — | ID del evento en el proveedor. | evt_1Abc23 |
| event_type | TEXT | No | — | Tipo del evento. | payment_intent.succeeded |
| payload | JSONB | No | — | Cuerpo del evento completo (auditoría). | — |
| processed_at | TIMESTAMPTZ | Sí | — | Marca temporal cuando el dispatch terminó sin error. | — |
| error | TEXT | Sí | — | Mensaje del último error, si lo hubo. | — |
| retry_count | INT | No | 0 |
Veces que el dispatch falló y se reintentó. | — |
| created_at | TIMESTAMPTZ | No | NOW() |
— | — |
Restricciones: PK (id); uq_webhook_event UNIQUE (proveedor, external_id) — clave de idempotencia.
Índices: idx_webhook_proveedor_type, idx_webhook_unprocessed (created_at) WHERE processed_at IS NULL.
RLS: habilitada. Policy admin_ve_webhook_events: solo administradores ven la tabla.
56. facturas (extension migracion 007)
Columnas adicionales en facturas para CFDI 4.0 vía PAC (Facturama sandbox). El schema está listo; la emisión automática y la solicitud con RFC son funcionalidades de Phase 5–7 del plan de pagos/facturación, aún no implementadas.
| Columna | Tipo | Nullable | Default | Descripción | Ejemplo |
|---|---|---|---|---|---|
| solicitada_por | UUID | Sí | — | FK a usuarios(id). NULL si emisión automática (público en general). |
— |
| uso_cfdi | TEXT | Sí | — | Catálogo SAT. | G03, S01 |
| forma_pago | TEXT | Sí | — | Catálogo SAT. | 01-Tarjeta, 03-Transferencia |
| metodo_pago_sat | TEXT | Sí | — | PUE (pago en una exhibición) o PPD (pago en parcialidades). |
PUE |
| serie | TEXT | Sí | — | Serie del comprobante. | A |
| folio | TEXT | Sí | — | Folio interno. | 0042 |
| pac_proveedor | TEXT | Sí | — | PAC que timbró. | facturama |
| pac_referencia | TEXT | Sí | — | ID interno del PAC para cancelaciones. | — |
| cancelada_at | TIMESTAMPTZ | Sí | — | Marca temporal de cancelación. | — |
| cancelada_motivo | TEXT | Sí | — | Motivo SAT (01–04). | 01 |
| xml_contenido | TEXT | Sí | — | Base64 del XML timbrado (TEST). En PROD irá a object store. | — |
| pdf_contenido | TEXT | Sí | — | Base64 del PDF (TEST). | — |
ENUM estatus_factura extendido: añade pendiente_timbrado y fallida.
Resumen de cobertura
- Total de tablas documentadas: 56 (49 del dominio aplicativo +
auth.users+ 2 vistas asociativas + 4 entradas de extensiones/tablas migración 007). - Esquemas:
publicyauth. - Tablas con RLS habilitado: 49 (todas excepto las internas de credenciales y tokens transitorios; las nuevas
pagos_metodos_guardadosywebhook_eventstambién la tienen). - Total de FOREIGN KEYs documentadas: 89+.
- Total de CHECK constraints documentados: 21+.
- Total de índices documentados: 56+.
- Total de tipos enumerados: 28 (ENUM
estatus_facturaextendido en migración 007).
Fuentes consultadas
expressmx/docs/architecture/schema-consolidated.sql(líneas 1–2179).expressmx/00.sql(1478 líneas).expressmx/migrations/001_auth_credentials_and_reset.sql.expressmx/migrations/002_fix_usuarios_uuid_default.sql.expressmx/migrations/003_pins_soporte_cliente.sql.expressmx/migrations/004_rbac_permisos_zero_trust.sql.expressmx/migrations/005_audit_correlacion.sql.expressmx/migrations/006_support_itsm.sql.expressmx/migrations/007_pagos_facturas_extensions.sql.expressmx/.planning/architecture-pagos-cfdi.md.expressmx/.planning/research/case-study-validation-report.md.