root f152379882
CI/CD Pipeline / Build & Deploy (pull_request) Successful in 22s
fix(ci): add concurrency guard + PR trigger + workflow_dispatch
Apply the same concurrency pattern used in the python-project-template:
- cancel-in-progress: false prevents the shared act_runner from
  cancelling in-progress steps when a new push lands
- pull_request trigger ensures PRs are validated before merge
- workflow_dispatch allows manual re-runs
2026-07-09 15:23:40 +00:00
2026-07-09 15:22:48 +00:00

David Aragón — Portfolio

Portfolio personal y blog técnico de David Aragón. Sitio estático construido con Astro 5, donde comparto proyectos en los que estoy trabajando (build in public), posts sobre IoT, desarrollo y decisiones técnicas, y una página de about con mi trayectoria.

Características

  • Home con hero, últimos 3 posts del blog, proyectos destacados y CTA de newsletter
  • Blog (/blog) con posts categorizados en technical, business y personal, con RSS en /rss.xml
  • Projects (/projects) con proyectos en estados active, development o completed
  • About (/about) con la trayectoria profesional completa
  • Sitemap autogenerado en /sitemap-index.xml por @astrojs/sitemap
  • Newsletter vía formulario en la home (acción /api/subscribe)
  • Type-safe content con Zod schemas en src/content/config.ts
  • Búsqueda y SEO: meta tags, Open Graph y RSS listos para compartir

Stack técnico

  • Astro 5 — framework de sitios estáticos con islands
  • TypeScript — tipado estricto en todo el código
  • Tailwind CSS 3 — utility-first CSS con @tailwindcss/typography para prose
  • Zod — validación de frontmatter en content collections
  • RSS vía @astrojs/rss
  • Sitemap vía @astrojs/sitemap
  • Nginx como servidor estático en el contenedor de producción
  • Docker multi-stage (Node para build, nginx para servir)
  • CI/CD con Gitea Actions en .gitea/workflows/ci-cd.yaml
  • Deploy automático a Portainer vía webhook

Quick start (local)

Requisitos: Node.js >= 18.14.1 (recomendado 20).

# 1. Instalar dependencias
npm install

# 2. Arrancar dev server con HMR
npm run dev
# -> http://localhost:4321

# 3. Build de producción (genera ./dist/)
npm run build

# 4. Preview local del build
npm run preview

Despliegue (producción)

El sitio se construye como imagen Docker y se publica en el registry de Gitea. Portainer hace pull y reinicia el contenedor cuando el CI dispara el webhook.

# Construir y servir localmente con Docker Compose
docker compose up --build
# -> http://localhost:8080

# Producción: pull de la imagen publicada por CI
docker compose -f docker-compose.prod.yml up -d
# -> http://localhost:3001

La imagen final (nginx:alpine) solo contiene los estáticos generados en ./dist/. Ver Dockerfile para detalles del multi-stage.

Cómo añadir contenido

Nuevo post de blog

Crea un archivo Markdown en src/content/blog/ con nombre YYYY-MM-DD-slug.md. El frontmatter debe cumplir el schema de src/content/config.ts:

---
title: "Título del post"
description: "Resumen corto para SEO y previews"
publishDate: 2026-07-09
author: "David Aragón"   # opcional, default: David Aragón
tags: ["tag1", "tag2"]
category: "technical"   # technical | business | personal
featured: false         # true para destacar en home
draft: false            # true para ocultar del sitio público
image: "/ruta/opcional.jpg"  # opcional
---

# Contenido del post en Markdown

Aparecerá automáticamente en /blog/<slug> y, si no es draft, en la home.

Nuevo proyecto

Crea un archivo Markdown en src/content/projects/ con frontmatter:

---
title: "Nombre del proyecto"
description: "Descripción de una línea"
url: "https://proyecto.example.com"
github: "https://github.com/user/repo"   # opcional
status: "development"   # active | development | completed
tags: ["React", "FastAPI"]
startDate: 2026-07-01
featured: true          # true para mostrar en home
image: "/ruta/opcional.jpg"  # opcional
---

# Descripción completa del proyecto en Markdown

Aparecerá en /projects/<slug> y, si featured: true, también en la home.

Estructura del proyecto

.
├── astro.config.mjs          # Configuración Astro (site, integrations, markdown)
├── tailwind.config.cjs       # Tailwind theme y content paths
├── tsconfig.json             # TS estricto
├── package.json              # Deps y scripts
├── Dockerfile                # Multi-stage build (node -> nginx)
├── docker-compose.yml        # Local dev/test
├── docker-compose.prod.yml   # Producción (pull de registry)
├── nginx.conf                # Configuración nginx
├── .gitea/workflows/         # Pipelines CI/CD
│   └── ci-cd.yaml
├── public/                   # Assets estáticos servidos tal cual (favicon, david-aragon.jpg, etc.)
└── src/
    ├── components/
    │   ├── layout/           # Header, Footer
    │   └── ui/               # Card, Tag
    ├── content/
    │   ├── config.ts         # Schemas Zod para blog y projects
    │   ├── blog/             # Posts en Markdown
    │   └── projects/         # Proyectos en Markdown
    ├── layouts/              # BaseLayout, BlogLayout, ProjectLayout
    ├── pages/
    │   ├── index.astro       # Home
    │   ├── about.astro       # About
    │   ├── blog/             # Index + [slug].astro
    │   ├── projects/         # Index + [slug].astro
    │   └── rss.xml.ts        # Feed RSS (si está generado)
    ├── styles/               # CSS global
    └── utils/                # dateFormat.ts, readingTime.ts

CI/CD

Pipeline definido en .gitea/workflows/ci-cd.yaml. Trigger: push a main.

  1. Build: checkout, login en el registry de Gitea, build de la imagen Docker multi-stage
  2. Push: publica gitlab.impresion3d.pro/root/davidaragon-portfolio:latest
  3. Deploy: el webhook configurado en Portainer hace pull de la nueva imagen y reinicia el contenedor

Secrets necesarios en el repo (Settings → Secrets):

  • DOCKER_USERNAME — usuario del registry (normalmente root)
  • DOCKER_PASSWORD — token personal con permisos de registry

Ver CI-CD-SETUP.md para instrucciones detalladas de Portainer y registro de runners.

Licencia

Código del sitio: ver LICENSE si existe en el repo. El contenido (posts y proyectos) es © David Aragón.

Créditos

  • Construido con Astro
  • Estilado con Tailwind CSS
  • Hospedado en infraestructura propia (Gitea + Portainer)
S
Description
Personal tech portfolio and dev blog - davidaragon.impresion3d.pro
Readme 290 KiB
Languages
Astro 92.6%
TypeScript 3%
JavaScript 2.4%
Dockerfile 1.7%
CSS 0.3%