' ===================================================================== ' Express MX — Modelo Entidad-Relación (notación de Chen) ' ===================================================================== ' Complemento académico al modelo conceptual `database-er-conceptual.md` ' y al schema físico `schema-consolidated.sql`. ' ' Cada bloque @startchen ... @endchen genera un diagrama independiente. ' Renderizar todo a PNG: ' plantuml database-er-chen.puml ' Renderizar uno solo: ' plantuml -SuseSubChart=true database-er-chen.puml \ ' -filename "expressmx-er-{name}" ' ' Convenciones de notación (según GH-945 y GH-1718 de PlantUML): ' entity X { } entidad fuerte ' entity X <> { } entidad débil (rectángulo doble) ' relationship R { } relación (rombo) ' relationship R <> { } relación identificadora ' attr <> clave primaria (subrayado) ' attr <> atributo derivado (óvalo punteado) ' attr <> atributo multivaluado (óvalo doble) ' nombre { sub1 sub2 } atributo compuesto ' R -1- E cardinalidad 1, participación parcial ' R =1= E cardinalidad 1, participación total ' R -N- E cardinalidad N ' R -(0,1)- E rango de cardinalidad (min,max) ' A ->- B B es subclase de A ' A ->- d { B, C } especialización disjunta ' A ->- o { B, C } especialización con superposición ' A ->- U { B, C } unión / categoría ' ' Clasificación cuantitativa cubierta: ' - 26 entidades fuertes ' - 20 entidades débiles ' - 6 entidades asociativas ' - 1 auto-relación (tickets_soporte: problema_padre) ' ===================================================================== ' --------------------------------------------------------------------- ' Diagrama 1 — Vista global (núcleo operativo) ' --------------------------------------------------------------------- ' Sólo entidades fuertes principales y sus relaciones de mayor peso. ' Pensado para presentación ejecutiva: 14 entidades, 1 página. @startchen vista_global title ExpressMX — Vista global del modelo conceptual skinparam nodesep 25 skinparam ranksep 45 skinparam shadowing false skinparam defaultFontSize 12 hide circle ' Solo el nucleo operativo: 8 entidades fuertes y sus relaciones primarias. ' RBAC, soporte, finanzas y zero-trust se detallan en diagramas dedicados. entity "Usuario" as USUARIO { id <> nombre { nombres apellidos } email rol curp } entity "Categoria" as CATEGORIA { id <> nombre } entity "Servicio" as SERVICIO { id <> nombre precio_base } entity "Direccion" as DIRECCION { id <> domicilio { calle cp ciudad } } entity "Orden de Servicio" as ORDEN { folio <> fecha_programada estatus monto_total <> } entity "Pago" as PAGO { id <> monto metodo estatus } entity "Calificacion" as CALIFICACION { id <> puntuacion comentario } entity "Ticket" as TICKET { folio <> prioridad estatus tier_actual } ' Relaciones binarias del nucleo relationship "clasifica" as CLASIFICA { } relationship "ofrece" as OFRECE { precio_personalizado } relationship "reside_en" as RESIDE { } relationship "solicita" as SOLICITA { } relationship "atiende" as ATIENDE { } relationship "es_de" as ES_DE { } relationship "se_entrega_en" as ENTREGA { } relationship "paga" as PAGA { } relationship "califica" as CALIF_A { } relationship "es_calificado" as CALIF_EN { } relationship "sobre" as SOBRE { } relationship "reporta" as REPORTA { } relationship "originada" as ORIG_TICKET { } ' Catalogo CATEGORIA -1- CLASIFICA CLASIFICA -N- SERVICIO SERVICIO -N- OFRECE OFRECE -N- USUARIO ' Direccion USUARIO -1- RESIDE RESIDE -N- DIRECCION ' Operacion de ordenes USUARIO -1- SOLICITA SOLICITA =N= ORDEN USUARIO -1- ATIENDE ATIENDE -N- ORDEN SERVICIO -1- ES_DE ES_DE =N= ORDEN DIRECCION -1- ENTREGA ENTREGA =N= ORDEN ' Pagos ORDEN =1= PAGA PAGA -N- PAGO ' Calificaciones (relacion ternaria via entidad asociativa) USUARIO -1- CALIF_A CALIF_A -N- CALIFICACION USUARIO -1- CALIF_EN CALIF_EN -N- CALIFICACION ORDEN -1- SOBRE SOBRE -N- CALIFICACION ' Soporte USUARIO -1- REPORTA REPORTA =N= TICKET ORDEN -1- ORIG_TICKET ORIG_TICKET -N- TICKET @endchen ' --------------------------------------------------------------------- ' Diagrama 2 — Identidad, credenciales y RBAC ' --------------------------------------------------------------------- ' Cubre: usuarios + débil de credenciales + tokens + RBAC con asociativas ' Subclases: usuarios -> {cliente, prestador, admin} disjunta. @startchen identidad_rbac title Identidad y Control de Acceso (RBAC Zero Trust) skinparam nodesep 25 skinparam ranksep 45 skinparam shadowing false skinparam defaultFontSize 12 hide circle entity "Usuario" as USUARIO { id <> nombre { nombres apellidos } email telefono curp fecha_nacimiento rol activo foto } entity "Credenciales" as CREDS <> { password_hash fecha_actualizacion } entity "Token Reset Password" as TOKEN <> { token <> expira_en usado } entity "Rol Admin" as ROL_ADMIN { id <> clave nombre descripcion } entity "Permiso" as PERMISO { id <> clave descripcion dominio } entity "Asignacion Rol" as USR_ROL { id <> activo fecha_asignacion } entity "Concesion Permiso" as ROL_PERM { id <> } entity "Agencia" as AGENCIA { id <> nombre ciudad estado } ' Subclases del usuario entity "Cliente" as CLIENTE { } entity "Prestador" as PRESTADOR { calificacion_promedio <> ordenes_completadas <> } entity "Administrador" as ADMIN { } USUARIO ->- d { CLIENTE, PRESTADOR, ADMIN } ' Relaciones relationship "posee_credenciales" as POSEE { } relationship "solicita_reset" as SOL_RESET { } relationship "asume" as ASUME { } relationship "concedido_a" as CONC_A { } relationship "incluye" as INCLUYE { } relationship "agrupa" as AGRUPA { } relationship "opera_en" as OPERA { } ' Cardinalidades USUARIO =1= POSEE POSEE -1- CREDS USUARIO -1- SOL_RESET SOL_RESET -N- TOKEN ADMIN -1- ASUME ASUME -N- USR_ROL ROL_ADMIN -1- CONC_A CONC_A -N- USR_ROL ROL_ADMIN -1- INCLUYE INCLUYE -N- ROL_PERM PERMISO -1- AGRUPA AGRUPA -N- ROL_PERM PRESTADOR -N- OPERA OPERA -1- AGENCIA @endchen ' --------------------------------------------------------------------- ' Diagrama 3 — Catálogo de servicios y geografía ' --------------------------------------------------------------------- @startchen catalogo_servicios title Catalogo de Servicios y Geografia skinparam nodesep 25 skinparam ranksep 45 skinparam shadowing false skinparam defaultFontSize 12 hide circle entity "Categoria de Servicio" as CATEGORIA { id <> nombre descripcion icono activo } entity "Servicio" as SERVICIO { id <> nombre descripcion precio_base duracion_estimada activo } entity "Zona de Cobertura" as ZONA { id <> nombre descripcion poligono estatus } entity "Comision Plataforma" as COMISION <> { porcentaje vigencia_desde vigencia_hasta } entity "Servicio del Prestador" as SERV_PREST { id <> precio_personalizado activo } entity "Tarifa por Zona" as TARIFA { id <> tipo_ajuste valor vigencia_desde } entity "Prestador" as PRESTADOR { id <> nombre } relationship "clasifica" as CLAS { } relationship "comisiona" as COMIS { } relationship "ofrecido_en" as OFR_S { } relationship "ofrecido_por" as OFR_P { } relationship "ajusta" as AJUSTA { } relationship "cubre" as CUBRE { } CATEGORIA -1- CLAS CLAS =N= SERVICIO CATEGORIA -1- COMIS COMIS =N= COMISION SERVICIO -1- OFR_S OFR_S -N- SERV_PREST PRESTADOR -1- OFR_P OFR_P -N- SERV_PREST SERVICIO -1- AJUSTA AJUSTA -N- TARIFA ZONA -1- CUBRE CUBRE -N- TARIFA @endchen ' --------------------------------------------------------------------- ' Diagrama 4 — Onboarding y operación de prestadores ' --------------------------------------------------------------------- @startchen onboarding_prestadores title Onboarding y Operacion de Prestadores skinparam nodesep 25 skinparam ranksep 45 skinparam shadowing false skinparam defaultFontSize 12 hide circle entity "Administrador" as ADMIN { id <> } entity "Invitacion Prestador" as INVITACION { codigo <> email fecha_envio fecha_expiracion estatus } entity "Prestador" as PRESTADOR { id <> nombre curp } entity "Documento Prestador" as DOC <> { id <> tipo_documento url estatus fecha_revision } entity "Disponibilidad" as DISP <> { id <> dia_semana hora_inicio hora_fin activo } entity "Direccion" as DIR <> { id <> domicilio { calle numero_ext colonia cp ciudad estado referencias } default } relationship "invita" as INVITA { } relationship "redime" as REDIME { } relationship "aporta" as APORTA <> { } relationship "agenda" as AGENDA <> { } relationship "reside_en" as RESIDE <> { } ADMIN -1- INVITA INVITA -N- INVITACION INVITACION -1- REDIME REDIME -1- PRESTADOR PRESTADOR =1= APORTA APORTA =N= DOC PRESTADOR =1= AGENDA AGENDA =N= DISP PRESTADOR =1= RESIDE RESIDE =N= DIR @endchen ' --------------------------------------------------------------------- ' Diagrama 5 — Operación de órdenes ' --------------------------------------------------------------------- ' Núcleo transaccional: orden + sus débiles (historial, evidencias, ' cargos extra) + calificaciones (asociativa ternaria). @startchen operacion_ordenes title Operacion de Ordenes de Servicio skinparam nodesep 25 skinparam ranksep 45 skinparam shadowing false skinparam defaultFontSize 12 hide circle entity "Cliente" as CLIENTE { id <> nombre } entity "Prestador" as PRESTADOR { id <> nombre } entity "Servicio" as SERVICIO { id <> nombre precio_base } entity "Direccion" as DIRECCION { id <> calle cp } entity "Cupon" as CUPON { codigo <> tipo_descuento valor } entity "Orden de Servicio" as ORDEN { folio <> fecha_solicitud programacion { fecha_programada ventana_inicio ventana_fin } estatus monto_total <> notas pin_cliente pin_prestador } entity "Historial Estatus" as HIST <> { id <> estatus_anterior estatus_nuevo fecha notas } entity "Evidencia" as EVID <> { id <> tipo url descripcion fecha } entity "Cargo Extra" as CARGO <> { id <> concepto monto estatus_aprobacion fecha } entity "Calificacion" as CALIF { id <> puntuacion comentario fecha } relationship "solicita" as SOL { } relationship "atiende" as ATD { } relationship "es_de_servicio" as ES_DE { } relationship "entrega_en" as ENT { } relationship "aplica_cupon" as APL_C { } relationship "evoluciona" as EVOL <> { } relationship "evidencia" as EVD <> { } relationship "cobra_extra" as COBR <> { } relationship "califica" as CAL_A { } relationship "es_calificado" as CAL_EN { } relationship "sobre" as SOBRE { } CLIENTE -1- SOL SOL =N= ORDEN PRESTADOR -1- ATD ATD -N- ORDEN SERVICIO -1- ES_DE ES_DE =N= ORDEN DIRECCION -1- ENT ENT =N= ORDEN CUPON -1- APL_C APL_C -N- ORDEN ORDEN =1= EVOL EVOL =N= HIST ORDEN =1= EVD EVD =N= EVID ORDEN =1= COBR COBR =N= CARGO ' Calificaciones: relacion ternaria materializada CLIENTE -1- CAL_A CAL_A -N- CALIF PRESTADOR -1- CAL_EN CAL_EN -N- CALIF ORDEN -1- SOBRE SOBRE -N- CALIF @endchen ' --------------------------------------------------------------------- ' Diagrama 6 — Finanzas ' --------------------------------------------------------------------- @startchen finanzas title Pagos, Liquidaciones y Facturacion skinparam nodesep 25 skinparam ranksep 45 skinparam shadowing false skinparam defaultFontSize 12 hide circle entity "Orden de Servicio" as ORDEN { folio <> monto_total <> } entity "Prestador" as PRESTADOR { id <> } entity "Pago" as PAGO { id <> transaccion { monto metodo referencia fecha_pago } estatus } entity "Reembolso" as REEMBOLSO { id <> monto motivo estatus fecha_solicitud fecha_resolucion } entity "Transaccion del Prestador" as TX_P <> { id <> monto fecha tipo } entity "Corte de Pago" as CORTE { id <> periodo_inicio periodo_fin monto_total <> estatus_deposito } entity "Factura" as FACTURA { folio <> cfdi { uuid_cfdi rfc_emisor rfc_receptor } monto estatus pdf_url } relationship "paga" as PAGA { } relationship "reembolsa" as REE { } relationship "origina" as ORIG <> { } relationship "cobra" as COBRA <> { } relationship "consolida_en" as CONS { } relationship "factura_orden" as FAC_O { } relationship "factura_corte" as FAC_C { } ORDEN =1= PAGA PAGA -N- PAGO PAGO -1- REE REE -N- REEMBOLSO ORDEN =1= ORIG ORIG =N= TX_P PRESTADOR =1= COBRA COBRA =N= TX_P TX_P -N- CONS CONS -1- CORTE ORDEN -1- FAC_O FAC_O -N- FACTURA CORTE -1- FAC_C FAC_C -N- FACTURA @endchen ' --------------------------------------------------------------------- ' Diagrama 7 — Soporte ITSM (L1/L2/L3) ' --------------------------------------------------------------------- ' Cubre: tickets + SLA + KB + Major Incidents + auto-relacion problema @startchen soporte_itsm title Soporte ITSM, SLA, Knowledge Base y Major Incidents skinparam nodesep 25 skinparam ranksep 45 skinparam shadowing false skinparam defaultFontSize 12 hide circle entity "Usuario" as USUARIO { id <> } entity "Orden de Servicio" as ORDEN { folio <> } entity "Ticket" as TICKET { folio <> asunto descripcion categoria prioridad estatus tipo tier_actual } entity "Mensaje" as MSG <> { id <> contenido tipo_autor es_interno fecha } entity "Escalation Log" as ESC <> { id <> tier_origen tier_destino hipotesis fecha } entity "Estado SLA" as SLA_ST <> { primer_respuesta_at resuelto_at paused_total_secs frt_breach <> ttr_breach <> } entity "CSAT Survey" as CSAT <> { csat_score ces_score comentario fecha } entity "Politica SLA" as SLA_POL { id <> nombre frt_minutos ttr_minutos prioridad_aplica } entity "Calendario SLA" as SLA_CAL { id <> nombre zona_horaria horario_laboral { dias_laborales <> hora_inicio hora_fin } } entity "Respuesta Predefinida" as CANNED { slug <> titulo plantilla variables <> } entity "Articulo KB" as KB { slug <> titulo contenido version estatus audiencia <> helpful_ratio <> } entity "Historial KB" as KB_H <> { id <> version contenido fecha } entity "Vista KB" as KB_V <> { id <> fecha } entity "Major Incident" as MIM { id <> titulo descripcion severidad inicio fin pir_url } entity "Update MIM" as MIM_U <> { id <> contenido fecha } entity "Vinculo Ticket-MIM" as VINC { id <> } relationship "reporta" as REP { } relationship "atiende" as ATD { } relationship "relacionada" as REL_O { } relationship "dialoga" as DIAL <> { } relationship "escala" as ESCAL <> { } relationship "mide_sla" as MIDE <> { } relationship "encuesta" as ENC <> { } relationship "rige_sla" as RIGE { } relationship "horario" as HOR { } relationship "usa_canned" as USA_C { } relationship "autor_de" as AUT_KB { } relationship "versiona" as VER <> { } relationship "consulta" as CONS_KB { } relationship "visto_en" as VIS <> { } relationship "actualiza" as ACT_MIM <> { } relationship "afecta_ticket" as AF_T { } relationship "afecta_mim" as AF_M { } relationship "problema_padre" as PROB { } ' Identidad y tickets USUARIO -1- REP REP =N= TICKET USUARIO -1- ATD ATD -N- TICKET ORDEN -1- REL_O REL_O -N- TICKET ' Mensajes y escalation (debiles del ticket) TICKET =1= DIAL DIAL =N= MSG TICKET =1= ESCAL ESCAL =N= ESC CANNED -1- USA_C USA_C -N- MSG ' SLA TICKET =1= MIDE MIDE =1= SLA_ST SLA_POL -1- RIGE RIGE -N- SLA_ST SLA_CAL -1- HOR HOR -N- SLA_POL ' CSAT TICKET -1- ENC ENC -1- CSAT ' KB USUARIO -1- AUT_KB AUT_KB -N- KB KB =1= VER VER =N= KB_H USUARIO -1- CONS_KB CONS_KB -N- KB_V KB =1= VIS VIS =N= KB_V ' Major Incidents MIM =1= ACT_MIM ACT_MIM =N= MIM_U TICKET -N- AF_T AF_T -N- VINC MIM -N- AF_M AF_M -N- VINC ' Auto-relacion problema -> incidentes TICKET -1- PROB PROB -N- TICKET @endchen ' --------------------------------------------------------------------- ' Diagrama 8 — Zero-Trust, break-glass y auditoría ' --------------------------------------------------------------------- @startchen zero_trust_auditoria title Zero-Trust, Break-Glass y Auditoria skinparam nodesep 25 skinparam ranksep 45 skinparam shadowing false skinparam defaultFontSize 12 hide circle entity "Administrador" as ADMIN { id <> } entity "Cliente" as CLIENTE { id <> } entity "Ticket" as TICKET { folio <> } entity "PIN Soporte Admin" as PIN_A <> { id <> pin_hash expira_en intentos bloqueado_hasta } entity "PIN Soporte Cliente" as PIN_C <> { id <> pin_hash expira_en } entity "Acceso a Perfil" as ACC <> { id <> motivo expira_en revocado_en } entity "Caso de Soporte" as CASO { id <> abierto_en expira_en motivo cerrado_en } entity "Log de Auditoria" as LOG { id <> accion entidad entidad_id valor_anterior valor_nuevo ip user_agent fecha } relationship "pin_admin" as PIN_ADM <> { } relationship "pin_cliente" as PIN_CLI <> { } relationship "solicita_acceso" as SOL_ACC <> { } relationship "acceso_sobre" as ACC_SOB { } relationship "abre_caso" as ABRE { } relationship "caso_sobre" as CASO_SOB { } relationship "caso_de_ticket" as CASO_T { } relationship "ejecuta" as EJEC { } relationship "trace_caso" as TR_C { } relationship "trace_ticket" as TR_T { } ADMIN =1= PIN_ADM PIN_ADM =1= PIN_A CLIENTE =1= PIN_CLI PIN_CLI =N= PIN_C ADMIN =1= SOL_ACC SOL_ACC =N= ACC CLIENTE -1- ACC_SOB ACC_SOB -N- ACC ADMIN -1- ABRE ABRE -N- CASO CLIENTE -1- CASO_SOB CASO_SOB -N- CASO TICKET -1- CASO_T CASO_T -N- CASO ADMIN -1- EJEC EJEC -N- LOG CASO -1- TR_C TR_C -N- LOG TICKET -1- TR_T TR_T -N- LOG @endchen ' --------------------------------------------------------------------- ' Diagrama 9 — Especialización del Usuario (categorías y subclases) ' --------------------------------------------------------------------- ' Muestra el patrón EER: Persona ⊃ {Cliente, Prestador, Admin} con ' overlap controlado (un Prestador puede también ser Cliente). @startchen jerarquia_usuario title Jerarquia y Categorias del Usuario skinparam nodesep 25 skinparam ranksep 45 skinparam shadowing false skinparam defaultFontSize 12 hide circle entity "Persona" as PERSONA { curp <> nombre { nombres apellidos } fecha_nacimiento email telefono } entity "Usuario del Sistema" as USUARIO { id <> rol activo foto } entity "Cliente" as CLIENTE { fecha_alta total_ordenes <> } entity "Prestador" as PRESTADOR { fecha_aprobacion calificacion_promedio <> ordenes_completadas <> bono_acumulado <> } entity "Administrador" as ADMIN { fecha_alta_panel } entity "Agente Soporte" as AGENTE { tier cola_asignada } entity "Operador L3" as L3 { area_especialidad } ' Persona es la categoria que unifica al Usuario y a entidades externas ' Para nuestro sistema: Usuario es el unico tipo de Persona que persiste. PERSONA ->- U { USUARIO } ' Especializacion principal: superposicion controlada ' Un mismo usuario puede ser Cliente y Prestador simultaneamente. USUARIO ->- o { CLIENTE, PRESTADOR, ADMIN } ' Sub-especializacion del administrador: disjunta ADMIN ->- d { AGENTE, L3 } @endchen