Categoría: Personal Projects

  • AdventureWorks: Custom Full-Stack Data & Analytics Platform

    Este proyecto documenta el diseño e implementación de una plataforma de datos full-stack y de código abierto, desarrollada para reemplazar una infraestructura analítica comercial costosa y rígida. A través de la migración de la base de datos relacional de AdventureWorks desde SQL Server hacia PostgreSQL, el desarrollo de pipelines ETL modulares en Python y la integración de modelos predictivos de Machine Learning, se transformó un sistema de reportes tradicional en un motor independiente y escalable, centralizado en una aplicación web interactiva con Flask y Docker.

    El Desafío del Negocio (The Problem Statement)

    AdventureWorks Inc. gestionaba su inteligencia de negocio y reportería a través de una suite de analítica comercial propietaria y tradicional basada en licencias de software cerrado. Al escalar la organización, el equipo se enfrentó a tres bloqueos críticos:

    1. Escala Exponencial de Costos por Licenciamiento: El modelo de cobro por usuario o por núcleo se volvió financieramente insostenible ante la creciente demanda de acceso concurrente por parte de Ventas, RRHH, Producción y Compras.
    2. Limitaciones de Integración con Data Science y ML: El ecosistema cerrado dificultaba acoplar modelos avanzados de Machine Learning (como forecasting de series temporales con Prophet o clasificación con XGBoost) en los flujos de datos sin recurrir a costosos módulos de IA adicionales.
    3. Dependencia del Proveedor (Vendor Lock-in): La falta de control sobre el procesamiento impedía personalizar la interfaz a nivel corporativo y flexibilizar el despliegue en infraestructura propia.

    Nuestra Solución:

    Arquitectura Full-Stack Data de Código Abierto. Diseñamos y desarrollamos una plataforma web propietaria, independiente y end-to-end que migró la infraestructura y transformó los reportes rígidos del pasado en un motor analítico y predictivo centralizado:

    Pipeline del proyecto

    Fase 1: Ingesta, Auditoría y Exploración Profunda (OLTP)

    Objetivo: Comprender las reglas y la estructura exacta del negocio para mitigar sesgos en las etapas de transformación y modelado.

    • Aprovisionamiento: Extracción y restauración del backup relacional nativo (.bak) de AdventureWorks 2022 en SQL Server.
    • Data Quality & Perfilado Inicial: Auditoría técnica mediante scripts SQL de exploración individual para cada una de las 18 tablas relevantes, documentando rangos de fechas, valores únicos y patrones de columnas clave.
    • Garantía de Integridad: Identificación exhaustiva de claves primarias y foráneas reales, consolidando las dinámicas operacionales en un Diccionario de Datos maestro y un diagrama relacional completo.

    Fase 2: Diseño del Modelo Analítico Relacional y Requerimientos

    Objetivo: Traducir los objetivos corporativos en una arquitectura de datos técnica limpia y estructurada.

    • Definición de Granularidad: Establecimiento preciso del nivel de detalle de las entidades operativas (ej. Ventas por línea de pedido, Inventarios por snapshots de producto/almacén y Finanzas por periodo contable).
    • Mapeo de KPIs: Selección de indicadores estratégicos para una visión de 360° (Sales Amount, Total Product Cost, Profit, Margen %, Tendencias YoY/MoM, Ticket Promedio y Alertas de Stock).
    • Gobernanza Técnica: Generación de un Documento de Requerimientos Funcionales como base para validar formalmente las necesidades lógicas con cada área antes de iniciar el código.

    Fase 3: Extracción y Preparación mediante Vistas SQL

    Objetivo: Proveer una capa de datos purificada, segura y optimizada desde la base de origen.

    • Desacoplamiento Estructural: Creación de vistas en SQL Server diseñadas según los requerimientos funcionales para pre-estructurar el set de datos.
    • Seguridad y Anonimización: Selección rigurosa de atributos descriptivos y demográficos para segmentación, aplicando políticas de privacidad al anonimizar o remover datos sensibles de clientes.
    • Cómputo en Base de Datos: Implementación de transformaciones básicas directamente en el motor de origen (como cálculo dinámico de edad y unificación de jerarquías de productos) para aligerar las fases posteriores de procesamiento en Python.

    Fase 4: Migración Heterogénea de Bases de Datos

    Objetivo: Romper la dependencia con el proveedor tradicional migrando el núcleo de la compañía a un motor Open-Source (PostgreSQL) sin alterar su estructura relacional original.

    • Schema Mapping: Traducción de tipos de datos, restricciones e incompatibilidades entre SQL Server y PostgreSQL mediante el uso de Python.
    • Pipelines de Ingesta: Diseño de scripts de migración progresiva y por lotes para mover de manera controlada el modelo relacional puro, asegurando consistencia matemática absoluta entre ambos motores.
    • Stack Principal: SQL Server, PostgreSQL, SQLAlchemy, PyODBC, Psycopg2 y Pandas.

    Fase 5: Pipeline ETL y Automatización con Python

    Objetivo: Construir un pipeline reproducible con un solo comando que extraiga, limpie y guarde datos curados listos para consumo concurrente.

    • Pipeline Modular (Jupyter/Scripts): Desarrollo de notebooks de experimentación consolidados posteriormente en un script ejecutable (etl_pipeline.py) alimentado por un archivo central de configuración (config.py).
    • Feature Engineering & Limpieza: Tratamiento automatizado de valores nulos mediante reglas específicas según la columna, conversión estructurada de tipos/fechas y eliminación de duplicados mediante funciones reutilizables (CheckData).
    • Persistencia Eficiente (Formatos de Alto Rendimiento): Exportación de datasets limpios y validados a disco en formato Parquet (para optimizar espacio y velocidad de lectura).
    • Trazabilidad y Auditoría: Integración de logs detallados de seguimiento en consola para registrar el éxito/fallo del pipeline y mantenimiento de un registro maestro de control (datasets_control.xlsx) con métricas de filas y columnas procesadas.

    Fase 6: Optimización de la Capa Analítica en PostgreSQL

    Objetivo: Centralizar la lógica analítica pesada dentro de PostgreSQL para mitigar la carga computacional en el backend de la aplicación.

    • Modelado Lógico: Configuración de Vistas (Views) enriquecidas y almacenamiento indexado en PostgreSQL directamente sobre las tablas migradas.
    • Agregación Avanzada: Construcción de consultas complejas diseñadas para unificar la información dispersa de las áreas de Sales, HR, Product Performance, Supply Chain y Customer Analytics en estructuras consolidadas.

    Fase 7: Backend Analítico y Arquitectura de Software

    Objetivo: Construir la capa lógica del servidor encargada de procesar peticiones y unificar los datos analíticos de la empresa.

    • Backend Engineering: Desarrollo de una aplicación web robusta en Python utilizando Flask, estructurada de forma modular mediante Blueprints para segmentar los servicios de cada departamento de la compañía.
    • Persistencia Dinámica y APIs: Conexión interactiva a PostgreSQL para leer de forma nativa los archivos estructurados y las vistas optimizadas, garantizando tiempos mínimos de respuesta del servidor (latencia en milisegundos).

    Fase 8: Pipeline de Machine Learning y Analítica Predictiva

    Objetivo: Escalar la plataforma hacia la analítica predictiva, dotando al sistema de la capacidad de anticipar eventos críticos de negocio.

    • Modelado de Inteligencia Artificial: Diseño e implementación de modelos supervisados y de análisis temporal utilizando Scikit-Learn, XGBoost y Prophet.
    • Casos de Uso Operacionales:
      • Forecasting de Ventas: Modelos de series de tiempo para proyectar la demanda mensual e ingresos.
      • Clasificación de Churn: Modelos predictivos para calcular la probabilidad de abandono de clientes recurrentes.
      • Optimización de Cadena de Suministro: Predicción de quiebres de stock basándose en flujos históricos de inventario.
    • Inferencia en Producción: Creación de un script automatizado para la extracción de features, reentrenamiento de modelos y serialización de artefactos (.pkl / ONNX), consumidos directamente por la API de Flask para generar predicciones en tiempo real. [1]

    Fase 9: Visualización de Datos e Interfaces de Usuario (Frontend)

    Objetivo: Democratizar los insights corporativos permitiendo a la mesa directiva evaluar el rendimiento histórico y forecast predictivos en una sola pantalla unificada.

    • Frontend Interactivo: Creación de una interfaz web multipágina y responsive codificada con Plotly y Flask, reemplazando por completo los visualizadores de la suite comercial rígida.
    • Dashboards Ejecutivos Diseñados: Executive Overview, Sales Intelligence, HR Analytics, Product Performance y Geographic Insights.
    • Capa Semántica Unificada: Ocultamiento de columnas técnicas y exposición directa al usuario de medidas avanzadas de KPIs históricos calculados en base de datos junto a las proyecciones dinámicas estimadas por los modelos de Machine Learning.

    Fase 10: Despliegue en Producción y DevOps (MLOps)

    Objetivo: Publicar el sistema bajo una infraestructura escalable, segura y con costos de mantenimiento fijos, logrando la independencia total del negocio.

    • Infraestructura Cloud: Aprovisionamiento, hardening y configuración de políticas de seguridad en un Servidor Virtual Privado (VPS) con Ubuntu Server.
    • Contenerización Completa: Aislamiento de entornos y servicios (PostgreSQL, la aplicación Flask con sus pipelines de ML, las dependencias de Python y los servidores web) mediante Docker y Docker Compose.
    • Arquitectura de Producción: Implementación del servidor WSGI Gunicorn acoplado a Nginx como proxy inverso, garantizando la gestión eficiente de peticiones, compresión de assets, balanceo de carga básico y cifrado SSL.

    Ecosistema Tecnológico (Tech Stack)

    CategoríaTecnologías ClavePropósito en el Proyecto
    LenguajesPython (v3.11+), SQL (T-SQL / PL-pgSQL), HTML5/CSS3Procesamiento central, consultas optimizadas e interfaz nativa.
    Bases de DatosSQL Server , PostgreSQLMigración heterogénea desde el motor origen tradicional al destino Open-Source.
    Data Engineering & ETLPandas, SQLAlchemy, PyODBC, Psycopg2, ParquetScripting modular, mapeo de esquemas y persistencia de alto rendimiento.
    Data Science & MLXGBoost, Prophet (Meta), Scikit-Learn, ONNX / PickleModelos predictivos de series temporales, clasificación de churn e inferencia.
    Backend & APIsFlask, Flask Blueprints, GunicornArquitectura de software modular para servir datos y predicciones en tiempo real.
    Frontend & UXPlotly, Dash / Custom ComponentsVisualizaciones interactivas multipágina y dashboards corporativos 360°.
    DevOps & MLOpsDocker, Docker Compose, Nginx, Ubuntu Server (VPS), SSLContenerización multi-servicio, proxy inverso, seguridad y despliegue en la nube.

    Infografía de pipeline y arquitectura tecnológica

  • Proyecto de aplicación web Flask: Projects Portal.

    En este proyecto desarrollaremos una aplicación web con Flask que funcionará como el portal principal de nuestro VPS. Su propósito es servir como punto central de acceso a todos los proyectos, aplicaciones y servicios que vayamos desplegando a lo largo del tiempo.

    La página estará disponible en el subdominio projects.fernandorioseco.es y actuará como un auténtico escaparate técnico y profesional. Desde ella será posible entrar a las aplicaciones de proyectos realizados. También cada proyecto contará con su propio subdominio dentro del VPS.

    En ese subdominio se desplegará la aplicación funcional del proyecto, es decir, la herramienta o servicio que el usuario podrá utilizar directamente, ya sea una aplicación desarrollada con Flask, Streamlit, FastAPI u otra tecnología.

    La explicación detallada del proyecto —objetivos, arquitectura, tecnologías empleadas, proceso de desarrollo y aprendizajes obtenidos— no se mostrará dentro de la aplicación, sino en el sitio principal del portfolio, donde cada proyecto tendrá su propia ficha o artículo descriptivo.

    De esta forma se separan claramente dos elementos:

    1. La documentación del proyecto, alojada en el sitio principal del portfolio.
    2. La aplicación desplegada, accesible mediante su subdominio correspondiente.

    Este enfoque permite mantener el portfolio organizado y profesional, ofreciendo por un lado la explicación técnica del trabajo realizado y, por otro, el acceso directo a la aplicación en funcionamiento.

    Estructura general del proyecto

    El propósito del proyecto es construir una aplicación web en Flask desplegada en projects.fernandorioseco.es que actuará como portal central del VPS.

    Objetivos

    • Centralizar el acceso a proyectos.
    • Mostrar información sobre el VPS.
    • Presentar el stack tecnológico.
    • Servir como portfolio profesional.

    Para desarrollar el Projects Portal seguiremos una metodología organizada que abarcará desde el diseño de la aplicación en local hasta su despliegue definitivo en el VPS. El proyecto no solo consistirá en construir una aplicación web con Flask, sino también en integrarla dentro de la infraestructura del servidor y conectarla con el resto de aplicaciones del portfolio.

    La estructura general del proyecto se dividirá en las siguientes fases:

    1 – Planificación y Diseño: En primer lugar definiremos el objetivo del portal, las secciones que incluirá y la experiencia de usuario que queremos ofrecer. En esta fase estableceremos la arquitectura de la aplicación, el diseño de la interfaz y la información que se mostrará en cada sección.

    2Setup de la Aplicación y Control de Versiones con Git y GitHub: Preparar el setup del proyecto con una app mínima, inicializar un repositorio Git y publicar el código en GitHub para mantener un historial de cambios y facilitar el despliegue en el servidor.

    3 – Desarrollo Local: Crearemos el proyecto Flask en nuestro entorno local, organizaremos la estructura de carpetas, diseñaremos las plantillas HTML y desarrollaremos los estilos CSS y la lógica necesaria para mostrar los proyectos de forma dinámica.

    4 – Configuración del Dominio: Crearemos el subdominio projects.fernandorioseco.es y configuraremos el registro DNS para que apunte a la dirección IP pública del VPS.

    5 – Preparación del VPS: Crearemos el directorio del proyecto en el servidor, clonaremos el repositorio desde GitHub, configuraremos el entorno virtual de Python e instalaremos todas las dependencias necesarias.

    6 – Configuración del Servicio con Gunicorn y systemd: Configuraremos Gunicorn como servidor WSGI y crearemos un servicio de systemd para que la aplicación se ejecute automáticamente y permanezca activa tras reinicios del sistema.

    7 – Configuración de Nginx y HTTPS: Configuraremos Nginx como proxy inverso para publicar la aplicación en Internet y habilitaremos HTTPS mediante certificados SSL de Let’s Encrypt.

    8 – Actualización y Mantenimiento: Definiremos el procedimiento para desplegar nuevas versiones del portal y añadir proyectos al catálogo mediante archivos JSON individuales.

    9 – Mejoras y Evolución: Una vez desplegado el portal, podremos incorporar nuevas funcionalidades, como filtros por tecnología, estadísticas del VPS en tiempo real o un panel de administración para gestionar los proyectos desde una interfaz web.

    1. Planificación y Diseño

    Arquitectura de la Aplicación

    La aplicación Projects Portal se desarrollará con Flask siguiendo una arquitectura sencilla, modular y escalable. El objetivo es separar claramente la lógica de negocio, la presentación y los datos para facilitar el mantenimiento y la incorporación de nuevos proyectos.

    La arquitectura se basará en los siguientes componentes:

    1. Cliente web (navegador).
    2. Servidor web Nginx.
    3. Servidor de aplicaciones Gunicorn.
    4. Aplicación Flask.
    5. Plantillas HTML con Jinja2.
    6. Archivos estáticos (CSS, JavaScript e imágenes).
    7. Archivo de configuración con los datos de los proyectos.

    Flujo de Funcionamiento

    Usuario
       
    Navegador Web
       
    Nginx (Reverse Proxy)
       
    Gunicorn (WSGI Server)
       
    Flask Application
       
    Routes (views.py)
       
    Data Source (projects.json o Python dictionary)
       
    Jinja2 Templates
       
    HTML Renderizado
       
    Respuesta al Navegador
    

    Componentes de la Arquitectura

    • Navegador del Usuario: Es el cliente que realiza la petición HTTP y renderiza el HTML, CSS y JavaScript enviados por la aplicación.
    • Nginx: Actúa como proxy inverso.
      • Recibe las peticiones HTTPS.
      • Gestiona los certificados SSL/TLS.
      • Redirige el tráfico hacia Gunicorn.
      • Sirve archivos estáticos si se desea.
    • Gunicorn: Servidor WSGI encargado de ejecutar la aplicación Flask.
      • Inicia la aplicación.
      • Gestiona procesos workers.
      • Atiende múltiples peticiones concurrentes.
    • Aplicación Flask: Contiene la lógica principal del portal.
      • Fuente de Datos: Los proyectos pueden almacenarse en:
        • Un archivo projects.json.
      • Plantillas Jinja2: Se encargan de generar el HTML dinámico.
        • base.html
        • index.html
        • Componentes parciales:
          • navbar.html
          • hero.html
          • projects.html
          • footer.html
      • Archivos Estáticos: Recursos utilizados por la interfaz:
        • CSS.
        • JavaScript.
        • Imágenes.
        • Iconos.

    Estructura de carpetas y ficheros

    projects-portal/
    ├── app/
       ├── __init__.py
       ├── routes.py
       ├── data/
          └── projects.json
       ├── templates/
          ├── base.html
          ├── index.html
          └── components/
              └── navbar.html
              └── hero.html
              └── vps_info.html
              └── tech_stack.html
              └── projects.html
              └── resources.html
              └── footer.html
       └── static/
           ├── css/
           ├── js/
           └── img/
    ├── config.py
    ├── requirements.txt
    ├── run.py
    └── wsgi.py
    

    Descripción de los ficheros

    • app/__init__.py: Crea y configura la aplicación Flask, registra las rutas y devuelve la instancia principal de la aplicación.
    • app/routes.py: Define las rutas de la aplicación y establece que la página principal renderice la plantilla index.html.
    • run.py: Ejecuta la aplicación en modo desarrollo para realizar pruebas en el entorno local.
    • wsgi.py: Expone la aplicación para que pueda ser ejecutada por un servidor WSGI como Gunicorn en producción.
    • app/templates/index.html: Crea la estructura HTML básica de la página principal con el nombre del portal y una breve descripción del laboratorio.
    • app/data/projects.json: Almacenará la información de los proyectos que se mostrarán dinámicamente en el portal.
    • requirements.txt: Guarda el listado de dependencias Python necesarias para ejecutar el proyecto.
    • config.py: Centraliza la configuración general de la aplicación.
    • app/static/css/: Contendrá las hojas de estilo CSS de la aplicación.
    • app/static/js/: Contendrá los archivos JavaScript utilizados en la interfaz.
    • app/static/img/: Almacenará imágenes, iconos y recursos gráficos.
    • app/templates/base.html: Servirá como plantilla base común para todas las páginas del sitio.
    • app/templates/components/: Almacenará componentes reutilizables de la interfaz, como la barra de navegación o el footer.

    Patrón Arquitectónico

    El portal Projects Portal seguirá una versión simplificada del patrón arquitectónico MVC (Model-View-Controller), uno de los modelos de diseño más utilizados en el desarrollo de aplicaciones web. El objetivo es separar claramente los datos, la lógica de la aplicación, y la presentación visual.

    Componente MVCImplementación
    Modelapp/data/projects.json
    Viewapp/templates/*.html
    Controllerapp/routes.py

    Escalabilidad

    La arquitectura permite evolucionar fácilmente hacia:

    • Base de datos relacional.
    • Panel de administración.
    • API REST.
    • Autenticación.
    • Caché con Redis.
    • Contenerización con Docker.

    Estructura de la Interfaz de Usuario (UI)

    La aplicación Projects Portal estará compuesta por una única página principal diseñada para presentar el laboratorio técnico y ofrecer acceso directo a todos los proyectos desplegados en el VPS. La interfaz se organizará en varias secciones claramente diferenciadas, cada una con una función específica dentro de la experiencia de usuario.

    Boceto de referencia aproximado generado por IA:

    • Barra de Navegación (Navbar): La página comenzará con una barra de navegación fija en la parte superior. Elementos de la navbar:
      • Logotipo o icono del portal.
      • Nombre del sitio: Projects Portal.
      • Enlaces externos:
      • Botón opcional para modo oscuro/claro.
    • Hero Section: Es la sección principal visible al cargar la página. Contenido:
      • Etiqueta superior: Laboratorio Personal en la Nube.
      • Título principal: Projects Portal.
      • Subtítulo con la propuesta de valor.
      • Descripción breve del portal.
      • Botones de acción:
        • Ver Proyectos.
        • GitHub.
      • Ilustración isométrica de un servidor VPS conectado a la nube.
    • Información del VPS: Sección formada por tarjetas con las características principales del servidor.
      • Sistema operativo.
      • CPU.
      • Memoria RAM.
      • Almacenamiento.
      • IP pública.
      • Dominio principal.
    • Stack Tecnológico: Grid con iconos y nombres de las tecnologías utilizadas. Tecnologías representadas:
      • Linux.
      • Docker.
      • Flask.
      • Nginx.
      • PostgreSQL.
      • Redis.
      • Python.
      • Power BI.
      • LangChain.
      • Machine Learning.
    • Proyectos Desplegados: Sección principal del portal, el contenido se distribuye en tarjetas
      • Icono o imagen representativa.
      • Nombre del proyecto.
      • Descripción breve.
      • Tecnologías utilizadas.
      • Botones de acción:
        • Open App.
        • Documentation.
        • Source Code.
        • API Docs (solo si existe API).
    • Recursos y Enlaces: Bloque con accesos a recursos externos.
    • Footer: Pie de página visible al final del sitio.
      • Nombre del autor.
      • Cargo o marca personal.
      • Correo electrónico.
      • Ubicación.
      • Iconos a redes profesionales.
      • Copyright.

    Flujo de interacción del usuario

    1. El visitante accede a projects.fernandorioseco.es.
    2. Visualiza la presentación del laboratorio.
    3. Consulta la infraestructura y tecnologías utilizadas.
    4. Explora las tarjetas de proyectos.
    5. Accede a:
      • La aplicación en producción.
      • La documentación del proyecto.
      • El código fuente.
      • La documentación de la API, si existe.
    6. Navega a GitHub, blog o LinkedIn.

    Objetivo de la interfaz

    La UI debe transmitir una imagen:

    • Profesional.
    • Moderna.
    • Tecnológica.
    • Clara y fácil de navegar.

    Al mismo tiempo, debe funcionar como un punto central desde el que cualquier visitante pueda comprender tu infraestructura y acceder rápidamente a todos los proyectos de tu portfolio.

    2. Setup de la Aplicación y Control de Versiones

    Setup del Proyecto

    En esta fase realizaremos la configuración inicial del proyecto en nuestro entorno local. El objetivo es preparar la estructura base de la aplicación, crear un entorno virtual, instalar las dependencias necesarias y verificar que Flask funciona correctamente antes de comenzar con el desarrollo de la interfaz. En esta fase desarrollamos:

    • El directorio raíz del proyecto.
    • Un entorno virtual de Python.
    • Librerías necesarias
    • El archivo requirements.txt.
    • La estructura de carpetas del proyecto.
    • Los archivos base de la aplicación.
    • Implementar una aplicación Flask mínima.
    • Crear el repositorio en GitHub.

    Implementar una aplicación Flask mínima

    #app/__init__.py
    from flask import Flask
    
    def create_app():
        app = Flask(__name__)
    
        from app.routes import main
        app.register_blueprint(main)
    
        return app
        
        
    # app/routes.py
    from flask import Blueprint, render_template
    
    main = Blueprint("main", __name__)
    
    @main.route("/")
    def home():
        return render_template("index.html")
    
    
    
    # run.py
    from app import create_app
    
    app = create_app()
    
    if __name__ == "__main__":
        app.run(debug=True)
    
    
    #wsgi.py
    from app import create_app
    
    app = create_app()
    
    
    #app/templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Projects Portal</title>
    </head>
    <body>
        <h1>Projects Portal</h1>
        <p>Personal VPS Lab for DevOps, Data Science, MLOps and AI Engineering.</p>
    </body>
    </html>

    Ejecutar la aplicación en local

    python run.py

    Abrimos el navegador en:

    http://127.0.0.1:5000

    Si todo ha ido correctamente, veremos la primera versión funcional del portal.

    Crear un archivo projects.json de ejemplo

    Aunque todavía no lo utilizaremos, podemos dejar preparado el archivo que almacenará la información de los proyectos. en app/data/projects.json

    [
      {
        "name": "CO2 Emissions Dashboard",
        "description": "Análisis interactivo de emisiones de vehículos.",
        "technologies": ["Python", "Pandas", "Power BI", "Streamlit"],
        "app_url": "https://co2.projects.fernandorioseco.es",
        "article_url": "https://fernandorioseco.es/co2-emissions-dashboard",
        "github_url": "https://github.com/fernandorioseco/co2-emissions-dashboard",
        "api_docs_url": null
      }
    ]
    

    Control de versiones con Git y Github

    1. Crear el archivo .gitignore.
    2. Inicializar el repositorio Git.
    3. Realizar el primer commit.
    4. Crear el repositorio remoto en GitHub.
    5. Subir el código al repositorio.
    6. Establecer la rama principal main.

    3. Desarrollo local

    Arquitectura de Plantillas

    La interfaz del Projects Portal se construye siguiendo una arquitectura de plantillas modular basada en el motor de plantillas Jinja, integrado de forma nativa en Flask. Este enfoque permite dividir la interfaz en componentes independientes y reutilizables, facilitando el mantenimiento y la escalabilidad de la aplicación.

    La finalidad de esta arquitectura es separar la estructura visual del sitio en piezas con responsabilidades bien definidas:

    • Una plantilla base común.
    • Una página principal.
    • Componentes reutilizables.

    Gracias a esta organización, cada sección de la interfaz puede desarrollarse y modificarse de forma aislada. Las plantillas HTML se almacenan en el directorio: app/templates/. La estructura adoptada es la siguiente:

    app/templates/
    ├── base.html
    ├── index.html
    └── components/
        ├── navbar.html
        ├── hero.html
        ├── vps_info.html
        ├── tech_stack.html
        ├── projects.html
        ├── resources.html
        └── footer.html
    ElementoDescripción
    base.htmlPlantilla base de la aplicación. Define la estructura HTML común del sitio, incluyendo la cabecera del documento, la carga de estilos, la barra de navegación, el bloque de contenido principal y el footer.
    index.htmlPágina principal del portal. Ensambla secuencialmente los distintos componentes visuales mediante instrucciones {% include %}. Contiene muy poca lógica y actúa como orquestador de la interfaz.
    components/Directorio que contiene las secciones independientes que conforman la página principal. Cada archivo representa un bloque funcional concreto.
    navbar.htmlBarra de navegación superior.
    hero.htmlSección principal de presentación del portal.
    vps_info.htmlInformación técnica del servidor VPS.
    tech_stack.htmlTecnologías y herramientas utilizadas en el laboratorio.
    projects.htmlListado dinámico de proyectos desplegados.
    resources.htmlEnlaces externos a documentación, GitHub, blog y LinkedIn.
    footer.htmlPie de página del sitio.

    Integración con Flask

    La ruta principal devuelve la plantilla:

    return render_template("index.html", projects=projects)

    Jinja2 se encarga automáticamente de resolver la herencia e inclusiones.

    base.html – plantilla base de la aplicación

    El archivo base.html constituye la plantilla base del Projects Portal. Su función es definir la estructura HTML común que compartirán todas las páginas del sitio. Este enfoque permite centralizar los elementos globales de la interfaz y evitar la duplicación de código. Ubicación del archivo: app/templates/base.html

    Propósito

    La plantilla base se encarga de definir la estructura general del documento HTML e incluir aquellos elementos que deben estar presentes en todas las páginas de la aplicación. En concreto, base.html incorpora:

    • Definir la estructura HTML general del documento.
    • Configurar las etiquetas meta necesarias.
    • Establecer un título por defecto.
    • Cargar la hoja de estilos.
    • Incluir la barra de navegación.
    • Definir un bloque de contenido que heredarán las páginas hijas.
    • Incluir el footer.

    Estructura conceptual

    [ DOCUMENTO HTML ] (Template Maestro)
    
     ├── [ HEAD ] (Configuración Invisible)
     │    ├── Metadatos (Viewport, Charset)
     │    ├── Título Dinámico {% block title %}
     │    └── Estilos Propios (styles.css)
    
     └── [ BODY ] (Estructura Visible)
    
          ├── [ HEADER ] ─── {% include "navbar.html" %}  ── (Componente Reutilizable)
    
          ├── [ MAIN ] ───── {% block content %} ──────── (Espacio Inyectable/Variable)
          │                                                *Aquí se carga el contenido*
          │                                                *específico de cada ruta*
    
          └── [ FOOTER ] ─── {% include "footer.html" %}  ── (Componente Reutilizable)

    Elementos de Jinja2 utilizados

    • title: este permite definir un título por defecto y sobrescribirlo desde plantillas hijas.
    • content: reserva el espacio donde se insertará el contenido específico de cada página.
    • include: inserta componentes reutilizables como la barra de navegación y el footer.
    • url_for(): genera automáticamente la URL correcta para los archivos estáticos.

    Relación con el resto de plantillas

    base.html es utilizada por index.html mediante la instrucción: {% extends "base.html" %}. A partir de ese momento, index.html solo necesita definir el contenido correspondiente al bloque content.

    Flujo de renderizado

    index.html  
    └── extends base.html           
            ├── navbar.html           
            ├── content           
            └── footer.html

    navbar.html – barra de navegación

    La barra de navegación es el componente situado en la parte superior de la página y proporciona acceso a recursos externos relevantes. Al tratarse de un elemento común a todas las páginas del sitio, se implementa como un componente independiente que es incluido desde base.html. Ubicación del archivo: app/templates/components/navbar.html

    Propósito del componente

    • Identificar visualmente el sitio mediante el nombre del portal.
    • Proporcionar acceso a recursos externos como GitHub, el blog y LinkedIn.

    Elementos:

    • Identidad del sitio: Projects Portal
    • Enlaces externos: GitHub, Blog, LinkedIn

    Estructura conceptual

    [ NAV: .navbar ] (Marco Principal: Fondo oscuro + Sombra)
     └── [ .container ] (Centrado del contenido)
          ├── [ .navbar-brand ] ─ "Projects Portal" (Logo/Título)
    
          ├── [ .navbar-toggler ] ─ [ Icono Hamburguesa ] (Solo visible en móviles)
    
          └── [ .collapse .navbar-collapse ] (Contenedor colapsable)
               └── [ .navbar-nav ] (Lista de enlaces: Alineada a la derecha)
                    ├── [ .nav-item ] ── [ .nav-link ] ─ "GitHub" (Externo ↗)
                    ├── [ .nav-item ] ── [ .nav-link ] ─ "Blog"   (Externo ↗)
                    └── [ .nav-item ] ── [ .nav-link ] ─ "LinkedIn" (Externo ↗)

    Enlaces externos

    Los enlaces externos se abren en una nueva pestaña mediante target="_blank".

    Relación con base.html

    La plantilla base incorpora este componente mediante: {% include "components/navbar.html" %}. De esta forma, cualquier modificación realizada en navbar.html se reflejará automáticamente en todas las páginas del sitio.

    Diseño visual

    La navbar se diseñará con las siguientes características:

    • Posición fija o sticky en la parte superior.
    • Fondo blanco o semitransparente.
    • Sombra ligera.
    • Distribución horizontal.
    • Adaptación responsive para dispositivos móviles.

    hero.html – sección principal de presentación

    Define la sección superior de la página principal y constituye el primer elemento visual que verá el visitante al acceder al portal. Su objetivo es comunicar de forma inmediata qué es Projects Portal, cuál es su propósito y qué tipo de proyectos alberga. Ubicación del archivo: app/templates/components/hero.html

    Elementos: La sección estará compuesta por dos columnas.

    • Columna izquierda
      • Badge superior: Personal VPS Lab.
      • Título principal: Projects Portal.
      • Subtítulo descriptivo.
      • Breve descripción del portal.
      • Botones de acción:
        • View Projects.
        • GitHub.
    • Columna derecha
      • Ilustración isométrica del VPS.

    Estructura conceptual

    [ SECTION: .hero ] (Contenedor de alto impacto / Fondo)
     └── [ .container .hero-content ] (Alineación Flex/Grid)
    
          ├── [ .hero-text ] (Bloque de Información - Izquierda/Centro)
          │    ├── [ .hero-badge ] ─ "Personal VPS Lab" (Categorización)
          │    ├── [ .hero-title ] ─ "Projects Portal" (H1 - Mensaje Principal)
          │    ├── [ .hero-subtitle ] ─ (Propuesta técnica: DevOps, IA, etc.)
          │    ├── [ .hero-description ] ─ (Detalle del ecosistema: APIs, Dashboards)
          │    └── [ .hero-actions ] (Llamada a la acción / CTA)
          │         ├── [ .btn-primary ] ─ "View Projects"
          │         └── [ .btn-secondary ] ─ "GitHub"
    
          └── [ .hero-image ] (Bloque Visual - Derecha)
               └── [ img ] ─ "vps-illustration.png" (Ilustración técnica)

    Mensaje principal

    La sección presentará el portal como: Un laboratorio personal desplegado en un VPS, orientado a DevOps, Ciencia de Datos, MLOps e Ingeniería de Inteligencia Artificial.

    Diseño visual

    El Hero Section tendrá las siguientes características:

    • Fondo azul oscuro.
    • Texto en color blanco.
    • Diseño en dos columnas.
    • Botones de llamada a la acción.
    • Imagen ilustrativa a la derecha.
    • Amplio espaciado vertical.

    Relación con index.html

    La página principal incluirá este componente mediante: {% include "components/hero.html" %}

    vps_info.html – infraestructura del VPS

    El componente vps_info.html muestra un resumen de las principales características técnicas del servidor donde se alojan el Projects Portal y el resto de aplicaciones del portfolio. Esta sección aporta contexto técnico y refuerza la credibilidad del portal al evidenciar que los proyectos se ejecutan sobre una infraestructura real administrada por el propio autor. Ubicación del archivo: app/templates/components/vps_info.html

    Propósito

    La sección tiene como objetivo presentar, de forma visual y estructurada, la configuración básica del VPS utilizado como entorno de despliegue. Permite al visitante conocer:

    • El sistema operativo del servidor.
    • Los recursos de CPU y memoria.
    • La capacidad de almacenamiento.
    • La IP pública.
    • El dominio asociado al portal.

    Información mostrada

    • Sistema Operativo.
    • CPU.
    • RAM.
    • Disco.
    • IP pública.
    • Dominio.

    Diseño visual

    • Un título
    • Una cuadrícula de tarjetas.
    • Un icono SVG por cada métrica.
    • El nombre del atributo.
    • Su valor correspondiente.

    Estructura conceptual

    [ SECTION: #vps-info ] (Ancla de navegación + Fondo de sección)
     └── [ .container ] (Alineación central)
          ├── [ .section-header ]
          │    └── [ h2 ] ── "Infraestructura del VPS"
    
          └── [ .vps-grid ] (Contenedor Layout: Probablemente Grid o Flexbox)
               ├── [ .vps-card ] ─ (OS: Ubuntu 24.04)
               ├── [ .vps-card ] ─ (CPU: 4 vCPU)
               ├── [ .vps-card ] ─ (RAM: 8 GB)
               ├── [ .vps-card ] ─ (Disco: 160 GB SSD)
               ├── [ .vps-card ] ─ (IP: 186.xxx...)
               └── [ .vps-card ] ─ (Dominio: projects.fernandorioseco.es)

    Recursos gráficos

    Los iconos utilizados en esta sección se almacenarán en: app/static/img/icons/

    Relación con index.html

    La página principal incluirá esta sección mediante: {% include "components/vps_info.html" %}

    projects.html – catálogo dinámico de proyectos

    El componente projects.html es la sección más importante del portal, ya que muestra las aplicaciones desplegadas en el VPS y proporciona acceso directo a cada una de ellas.

    A diferencia del resto de secciones, su contenido se genera dinámicamente a partir de los datos almacenados en projects.json. El archivo se ubica en: app/templates/components/projects.html.

    La sección incorpora un buscador dinámico que permite filtrar proyectos por cualquier término relevante, como tecnologías, categorías, nombre o palabras incluidas en la descripción. El buscador permite al usuario encontrar proyectos escribiendo uno o varios términos de búsqueda.

    Cada tarjeta de proyecto almacena en el atributo data-search el contenido que será evaluado por JavaScript. Este atributo incluye: nombre del proyecto, descripción y tecnologías utilizadas.

    Lógica de filtrado

    El archivo main.js:

    1. Captura el contenido del input.
    2. Divide el texto por comas.
    3. Normaliza los términos.
    4. Recorre todas las tarjetas.
    5. Muestra solo las que contienen todos los términos.

    Propósito

    Esta sección tiene como objetivo presentar cada proyecto del portfolio mediante una tarjeta con información resumida y enlaces relevantes. Cada tarjeta permitirá al visitante acceder a:

    • La aplicación desplegada.
    • El artículo de documentación del proyecto.
    • El repositorio de código fuente en GitHub.
    • La documentación de la API, cuando exista.

    Fuente de datos

    Los datos de los proyectos se almacenarán en el archivo: app/data/projects.json. Cada registro del archivo contendrá toda la información necesaria para construir una tarjeta.

    Información mostrada en cada tarjeta

    • Nombre del proyecto.
    • Descripción breve.
    • Tecnologías utilizadas.
    • Enlaces de acción.

    Estructura conceptual de una tarjeta

    [ DATOS: Lista de Proyectos ] 
    
          ▼ (Ciclo for project in projects)
    [ ARTICLE: .project-card ]  <──────────────────┐
     │                                             │
     ├── [ .project-title ] ─── {{ project.name }} │
     │                                             │
     ├── [ .project-description ] ─ {{ desc }}     │ (Repite por cada
     │                                             │  proyecto en la lista)
     ├── [ .project-tech ] ────────────────────────┤
     │    └── [ .tech-badge ] ─ {{ tech }} (Bucle) │
     │                                             │
     └── [ .project-links ] ───────────────────────┘
          ├── App URL
          ├── Documentation
          ├── GitHub
          └── [ IF: API URL ] ── (Carga condicional)

    Generación dinámica con Jinja2

    La plantilla recorrerá la lista projects enviada desde Flask mediante un bucle for. Por cada elemento del JSON se generará automáticamente una nueva tarjeta.

    Relación con Flask

    La ruta principal cargará los datos y los enviará a la plantilla: return render_template("index.html", projects=projects)

    Archivos involucrados

    La página principal incluirá esta sección mediante: {% include "components/projects.html" %}, en la acción de búsqueda se involucran :

    ArchivoFunción
    projects.htmlCampo de búsqueda y atributo data-search.
    main.jsLógica de filtrado.
    styles.cssEstilos del buscador.
    base.htmlCarga del archivo JavaScript.

    resources.html – recursos y enlaces externos

    El componente resources.html agrupa los enlaces externos más relevantes relacionados con el Projects Portal y con el perfil profesional del autor. Su objetivo es ofrecer al visitante un acceso rápido a la documentación técnica, al código fuente y a los perfiles profesionales asociados al proyecto. Ubicación del archivo: app/templates/components/resources.html

    Propósito

    Esta sección actúa como un bloque complementario al catálogo de proyectos. Mientras que cada tarjeta de proyecto contiene enlaces específicos, resources.html reúne los recursos generales del portal y del autor.

    Recursos que se mostrarán

    Información mostrada en cada tarjeta

    • Nombre del recurso.
    • Descripción breve.
    • Botón o enlace de acceso.

    Diseño visual

    La sección se mostrará como una cuadrícula de tarjetas o como una fila de enlaces destacados.

    Elementos visuales

    • Título de la sección.
    • Breve texto descriptivo.
    • Tarjetas con icono SVG.
    • Enlaces externos.

    Estructura conceptual

    [ SECTION: #resources ] (Contenedor de cierre / Footer-Prep)
     └── [ .container ] (Alineación y consistencia visual)
          ├── [ .section-header ]
          │    ├── [ h2 ] ── "Resources"
          │    └── [ p ] ─── (Resumen de contenido externo)
    
          └── [ .resources-grid ] (Layout de rejilla para acceso rápido)
               ├── [ .resource-card ] ─ (Documentation ➜ Blog)
               ├── [ .resource-card ] ─ (GitHub Repository ➜ Source Code)
               ├── [ .resource-card ] ─ (LinkedIn ➜ Professional Profile)
               └── [ .resource-card ] ─ (Website ➜ Portfolio)

    Relación con index.html

    La página principal incluirá esta sección mediante: {% include "components/resources.html" %}

    footer.html – pie de página

    El componente footer.html define la sección final del sitio y contiene información general sobre el portal y enlaces complementarios. Aunque es un elemento sencillo, cumple una función importante al cerrar visualmente la página y ofrecer referencias adicionales al visitante. Ubicación del archivo: app/templates/components/footer.html

    Propósito

    • Mostrar información de copyright.
    • Identificar al autor del portal.
    • Incluir enlaces a recursos relevantes.
    • Cerrar visualmente la página de forma consistente.

    Información que incluirá

    • Nombre del portal.
    • Año actual.
    • Nombre del autor.
    • Enlaces a GitHub, Blog y LinkedIn.

    Estructura conceptual

    [ FOOTER: .footer ] (Bloque de cierre / Estilo de fondo)
     └── [ .container .footer-content ] (Alineación y distribución espacial)
    
          ├── [ .footer-text ] ─── "© 2026 Projects Portal · Fernando Rioseco"
          │                        (Propiedad Intelectual / Marca Personal)
    
          └── [ .footer-links ] ── (Navegación Secundaria / Social)
               ├── [ Enlace ] ─ GitHub
               ├── [ Enlace ] ─ Blog
               └── [ Enlace ] ─ LinkedIn

    Diseño visual

    • Fondo oscuro o gris claro.
    • Texto de tamaño reducido.
    • Enlaces discretos.
    • Distribución horizontal en escritorio.
    • Apilado vertical en dispositivos móviles.

    Relación con base.html

    La plantilla base lo incluye mediante: {% include "components/footer.html" %}

    index.html – ensamblado de la página principal

    El archivo index.html es la plantilla principal del Projects Portal. Su función no es definir el contenido detallado de cada sección, sino ensamblar todos los componentes que conforman la página de inicio. Actúa como un punto de integración donde se combinan la plantilla base y los distintos componentes HTML desarrollados previamente. Ubicación del archivo: app/templates/index.html

    Propósito

    index.html tiene tres responsabilidades principales:

    1. Heredar la estructura general definida en base.html.
    2. Definir el contenido del bloque principal.
    3. Incluir, en el orden correcto, todos los componentes de la interfaz.

    Componentes incluidos

    La página principal incorpora las siguientes secciones:

    1. hero.html
    2. vps_info.html
    3. tech_stack.html
    4. projects.html
    5. resources.html

    La barra de navegación y el footer no se incluyen directamente aquí, ya que son incorporados automáticamente por base.html.

    Relación con base.html

    La plantilla comienza con: {% extends "base.html" %}. Esto indica que utilizará la estructura general definida en la plantilla base.

    Definición del contenido principal

    Todo el contenido de la página se inserta dentro del bloque:

    {% block content %}
    ...
    {% endblock %}

    Estructura conceptual

    [ ARCHIVO: base.html ] (El Cascarón)
    
     ├── [ BLOQUE: content ] <─── (Inyección desde este archivo)
     │    │
     │    ├── [ Hero.html ] ───────── (Impacto Visual / Intro)
     │    ├── [ vps_info.html ] ───── (Hardware / Especificaciones)
     │    ├── [ tech_stack.html ] ─── (Herramientas / Lenguajes)
     │    ├── [ projects.html ] ───── (Portafolio / Apps)
     │    └── [ resources.html ] ──── (Enlaces / Documentación)
    
     └── [ Footer ] (Desde base.html)

    Flujo de renderizado

    Cuando Flask renderiza index.html:

    1. Carga base.html.
    2. Sustituye el bloque content.
    3. Inserta los componentes incluidos.
    4. Genera el HTML final enviado al navegador.

    Arquitectura CSS

    Una vez definida la estructura HTML de la aplicación, el siguiente paso consiste en desarrollar la capa de presentación mediante hojas de estilo CSS. En el Projects Portal se ha optado por utilizar CSS puro, sin frameworks externos como Bootstrap, con el objetivo de mantener un control total sobre el diseño y comprender en detalle el comportamiento visual de cada componente. Todos los estilos del proyecto se almacenan inicialmente en: app/static/css/styles.css

    La arquitectura CSS tiene como finalidad:

    • Centralizar todos los estilos de la aplicación.
    • Mantener una organización clara y escalable.
    • Reutilizar reglas comunes.
    • Facilitar el mantenimiento.
    • Garantizar consistencia visual.

    El archivo styles.css se estructurará en bloques claramente diferenciados.

    styles.css
    ├── Variables CSS
    ├── Reset básico
    ├── Estilos globales
    ├── Componentes reutilizables
    ├── Layout
    ├── Estilos por sección
    └── Media queries

    La arquitectura CSS del Projects Portal se basa en un único archivo styles.css, organizado en bloques lógicos que incluyen variables, estilos globales, componentes reutilizables y reglas específicas para cada sección de la interfaz.

    El Projects Portal ha sido diseñado para adaptarse correctamente a distintos tamaños de pantalla, garantizando una experiencia de usuario adecuada tanto en ordenadores de escritorio como en tablets y teléfonos móviles.

    El objetivo del diseño responsive es que todos los elementos de la interfaz se ajusten automáticamente al espacio disponible sin necesidad de crear versiones separadas de la página.

    Breakpoints

    La adaptación a diferentes resoluciones se realiza mediante media queries. Los puntos de ruptura utilizados se corresponden con los tamaños habituales de dispositivos:

    • Móviles pequeños.
    • Tablets.
    • Portátiles.
    • Monitores de escritorio.

    Técnicas utilizadas

    Para lograr el comportamiento responsive se emplean:

    • CSS Grid.
    • Flexbox.
    • Media queries.
    • Unidades relativas (rem, %, fr).
    • Imágenes fluidas (max-width: 100%).

    Resultado preliminar de la estructura + css

    Haz clic en la imagen para ver.

    Incorporación de Recursos Visuales y Ajustes Finales de UI

    El propósito es transformar una interfaz funcional en una interfaz visualmente pulida.

    • Descarga de iconos
    • Optimización de imágenes
    • Integración de logos tecnológicos
    • Ilustración del Hero Section
    • Ajustes de CSS
    • Refinamiento de tipografía y colores
    • Corrección de detalles responsive
    • Revisión visual final

    Resultado final de la aplicación web

    4. Configuración del dominio

    Una vez completado el desarrollo local de la aplicación, el siguiente paso consiste en asociarla a un dominio público para que pueda ser accesible desde Internet. En este proyecto, la aplicación Flask se publicará en el subdominio: projects.fernandorioseco.es

    La configuración del dominio permite:

    • Asociar la aplicación a una URL pública.
    • Dirigir el tráfico al VPS.
    • Servir la aplicación mediante Nginx.
    • Habilitar HTTPS con certificados SSL.

    Arquitectura general

    Usuario
    
    projects.fernandorioseco.es
    
    DNS
    
    IP pública del VPS
    
    Nginx
    
    Gunicorn
    
    Flask Application
    

    Crear el registro DNS

    En el proveedor donde gestionas tu dominio, debes crear un registro de tipo A.

    CampoValor
    TipoA
    Nombreprojects
    ValorIP pública del VPS
    TTLAuto

    Verificar la propagación DNS

    Una vez creado el registro, el subdominio debe resolver hacia la IP del servidor.

    nslookup projects.fernandorioseco.es

    5. Preparación del VPS

    Una vez que la aplicación ha sido desarrollada localmente y el subdominio ya apunta al servidor, el siguiente paso consiste en preparar el VPS para alojar el proyecto.

    En esta fase se crea la estructura de directorios en el servidor, se descarga el código fuente desde GitHub, se configura un entorno virtual de Python y se instalan las dependencias necesarias para ejecutar la aplicación.

    La preparación del VPS tiene como finalidad:

    • Crear el directorio donde residirá el proyecto: /var/www.
    • Descargar el código fuente desde el repositorio remoto.
    • Configurar un entorno virtual aislado.
    • Instalar las librerías definidas en requirements.txt.
    • Verificar que la aplicación puede ejecutarse en el servidor.
    # Crear la carpeta del proyecto
    sudo mkdir -p /var/www/projects-portal
    
    # Cambiar propietario y grupo de los archivos del proyecto
    sudo chown -R $USER:$USER /var/www/projects-portal
    
    # clonar repositorio desde github
    git clone https://github.com/fer78/projects-portal.git /var/www/projects-portal

    Crear entorno virtual

    # en sistemas Debian/Ubuntu no viene instalado por defecto
    sudo apt install python3.12-venv
    
    # Accede al directorio
    cd /var/www/projects-portal
    
    # Crea el entorno virtual y activalo
    python3 -m venv venv
    source venv/bin/activate
    
    # Instalar dependencias
    pip install --upgrade pip
    pip install -r requirements.txt
    
    # comprobar que las dependencias se instalaron correctamente
    pip list

    Probar la aplicación Flask.

    python run.py

    Si todo es correcto, Flask iniciará el servidor de desarrollo.

    Probar Gunicorn

    gunicorn --bind 127.0.0.1:8000 wsgi:app

    Este comando confirma que la aplicación está lista para ejecutarse en producción.

    Archivos implicados

    ArchivoFunción
    requirements.txtLista de dependencias Python.
    wsgi.pyPunto de entrada para Gunicorn.
    venv/Entorno virtual del proyecto.
    run.pyScript de desarrollo local.

    6. Configuración del servicio con Gunicorn y systemd

    Una vez que la aplicación Flask funciona correctamente en el VPS, el siguiente paso consiste en ejecutarla como un servicio del sistema. Para ello utilizaremos:

    • Gunicorn como servidor WSGI.
    • systemd como gestor de servicios de Linux.

    Esta configuración permite que la aplicación se inicie automáticamente al arrancar el servidor y se reinicie en caso de fallo.

    La configuración del servicio persigue los siguientes objetivos:

    • Ejecutar la aplicación Flask en segundo plano.
    • Iniciar el servicio automáticamente en cada reinicio.
    • Reiniciar el proceso si se detiene inesperadamente.
    • Centralizar los logs en journalctl.

    Arquitectura del servicio

    systemd
    
    Gunicorn
    
    wsgi.py
    
    Flask Application

    Crear el archivo de servicio

    sudo nano /etc/systemd/system/projects-portal.service
    

    Definir la unidad de servicio

    [Unit]
    Description=Gunicorn service for Projects Portal
    After=network.target
    
    [Service]
    User=tu usuario
    Group=www-data
    WorkingDirectory=/var/www/projects-portal
    Environment="PATH=/var/www/projects-portal/venv/bin"
    
    ExecStart=/var/www/projects-portal/venv/bin/gunicorn \
        --workers 3 \
        --bind 127.0.0.1:8000 \
        wsgi:app
    
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    

    Poner a punto el servicio

    # reiniciar systemd
    sudo systemctl daemon-reload
    
    # habilitar el servicio
    sudo systemctl start projects-portal
    
    # verificar el estado
    sudo systemctl status projects-portal

    Comandos de administración

    # Consultar logs
    sudo journalctl -u projects-portal -f
    
    # Reiniciar
    sudo systemctl restart projects-portal
    
    # Detener
    sudo systemctl stop projects-portal
    
    # Deshabilitar
    sudo systemctl disable projects-portal

    Resultado esperado

    Al finalizar esta fase:

    • Gunicorn se ejecutará como servicio del sistema.
    • La aplicación arrancará automáticamente tras cada reinicio.
    • Los logs estarán disponibles mediante journalctl.
    • El proceso se reiniciará automáticamente ante fallos.

    7. Configuración de Nginx y HTTPS

    Una vez que la aplicación Flask se ejecuta correctamente mediante Gunicorn y systemd, el siguiente paso consiste en publicarla en Internet a través de un servidor web. Para ello utilizaremos:

    • Nginx como proxy inverso.
    • Certbot para obtener certificados SSL.
    • Let’s Encrypt como autoridad certificadora.

    Esta etapa permite:

    • Asociar el subdominio projects.fernandorioseco.es a la aplicación.
    • Redirigir las peticiones HTTP hacia Gunicorn.
    • Servir archivos estáticos directamente.
    • Habilitar HTTPS.
    • Redirigir automáticamente de HTTP a HTTPS.

    Arquitectura final

    Usuario
       
    https://projects.fernandorioseco.es
       
    Nginx (puertos 80 y 443)
       
    Gunicorn (127.0.0.1:8000)
       
    Flask Application

    Instalar y Configurar Nginx

    El siguiente paso es crear un archivo de configuración de Nginx para la aplicación Flask. Ese archivo define cómo Nginx debe responder cuando alguien acceda a projects.fernandorioseco.es.

    sudo apt install nginx
    sudo nano /etc/nginx/sites-available/projects-portal
    server {
        listen 80;
        server_name projects.fernandorioseco.es;
    
        location /static/ {
            alias /var/www/projects-portal/app/static/;
        }
    
        location / {
            proxy_pass http://127.0.0.1:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }

    Activar el sitio

    sudo ln -s /etc/nginx/sites-available/projects-portal \
               /etc/nginx/sites-enabled/
               
    # Validar la configuración
    sudo nginx -t
    
    # Recargar Nginx
    sudo systemctl reload nginx
    

    Configurar HTTPS con Let’s Encrypt

    Generar el certificado SSL con Let’s Encrypt y Certbot.

    sudo certbot --nginx -d projects.fernandorioseco.es

    Verificar acceso seguro

    La aplicación deberá quedar disponible en:

    https://projects.fernandorioseco.es

    Flujo de resolución del dominio

    1. El usuario accede al subdominio.
    2. DNS devuelve la IP del VPS.
    3. Nginx recibe la petición.
    4. Nginx reenvía la petición a Gunicorn.
    5. Gunicorn ejecuta Flask.
    6. Flask devuelve la página renderizada.

    8. Actualización y Mantenimiento

    Una vez desplegado el portal, es importante definir un procedimiento claro para actualizar el código, incorporar nuevos proyectos y mantener la aplicación operativa en el tiempo. La arquitectura adoptada, basada en archivos JSON individuales y control de versiones con Git, simplifica enormemente estas tareas de establecer un flujo de trabajo para:

    • Desplegar nuevas versiones del código.
    • Añadir proyectos al catálogo.
    • Corregir errores.
    • Reiniciar servicios.
    • Supervisar el funcionamiento del portal.

    Flujo de actualización del código

    El proceso habitual consiste en:

    1. Realizar cambios en el entorno local (añadir nuevos proyectos o funcionalidades)
    2. Confirmar los cambios en Git.
    3. Enviar los cambios al repositorio remoto.
    4. Actualizar el VPS mediante git pull.
    5. Reiniciar el servicio.
    # ve a la carpeta del proyecto
    cd /var/www/projects-portal
    
    # Actualiza los ficheros desde github
    git pull origin main
    
    # reinicia el servicio 
    sudo systemctl restart projects-portal
    
    # verifica el funcionamiento
    sudo systemctl status projects-portal

    El mantenimiento del portal se reduce a actualizar el repositorio Git, añadir nuevos archivos JSON y reiniciar el servicio Gunicorn cuando sea necesario.

    Script de Actualización del Portal

    En vez de estar haciendo secuencias de comandos en cada actualización, creamos un script en Bash que agilice el proceso. Este script descargará los últimos cambios desde GitHub, reiniciará el servicio de Gunicorn y mostrará el estado final de la aplicación.

    Crear el Script

    nano /var/www/projects-portal/update.sh
    #!/bin/bash
    
    set -e
    
    echo "=========================================="
    echo " Updating Projects Portal"
    echo "=========================================="
    
    cd /var/www/projects-portal
    
    echo "Pulling latest changes from GitHub..."
    git pull origin main
    
    echo "Restarting Gunicorn service..."
    sudo systemctl restart projects-portal
    
    echo "Checking service status..."
    sudo systemctl status projects-portal --no-pager
    
    echo "=========================================="
    echo " Update completed successfully"
    echo "=========================================="
    

    Permisos de ejecución y añadir al PATH.

    # permisos de ejecucion
    chmod +x /var/www/projects-portal/update.sh
    
    # añadir al path para ejecutar desde cualquier ubicacion
    sudo ln -s /var/www/projects-portal/update.sh /usr/local/bin/update-portal

    Ahora el script de actualización es un comando que puede ejecutarse desde cualquier ubicación

    update-portal

    9. Mejoras y Evolución

    El Projects Portal se ha diseñado con una arquitectura modular y escalable que facilita la incorporación de nuevas funcionalidades. A medida que el catálogo crezca, el portal puede evolucionar desde una página estática hacia una plataforma más avanzada de gestión y visualización de proyectos.

    Posibles mejoras

    • Buscador avanzado: Filtros por tecnología, por tipo de proyecto u ordenación.
    • Métricas del VPS: CPU, memoria, uso de disco, uptime, etc.
    • Panel de administración: Crear y editar proyectos desde una interfaz web, subir imágenes y recursos.
    • Base de datos: migración desde archivos JSON a PostgreSQL.
    • API REST: Exponer los proyectos mediante una API desarrollada con FastAPI.
    • Integración con GitHub: mostrar automáticamente estrellas, forks y fecha de última actualización.
    • Dashboards embebidos: integrar aplicaciones desarrolladas con Streamlit, Dash o Gradio.

    Conclusiones

    El desarrollo de Projects Portal ha permitido construir una aplicación web completa utilizando una arquitectura moderna basada en Python y Flask, con despliegue profesional sobre un VPS Linux.

    Aunque funcionalmente se trata de un portal sencillo, el proyecto integra todos los componentes fundamentales que intervienen en el ciclo de vida de una aplicación web en producción: desarrollo local, control de versiones, despliegue, automatización de servicios, configuración del servidor web y publicación segura mediante HTTPS.

    Conocimientos aplicados

    A lo largo del proyecto se han puesto en práctica competencias técnicas de distintas áreas.

    Desarrollo Backend

    • Programación en Python.
    • Desarrollo web con Flask.
    • Uso de plantillas con Jinja2.
    • Lectura dinámica de archivos JSON.
    • Diseño modular de componentes.

    Frontend

    • HTML5 semántico.
    • CSS3 con diseño responsive.
    • JavaScript para búsqueda y filtrado.
    • Integración de recursos gráficos e iconografía.

    DevOps y Linux

    • Administración de Ubuntu.
    • Gestión de permisos y estructura de directorios.
    • Uso de entornos virtuales.
    • Automatización con systemd.
    • Despliegue con Gunicorn.
    • Configuración de Nginx.

    Redes e Infraestructura

    • Configuración de DNS.
    • Gestión de subdominios.
    • Resolución de nombres.
    • Configuración de HTTPS.
    • Certificados SSL con Let’s Encrypt.

    Control de versiones

    • Uso de Git.
    • Publicación en GitHub.
    • Flujo de despliegue basado en git pull.

    Diseño arquitectónico

    El proyecto ha sido diseñado siguiendo principios de modularidad y mantenibilidad:

    • Plantillas HTML desacopladas.
    • Archivos JSON individuales por proyecto.
    • Separación entre contenido, lógica y presentación.
    • Servicio persistente gestionado por systemd.
    • Proxy inverso con Nginx.

    Valor del proyecto

    Projects Portal cumple una doble función.

    • Portfolio técnico: Actúa como punto central para acceder a todos los proyectos desplegados.
    • Laboratorio práctico: Sirve como entorno real para aplicar conocimientos.

    Reflexión final

    Projects Portal demuestra la capacidad de diseñar, desarrollar y desplegar una aplicación web completa siguiendo prácticas profesionales de ingeniería de software e infraestructura.

    El proyecto integra desarrollo backend, frontend, administración de sistemas, redes y automatización, constituyendo una evidencia sólida de competencias en programación, análisis de datos, DevOps y tecnologías modernas de Inteligencia Artificial.