izan@asonipse:~
guest@asonipse:~$ whoami

IZAN ESPINOSA

> ADMINISTRADOR DE SISTEMAS Y REDES | CCST CYBERSECURITY - CISCO

Izan Espinosa
guest@asonipse:~$ cat SobreMi.txt

Administrador de sistemas enfocado en la gestión de infraestructura, seguridad y redes. Cuento con una sólida base de conocimientos técnicos consolidados tanto de forma autónoma como durante el desarrollo de mis prácticas profesionales en el sector tecnológico, asumiendo responsabilidades de soporte crítico, gestión de incidencias y despliegues.

guest@asonipse:~$ certutil --list-verified

[ CERTIFICACIONES Y CREDENCIALES ]

Marzo 2026 (Exp. 2031)

Cisco Certified Support Technician (CCST) Cybersecurity

Cisco — Credencial Activa

Diciembre 2025

CCNA: Switching, Routing, and Wireless Essentials

Cisco | Enrutamiento, Alta disponibilidad

Diciembre 2025

Linux II: Advanced System Services

Cisco | Gestión de datos, Servicios esenciales

Julio 2025

Ethical Hacker

Cisco | Ciberseguridad avanzada

Febrero 2025

Introduction to Cybersecurity

Cisco | Detección de amenazas

Septiembre 2024

Curso Básico de Ciberseguridad

CCN-CERT Centro Criptológico Nacional

Septiembre 2024

CCNA1: Introduction to Networks

Cisco | Ethernet, IP Connectivity

Junio 2024

NDG Linux Essentials

Cisco Partner | Linux Core

Mayo 2024

IT Essentials

Cisco | Sistemas operativos, Redes

guest@asonipse:~$ sysctl --get-all-aptitudes

[Networking]

  • Enrutamiento
  • IP connectivity
  • IP Subnetting
  • Ethernet
  • Protocolos de conmutación
  • Alta disponibilidad
  • Protocolo de Redundancia de Primer Salto (FHRP)
  • IP Services
  • Servicios de propiedad intelectual
  • Conceptos de redes

[Systems Administration]

  • Linux
  • Linux Virtual Server
  • Shells
  • Bash
  • Servicios esenciales del sistema
  • Gestión de datos
  • Proxmox
  • Windows
  • Windows Server
  • Administración Local de Sistemas Windows
  • Administración de Dominios Windows
  • Powershell
  • Sistemas operativos

[Cybersecurity & Auditing]

  • Ciberseguridad
  • Fundamentos de Seguridad de Red
  • Seguridad del sistema
  • Vulnerabilidades de la red
  • Detección de amenazas
  • Privacidad y confidencialidad de datos
  • Mejores prácticas cibernéticas

[Enterprise IT Operations]

  • Gestión de incidencias
  • Soporte técnico
  • Resolución de problemas
  • Configuración de sistemas
  • Plataformado de equipos
  • JIRA
  • Gestión documental
  • SQL
  • XML
  • JSON
  • HTML5
  • Hojas de estilos en cascada (CSS)
guest@asonipse:~$ cat experiencia_laboral.json
Mayo 2026 - Junio 2026

Solutel Prácticas

Desarrollo de competencias técnicas avanzadas en redes y soporte de infraestructura empresarial, consolidando entornos con Proxmox y arquitecturas distribuidas.

Marzo 2025 - Junio 2025

S2 Grupo Técnico de Microinformática (FCT)

Gestión integral de incidencias de empleados, optimización de flujos técnicos y planificación y asignación estratégica de equipamiento microinformático a sedes.

guest@asonipse:~$ cat formacion.log
>> G.S. Administración de Sistemas Informáticos en Red (ASIR)

IES Font de Sant Lluís | Finalización: Junio 2027

>> G.M. Sistemas Microinformáticos y Redes (SMR)

IES Font de Sant Lluís | 2023 - 2025

guest@asonipse:~$ ls -la ./proyectos/PetCare360

[ PROYECTO DESTACADO: PETCARE360 ]

Diseño, despliegue e integración total de la infraestructura IT y seguridad perimetral para una clínica y tienda de animales orientada a producción. Unifica virtualización en Proxmox VE, dominio con Active Directory, automatización de sistemas y auditoría de redes.

# Framework Frontend Local: Tkinter & TTK (LabelFrames & Treeview dinámicos)
# Mecanismo: Sockets TCP/IP nativos mediante puerto MySQL (3306) | IP Servidor: 10.0.0.200
import mysql.connector
from mysql.connector import Error
import tkinter as tk
from tkinter import messagebox, ttk
 
# Diccionario para guardar el mapa de los productos { "Nombre del Producto": id_producto }
diccionario_productos = {}
 
# Carga los productos de la base de datos en el desplegable al iniciar
def cargar_productos_desplegable():
    global diccionario_productos
    try:
        conexion = mysql.connector.connect(
            host="10.0.0.200",
            user="root",
            password="1dosTres#",
            database="tiendamascotas"
        )
        cursor = conexion.cursor()
        # Agarro el ID y el Nombre para mapearlos
        cursor.execute("SELECT id_producto, nombre FROM PRODUCTO ORDER BY nombre;")
 
        nombres_productos = []
        diccionario_productos.clear()
 
        for id_prod, nombre in cursor.fetchall():
            nombres_productos.append(nombre)
            diccionario_productos[nombre] = id_prod  # Guardamos la relación
 
        # Insertamos los nombres en el Combobox de la interfaz
        combo_producto['values'] = nombres_productos
        if nombres_productos:
            combo_producto.current(0) # Selecciona el primero por defecto
 
        cursor.close()
        conexion.close()
    except mysql.connector.Error as err:
        messagebox.showerror("Error de Inicio", f"No se ha podido cargar los productos en el menú:\n{err}")
 
# Funcion para ejecutar las consultas
def ejecutar_consulta(tipo_consulta):
    global tabla
    try:
        # Conexión al Windows Server
        conexion = mysql.connector.connect(
            host="10.0.0.200",
            user="root",
            password="1dosTres#",
            database="tiendamascotas"
        )
        cursor = conexion.cursor()
 
        # Captura los datos de las casillas de texto en tiempo real
        dni_input = entry_dni.get().strip()
 
        # Obtenemos el id desde el despegable usando el diccionario anteriormente creado
        producto_seleccionado = combo_producto.get()
        prod_input = diccionario_productos.get(producto_seleccionado)
 
        # Vaciamos y reseteamos por completo la tabla para cambiar las columnas sin errores
        tabla.destroy()
        tabla = ttk.Treeview(frame_tabla, show="headings")
        tabla.pack(side="left", fill="both", expand=True)
 
        scrollbar.config(command=tabla.yview)
        tabla.configure(yscrollcommand=scrollbar.set)
 
        # Mapeo de las Consultas
        if tipo_consulta == 1:
            if not dni_input: return messagebox.showwarning("Falta Dato", "Introduce un DNI en la casilla")
            columnas = ("Tipo de Producto", "Cantidad Total Comprada")
            query = """SELECT PRODUCTO.tipo_producto, SUM(CONTIENE.cantidad)
FROM CONTIENE
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
JOIN PEDIDO ON CONTIENE.id_pedido = PEDIDO.id_pedido
WHERE PEDIDO.dni_cliente = %s
GROUP BY PRODUCTO.tipo_producto
ORDER BY SUM(CONTIENE.cantidad) DESC
LIMIT 1;"""
            cursor.execute(query, (dni_input,))
 
        elif tipo_consulta == 2:
            if not dni_input: return messagebox.showwarning("Falta Dato", "Introduce un DNI en la casilla")
            columnas = ("ID Pedido", "Fecha Pedido", "Nombre", "Cantidad", "Precio Venta", "Total Factura")
            query = """SELECT PEDIDO.id_pedido, PEDIDO.fecha_pedido,
PRODUCTO.nombre, CONTIENE.cantidad, 
      PRODUCTO.precio_venta, (CONTIENE.cantidad * PRODUCTO.precio_venta)
FROM PEDIDO
JOIN CONTIENE ON PEDIDO.id_pedido = CONTIENE.id_pedido
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
WHERE PEDIDO.dni_cliente = %s
ORDER BY PEDIDO.id_pedido;"""
            cursor.execute(query, (dni_input,))
 
        elif tipo_consulta == 3:
            if not dni_input: return messagebox.showwarning("Falta Dato", "Introduce un DNI en la casilla")
            columnas = ("Total Gastado (€)",)
            query = """SELECT SUM(CONTIENE.cantidad * PRODUCTO.precio_venta)
FROM PEDIDO
JOIN CONTIENE ON PEDIDO.id_pedido = CONTIENE.id_pedido
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
WHERE PEDIDO.dni_cliente = %s;"""
            cursor.execute(query, (dni_input,))
 
        elif tipo_consulta == 4:
            if not dni_input: return messagebox.showwarning("Falta Dato", "Introduce un DNI en la casilla")
            columnas = ("Nombre", "Tipo Animal", "Fecha Nacimiento")
            query = """SELECT nombre, tipo_animal, fecha_nacimiento
FROM MASCOTA WHERE dni_cliente = %s;"""
            cursor.execute(query, (dni_input,))
 
        elif tipo_consulta == 5:
            if not prod_input: return messagebox.showwarning("Falta Dato", "Selecciona un producto válido")
            columnas = ("Nombre Proveedor", "Teléfono")
            query = """SELECT PROVEEDOR.nombre, PROVEEDOR.telefono
FROM PROVEEDOR
JOIN SUMINISTRA ON PROVEEDOR.id_proveedor = SUMINISTRA.id_proveedor
WHERE SUMINISTRA.id_producto = %s;"""
            cursor.execute(query, (prod_input,))
 
        elif tipo_consulta == 6:
            if not prod_input: return messagebox.showwarning("Falta Dato", "Selecciona un producto válido")
            columnas = ("Nombre Producto", "Ganancia Total")
            query = """SELECT PRODUCTO.nombre, 
      SUM(CONTIENE.cantidad * (PRODUCTO.precio_venta - PRODUCTO.precio_coste))
FROM CONTIENE
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
WHERE PRODUCTO.id_producto = %s
GROUP BY PRODUCTO.nombre;"""
            cursor.execute(query, (prod_input,))
 
        elif tipo_consulta == 7:
            columnas = ("nombre", "SUM(CONTIENE.cantidad)")
            query = """SELECT PRODUCTO.nombre, SUM(CONTIENE.cantidad)
FROM CONTIENE
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
GROUP BY PRODUCTO.id_producto, PRODUCTO.nombre
ORDER BY SUM(CONTIENE.cantidad) DESC
LIMIT 5;"""
            cursor.execute(query)
 
        # Configuración del tamaño y alineación de las columnas
        tabla["columns"] = columnas
        for col in columnas:
            tabla.heading(col, text=col)
            if col in ["nombre", "Nombre Producto", "Producto", "Nombre Proveedor"]:
                tabla.column(col, anchor="w", width=380)
            else:
                tabla.column(col, anchor="center", width=160)
 
        # Pintamos los números en Tkinter
        for fila in cursor.fetchall():
            valores_limpios = []
            for celda in fila:
                if celda is None:
                    valores_limpios.append("0")
                elif isinstance(celda, (bytes, bytearray)):
                    valores_limpios.append(celda.decode('utf-8'))
                else:
                    valores_limpios.append(str(celda))
 
            tabla.insert("", tk.END, values=valores_limpios)
 
        cursor.close()
        conexion.close()
 
    except mysql.connector.Error as err:
        messagebox.showerror("Error MySQL", f"Hubo un problema con la base de datos:\n{err}")
 
# Diseño de la interfaz
root = tk.Tk()
root.title("PetCare IT - Cuadro de Mandos de Ventas")
root.geometry("850x600")
root.configure(bg="#f4f6f9")
 
lbl_titulo = tk.Label(root, text="🐾 PetCare360 🐾", font=("Arial", 16, "bold"), bg="#f4f6f9", fg="#2c3e50")
lbl_titulo.pack(pady=10)
 
# Cuadro superior de entradas de texto / filtros
frame_inputs = tk.LabelFrame(root, text=" Filtros de Búsqueda ", font=("Arial", 10, "bold"), bg="#f4f6f9", fg="#34495e", padx=10, pady=10)
frame_inputs.pack(fill="x", padx=20, pady=5)
 
tk.Label(frame_inputs, text="DNI Cliente:", font=("Arial", 10), bg="#f4f6f9").grid(row=0, column=0, padx=5)
entry_dni = tk.Entry(frame_inputs, font=("Arial", 10), width=15)
entry_dni.grid(row=0, column=1, padx=15)
entry_dni.insert(0, "11111111A") 
 
# Despegable
tk.Label(frame_inputs, text="Seleccionar Producto:", font=("Arial", 10), bg="#f4f6f9").grid(row=0, column=2, padx=5)
combo_producto = ttk.Combobox(frame_inputs, font=("Arial", 10), width=35, state="readonly")
combo_producto.grid(row=0, column=3, padx=15)
 
# Cuadro del menú con los botones
frame_botones = tk.LabelFrame(root, text=" Consultas Disponibles ", font=("Arial", 10, "bold"), bg="#f4f6f9", fg="#34495e", padx=10, pady=10)
frame_botones.pack(fill="x", padx=20, pady=10)
 
tk.Button(frame_botones, text="1. Tipo Prod. Más Comprado", bg="#3498db", fg="white", font=("Arial", 9), command=lambda: ejecutar_consulta(1)).grid(row=0, column=0, padx=5, pady=5, sticky="we")
tk.Button(frame_botones, text="2. Ver Facturas Completas", bg="#3498db", fg="white", font=("Arial", 9), command=lambda: ejecutar_consulta(2)).grid(row=0, column=1, padx=5, pady=5, sticky="we")
tk.Button(frame_botones, text="3. Total Gastado Cliente", bg="#3498db", fg="white", font=("Arial", 9), command=lambda: ejecutar_consulta(3)).grid(row=0, column=2, padx=5, pady=5, sticky="we")
tk.Button(frame_botones, text="4. Mascotas de Cliente", bg="#3498db", fg="white", font=("Arial", 9), command=lambda: ejecutar_consulta(4)).grid(row=0, column=3, padx=5, pady=5, sticky="we")
tk.Button(frame_botones, text="5. Teléfonos Proveedores", bg="#2ecc71", fg="white", font=("Arial", 9), command=lambda: ejecutar_consulta(5)).grid(row=1, column=0, padx=5, pady=5, sticky="we")
tk.Button(frame_botones, text="6. Ganancias de Producto", bg="#2ecc71", fg="white", font=("Arial", 9), command=lambda: ejecutar_consulta(6)).grid(row=1, column=1, padx=5, pady=5, sticky="we")
tk.Button(frame_botones, text="🔥 7. TOP 5 Más Vendidos", bg="#e67e22", fg="white", font=("Arial", 9, "bold"), command=lambda: ejecutar_consulta(7)).grid(row=1, column=2, columnspan=2, padx=5, pady=5, sticky="we")
 
for i in range(4):
    frame_botones.grid_columnconfigure(i, weight=1)
 
# El contenedor inferior de la tabla
frame_tabla = tk.Frame(root, bg="#f4f6f9")
frame_tabla.pack(fill="both", expand=True, padx=20, pady=10)
 
tabla = ttk.Treeview(frame_tabla, show="headings")
tabla.pack(side="left", fill="both", expand=True)
 
scrollbar = ttk.Scrollbar(frame_tabla, orient="vertical", command=tabla.yview)
tabla.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
 
# Hacemos una llamada al despegable nada mas arrancamos el programa
cargar_productos_desplegable()
 
root.mainloop()

1. Tipo de producto más comprado por un cliente en concreto

SELECT PRODUCTO.tipo_producto, SUM(CONTIENE.cantidad)
FROM CONTIENE
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
JOIN PEDIDO ON CONTIENE.id_pedido = PEDIDO.id_pedido
WHERE PEDIDO.dni_cliente = '11111111A'
GROUP BY PRODUCTO.tipo_producto
ORDER BY SUM(CONTIENE.cantidad) DESC
LIMIT 1;

2. Las facturas completas de un cliente en concreto

SELECT PEDIDO.id_pedido, PEDIDO.fecha_pedido, PRODUCTO.nombre, CONTIENE.cantidad, 
       PRODUCTO.precio_venta, (CONTIENE.cantidad * PRODUCTO.precio_venta)
FROM PEDIDO
JOIN CONTIENE ON PEDIDO.id_pedido = CONTIENE.id_pedido
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
WHERE PEDIDO.dni_cliente = '11111111A'
ORDER BY PEDIDO.id_pedido;

3. Cuanto dinero se ha gastado un cliente en concreto

SELECT SUM(CONTIENE.cantidad * PRODUCTO.precio_venta)
FROM PEDIDO
JOIN CONTIENE ON PEDIDO.id_pedido = CONTIENE.id_pedido
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
WHERE PEDIDO.dni_cliente = '11111111A';

4. Las mascotas de un cliente
SELECT nombre, tipo_animal, fecha_nacimiento
FROM MASCOTA

WHERE dni_cliente = '11111111A';

5. Los teléfonos de los proveedores de un producto en concreto

SELECT PROVEEDOR.nombre, PROVEEDOR.telefono
FROM PROVEEDOR
JOIN SUMINISTRA ON PROVEEDOR.id_proveedor = SUMINISTRA.id_proveedor
WHERE SUMINISTRA.id_producto = 1;

6. Ganancias generadas por un producto en concreto

SELECT PRODUCTO.nombre, 
       SUM(CONTIENE.cantidad * (PRODUCTO.precio_venta - PRODUCTO.precio_coste))
FROM CONTIENE
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
WHERE PRODUCTO.id_producto = 1
GROUP BY PRODUCTO.nombre;

7. Top 5 de los productos más vendidos
SELECT PRODUCTO.nombre, SUM(CONTIENE.cantidad)
FROM CONTIENE
JOIN PRODUCTO ON CONTIENE.id_producto = PRODUCTO.id_producto
GROUP BY PRODUCTO.id_producto, PRODUCTO.nombre
ORDER BY SUM(CONTIENE.cantidad) DESC
LIMIT 5;
;
#!/bin/bash

# Configurmos las rutas

ORIGEN="/mnt/respaldo_windows/"
DESTINO="/home/administrador/backups_datos/"
LOG="/var/log/backup_rsync.log"

# Crea la carpeta de destino si no existe

mkdir -p $DESTINO

echo "--- Inicio de Backup: $(date) ---" | tee a $LOG

#rsync:
-a (archivo: mantiene permisos y fechas)
-v (detallado: escribe lo que hace en el log)
-z (comprime durante la transferencia)
--delete (borra en destino lo que no está en origen) 
rsync -avz --delete $ORIGEN $DESTINO | tee -a $LOG

echo "Fin de Backup: $(date)" | tee -a $LOG
                                
guest@asonipse:~$ ./contactar.sh

¿Buscas un perfil técnico, proactivo y respaldado por certificaciones oficiales Cisco? Conecta conmigo de inmediato: