Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions docs/adr/R01-fundacion-sitio-jekyll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# ADR R01: Fundación del sitio personal con Jekyll

> **Estado:** Reemplazada → [R02](R02-migracion-jekyll-a-gatsby.md)
> **Fecha:** 2016-04
> **Categoría:** Plataforma / SSG / Quality
> **Repositorio:** `secorto.com_jekyll` (423 commits, 2016–2023)
> **Fecha reconstrucción:** 2026-02

Comment on lines +1 to +8
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Este ADR se marca como “reconstruido retrospectivamente”, pero no incluye una sección explícita de retrospectiva con los campos que el issue #85 pide para los ADRs retrospectivos (p. ej. “Decisión vigente (sí/no/parcial)”, resumen breve, si requiere actualización, responsable/fecha límite y acciones). Si este PR cierra #85, conviene añadir esa sección al final (o en el frontmatter/encabezado) para que quede verificable y accionable.

Copilot uses AI. Check for mistakes.
---

## Contexto

En marzo de 2016 se inició el desarrollo de un sitio web personal con el
objetivo de practicar desarrollo front-end y tener presencia profesional
en línea. El primer intento usó **Lektor** (SSG basado en Python) durante
apenas dos semanas (~8 commits, 16–17 mar 2016) antes de descartarse por
falta de ecosistema y documentación en español.

Se necesitaba un generador de sitios estáticos que:

- Tuviera ecosistema maduro de temas y plugins
- Permitiera escribir contenido en Markdown
- Se pudiera desplegar gratuitamente (GitHub Pages)
- Tuviera buena documentación

---

## Decisión

Adoptar **Jekyll** como generador de sitios estáticos, desplegado inicialmente
en GitHub Pages y luego migrado a Netlify.

### Evolución del stack (fases)

#### Fase 1 — Jekyll + Gulp + Bootstrap (abr 2016)

- Migración completa de Lektor a Jekyll con Gulp como task runner
- Bootstrap 3, Sass, jQuery
- Bower para dependencias frontend
- Dominio `scot3004.xyz`
- CI: Travis CI (Ruby 2.5 + Node.js 8)

#### Fase 2 — Bower → NPM (jun 2016, tags v1.2.x–v1.3.x)

- Bower eliminado, dependencias movidas a NPM
- Scripts NPM reemplazan parcialmente a Gulp
- `html-proofer` integrado como `lint:html`
- `imagemin-cli` para optimización de imágenes

#### Fase 3 — Dominio propio (2017)

- Migración de `scot3004.xyz` a `secorto.com`
- SEO tags, Open Graph, formulario de contacto
- Notice de cookies, reCAPTCHA

#### Fase 4 — Minimal Mistakes + Netlify (sep-oct 2018, tag v2.0.0)

- Tema cambiado de custom a `minimal-mistakes-jekyll` (gema Ruby)
- Eliminación de todo el CSS/HTML personalizado
- Deploy migrado de GitHub Pages a **Netlify**
- **Netlify CMS** integrado (editorial workflow: draft → review → publish)
- Gulpfile eliminado definitivamente

#### Fase 5 — Mantenimiento (2019–2020)

- Remark lint para Markdown
- Portafolio con entradas de PyCon
- Bumps de dependencias vía Dependabot
- Último commit funcional: marzo 2020

#### Fase 6 — Deprecación (2023)

- Commit final advirtiendo migración al nuevo repositorio (Astro)

### Estrategia de calidad

El comando `npm test` ejecutaba exclusivamente **linters y validación
estática** — no existían tests unitarios:

| Herramienta | Tipo | Alcance |
|---|---|---|
| **html-proofer** | Validación HTML post-build | Enlaces rotos, alt vacíos, HTML válido |
| **ESLint** | Linter JS | `.eslintrc.yaml` con 207 líneas de reglas, complejidad máx 6 |
| **scss-lint** | Linter SCSS | `_sass/**/*.scss` |
| **remark-lint** | Linter Markdown | Preset recommended + frontmatter |
| **CodeClimate** | Análisis estático | Duplication (JS, Ruby), eslint, fixme, rubocop, scss-lint |

Pipeline CI (Travis CI):

```
gem install bundler → bundle install → npm install
→ jekyll build → npm run test (= lint:js + lint:css + lint:html + lint:md)
```

Variable de entorno crítica: `NOKOGIRI_USE_SYSTEM_LIBRARIES=true` — necesaria
porque `html-proofer` dependía de **Nokogiri** (parser XML/HTML con binding
nativo en C), que era problemático de compilar en diferentes entornos.

### Contenido

- **17 posts** (2010–2018, los de 2010–2011 migrados desde Blogger)
- **3 entradas de portafolio** (pybaq, pycon, scot3004)
- **6 páginas** (404, archive, categories, contacto, portafolio, tags)
- Datos estructurados: `navigation.yml`, `timeline.yml`

---

## Alternativas consideradas

| Alternativa | Razón de descarte |
|---|---|
| **Lektor** (Python) | Ecosistema limitado, poca documentación, comunidad pequeña |
| **WordPress** | Requiere hosting dinámico, no alineado con práctica de front-end |
| **HTML estático** | No escala para blog con múltiples posts |

---

## Consecuencias

### Positivas

- Jekyll era el SSG más maduro en 2016 con integración nativa en GitHub Pages
- Minimal Mistakes proporcionó un diseño profesional sin esfuerzo de CSS
- Netlify CMS permitió edición de contenido sin tocar código
- Los linters mantuvieron calidad básica del código
- `html-proofer` detectaba enlaces rotos antes del deploy

### Negativas

- **Nokogiri** se volvió un dolor de cabeza recurrente: compilación nativa
fallaba frecuentemente en CI y en diferentes sistemas operativos
- Sin tests unitarios — la calidad dependía 100% de linting estático
- El stack Ruby + Node.js duplicaba la complejidad del entorno de desarrollo
- Jekyll carecía de componentización moderna (Liquid tiene limitaciones)
- La falta de tipado hacía difícil refactorizar con confianza
- Minimal Mistakes, al ser una gema, ocultaba la estructura interna y
dificultaba personalizaciones profundas

### Métricas del repositorio

| Métrica | Valor |
|---|---|
| Commits totales | 423 |
| Período activo | 2016-04 a 2020-03 (~4 años) |
| Tags de versión | v1.2.1, v1.2.2, v1.3.1, v1.3.2, v2.0.0 |
| CI | Travis CI |
| Deploy | GitHub Pages → Netlify |
| Último commit | 2023-03-04 (aviso de deprecación) |

---

## Referencias

- Repositorio: `secorto.com_jekyll/`
- [Jekyll](https://jekyllrb.com/)
- [Minimal Mistakes](https://mmistakes.github.io/minimal-mistakes/)
- [html-proofer](https://github.com/gjtorikian/html-proofer)
- [Nokogiri](https://nokogiri.org/)
232 changes: 232 additions & 0 deletions docs/adr/R02-migracion-jekyll-a-gatsby.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
# ADR R02: Migración de Jekyll a Gatsby

> **Estado:** Reemplazada → [R03](R03-migracion-gatsby-a-astro.md)
> **Fecha:** 2021-03
> **Categoría:** Plataforma / SSG / Testing / Quality
> **Repositorio:** `web2021` (111 commits, 2021–2023)
> **Fecha reconstrucción:** 2026-02

Comment on lines +1 to +8
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Este ADR se marca como “reconstruido retrospectivamente”, pero no incluye una sección explícita de retrospectiva con los campos que el issue #85 pide para los ADRs retrospectivos (p. ej. “Decisión vigente (sí/no/parcial)”, resumen breve, si requiere actualización, responsable/fecha límite y acciones). Si este PR cierra #85, conviene añadir esa sección al final (o en el frontmatter/encabezado) para que quede verificable y accionable.

Copilot uses AI. Check for mistakes.
---

## Contexto

Después de ~4 años con Jekyll ([ADR R01](R01-fundacion-sitio-jekyll.md)),
el sitio enfrentaba múltiples fricciones:

### Problemas con Nokogiri

`html-proofer` — la herramienta central de validación de calidad — dependía
de **Nokogiri**, un parser XML/HTML con bindings nativos en C. Compilar
Nokogiri era un proceso frágil:

- Fallaba frecuentemente en CI (Travis CI) requiriendo
`NOKOGIRI_USE_SYSTEM_LIBRARIES=true`
- Diferentes versiones de `libxml2`/`libxslt` en el sistema generaban
errores crípticos
- Actualizaciones de Ruby o del SO rompían la compilación nativa
- El stack dual Ruby + Node.js multiplicaba los puntos de fallo

### Deseo de mayor estructura

Jekyll con Liquid ofrecía poca componentización:

- No había componentes reutilizables con props tipados
- La lógica de templates era difícil de testear
- No existía sistema de tipos — los errores se detectaban en runtime (build)
- El código CSS/HTML estaba acoplado al tema Minimal Mistakes (gema opaca)

### Motivación personal

- Practicar React y el ecosistema moderno de JavaScript
- Tener una base más estructurada y componentizada
- Poder escribir tests unitarios reales (no solo linters)

---

## Decisión

Migrar a **Gatsby** (v5) con React 18, Theme UI para estilos, MDX para
contenido, y Jest + Cypress como frameworks de testing.

### Stack adoptado

| Capa | Tecnología | Reemplaza a |
|---|---|---|
| SSG | Gatsby 5 | Jekyll |
Comment on lines +48 to +55
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hay una inconsistencia interna de versión: en “Decisión” se indica “Gatsby (v5)”, pero en “Métricas del repositorio” se afirma “Versión final: 4.2.0 (package.json)”. Ajustar uno de los dos para que el ADR sea coherente (o explicar el motivo si el repo empezó en v5 pero terminó en v4.x).

Suggested change
Migrar a **Gatsby** (v5) con React 18, Theme UI para estilos, MDX para
contenido, y Jest + Cypress como frameworks de testing.
### Stack adoptado
| Capa | Tecnología | Reemplaza a |
|---|---|---|
| SSG | Gatsby 5 | Jekyll |
Migrar a **Gatsby 4** (versión final 4.2.0) con React 18, Theme UI para estilos,
contenido en MDX, y Jest + Cypress como frameworks de testing.
### Stack adoptado
| Capa | Tecnología | Reemplaza a |
|---|---|---|
| SSG | Gatsby 4 (4.2.0) | Jekyll |

Copilot uses AI. Check for mistakes.
| UI | React 18 | Liquid templates |
| Estilos | Theme UI 0.16 + Emotion | Sass + Minimal Mistakes |
| Contenido | MDX v5 (`.mdx` y `.md`) | Markdown + Liquid |
| Imágenes | gatsby-plugin-image + sharp | imagemin-cli |
| SVG | @svgr/webpack (componentes React) | Archivos estáticos |
| Color modes | Dark/Light via Theme UI | No existía |
| PWA | gatsby-plugin-manifest + offline | No existía |
| Tests unitarios | **Jest 29 + jsdom + Emotion serializer** | No existían |
| Tests E2E | **Cypress 12 + cypress-axe** | html-proofer |
| Linting | ESLint 8 + react-app + MDX plugin | ESLint + scss-lint + remark |
| Formatting | Prettier 3 | No existía |
| CI | **GitHub Actions** | Travis CI |
| Deploy | Netlify | Netlify (se mantuvo) |
| Dev env | DevContainer (Node 18) | Local únicamente |

### Arquitectura de la aplicación

```
src/
├── assets/ → Recursos estáticos (avatar, logo, iconos)
├── blocks/ → Contenido MDX como bloques (about.mdx)
├── components/ → Componentes React (Bio, Blog, Footer, Gallery, etc.)
├── constants.ts → Constantes (MAIN_CONTENT_ID)
├── containers/ → Layout, SEO, PostFooter
├── context/ → SidebarContext (React Context)
├── hooks/ → use-avatar, use-site-metadata
├── pages/ → 404, blog, index, portafolio
├── templates/ → blog-template, page-template, portafolio-template
├── theme/ → Colors, typography, styles (Theme UI)
└── types/ → Declaraciones TypeScript
```

### Generación de páginas (`gatsby-node.js`)

Gatsby usaba **GraphQL** para consultar contenido y generar páginas
estáticamente. El archivo `gatsby-node.js` ejecutaba:

1. `onCreateNode`: interceptaba nodos MDX, extraía `sourceInstanceName`
del padre y creaba campos `slug` y `collection`
2. `createPages`: dos queries GraphQL separadas (blog + portafolio),
cada post recibía contexto con `previous` y `next` para navegación
3. `onCreateWebpackConfig`: configuraba @svgr/webpack en los 4 stages

El **cross-referencing** de posts (previous/next) requería resolver
relaciones en GraphQL durante el build, contribuyendo a tiempos de
compilación de **~3 minutos**.

### Estrategia de testing

#### Jest — Tests unitarios con snapshot testing

```javascript
// jest.config.js
module.exports = {
testEnvironment: 'jsdom',
transform: { '^.+\\.[jt]sx?$': '<rootDir>/jest-preprocess.js' },
moduleNameMapper: {
'.+\\.(css|style)$': 'identity-obj-proxy',
'.+\\.(jpg|png|gif|svg)$': '<rootDir>/__mocks__/file-mock.js'
},
snapshotSerializers: ['@emotion/jest/serializer']
}
```

- **Snapshot testing**: verificaba que los componentes renderizaran
consistentemente (SEO, layouts)
- `react-test-renderer` para renderizado sin DOM
- `identity-obj-proxy` para mockear CSS modules
- Mock completo de Gatsby (`__mocks__/gatsby.js`): `useStaticQuery`,
`graphql`, `Link`, `navigate`, `StaticImage`
- `@emotion/jest/serializer` para snapshots legibles de estilos Emotion

#### Cypress — Tests E2E de accesibilidad

```javascript
// cypress/e2e/accessibility.cy.js
// Tests de a11y con axe-core en modo oscuro y claro
```

- `cypress-axe` + `axe-core` para auditoría de accesibilidad
- `@testing-library/cypress` para queries semánticas
- Solo un spec file: accesibilidad en ambos color modes
- No se usó Cypress Cloud (evitando el límite de 500 ejecuciones/mes
que luego motivaría el [ADR 002](002-testing-framework-migration.md))

#### Pipeline CI (GitHub Actions)

```yaml
# .github/workflows/tests.yml
name: Jest
on: push
jobs:
test:
steps:
- yarn install --frozen-lockfile
- yarn lint # ESLint (JS, JSX, MD, MDX)
- yarn test:unit # Jest
```

Solo lint + unit tests en CI. E2E se ejecutaba localmente o via Netlify
deploy previews.

### Contenido migrado

- **17 posts de blog** (mismos que Jekyll, convertidos de `.md` a MDX)
- **3 entradas de portafolio** (pybaq, perficient, scot3004)
- **Timeline profesional** (`content/timeline.yml`)
- Se mantuvo un solo idioma (español)

---

## Alternativas consideradas

| Alternativa | Razón de descarte |
|---|---|
| **Next.js** | Orientado a apps dinámicas con SSR; el sitio es 100% estático |
| **Hugo** | Go templates menos expresivos que JSX; sin ecosistema npm nativo |
| **Eleventy** | Más simple pero sin el ecosistema de componentes React |
| **Mantener Jekyll** | Nokogiri y la falta de componentización eran bloqueos |

---

## Consecuencias

### Positivas

- **Componentes React** permitieron estructura modular y reutilizable
- **Theme UI** proporcionó dark mode, sistema de diseño tipado y
estilos consistentes
- **Jest con snapshots** introdujo tests unitarios por primera vez en
el proyecto — verificación automática de regresiones visuales
- **Cypress + axe-core** automatizó auditorías de accesibilidad
- **TypeScript parcial** (migración gradual) mejoró la confiabilidad
- **DevContainer** estandarizó el entorno de desarrollo
- **MDX** permitió React dentro del Markdown (componentes interactivos)
- Se eliminó la dependencia de Ruby y Nokogiri completamente

### Negativas

- **Dependencias inestables**: las actualizaciones de Gatsby y sus ~34
plugins generaban conflictos frecuentes que retrasaban deploys. Snyk
reportó múltiples vulnerabilidades (9 commits de snyk-bot)
- **Builds de ~3 minutos**: el cross-referencing de posts via GraphQL
y la generación de imágenes con sharp alargaban el pipeline
- **GraphQL overhead**: consultas complejas para datos que podrían ser
simples archivos de configuración
- **Pocas actualizaciones de contenido**: el proyecto tenía baja
frecuencia de cambios, lo que hacía el overhead de Gatsby desproporcionado
- **gatsby-node.js monolítico**: toda la lógica de generación en un solo
archivo sin tipado
- **Snapshot testing frágil**: los snapshots se rompían con cambios
cosméticos, generando falsos positivos
- **Webpack opaco**: la configuración de webpack estaba abstraída por
Gatsby, dificultando optimizaciones

### Métricas del repositorio

| Métrica | Valor |
|---|---|
| Commits totales | 111 |
| Período activo | 2021-03 a 2023-07 (~2 años 4 meses) |
| Tags de versión | Ninguno |
| Versión final | 4.2.0 (package.json) |
| CI | GitHub Actions (lint + unit tests) |
| Deploy | Netlify |
| Último commit | 2023-07-20 (upgrade dependencias) |

---

## Referencias

- Repositorio: `web2021/`
- [ADR R01 — Jekyll](R01-fundacion-sitio-jekyll.md) (decisión reemplazada)
- [Gatsby](https://www.gatsbyjs.com/)
- [Theme UI](https://theme-ui.com/)
- [Jest Snapshot Testing](https://jestjs.io/docs/snapshot-testing)
- [cypress-axe](https://github.com/component-driven/cypress-axe)
Loading