Contexto y resultado
Este portfolio nació como un sitio estático para presentar un perfil profesional. Hoy es una plataforma editorial completa: sitio público renderizado en servidor, API propia en Go, base de datos PostgreSQL, autenticación con GitHub, panel administrativo, blog con interacciones moderadas, catálogo de recursos y videoteca de cursos.
El resultado disponible es un sistema en producción donde el propio medio sostiene el mensaje. El sitio afirma que su autor construye software completo y verificable; ese mismo sitio es la evidencia. No hay una capa de argumentación separada del artefacto: se puede abrir el repositorio y comprobar cada afirmación de esta página.
Problema y restricciones
Un portfolio tiene un problema de credibilidad estructural. Quien lo escribe también decide qué mostrar, así que cualquier afirmación es sospechosa por construcción: nada impide inflar un rol, inventar una métrica o publicar una captura favorable sin contexto.
La restricción autoimpuesta fue que ninguna afirmación pudiera sostenerse solo por buena voluntad del autor. Toda capacidad debía quedar respaldada por código, decisión explicable o prueba ejecutable, y toda ausencia debía declararse en lugar de omitirse.
A eso se sumaron tres límites operativos. El contenido principal debe funcionar sin JavaScript. El estándar de accesibilidad exigido es WCAG 2.2 AA, no una aspiración sino un requisito de entrega. Y la publicación no puede exponer secretos, datos de personas usuarias ni rutas administrativas.
Responsabilidad personal
Definí el producto, la arquitectura y el flujo de entrega, y los implementé en ambos repositorios: el frontend en Astro y la API en Go.
En el frontend eso incluyó el sistema de diseño y su documento normativo, el modelo de contenido tipado, el proxy de mismo origen hacia la API, la política de seguridad de contenido y la batería de pruebas unitarias y de extremo a extremo. En el backend, el diseño de la API, el esquema de datos y sus migraciones, la autenticación con GitHub, el modelo de roles y auditoría, las operaciones de privacidad y la instrumentación operacional.
Uso asistencia de inteligencia artificial como apoyo para análisis, implementación y documentación. Las decisiones de arquitectura, los contratos de datos y los criterios de publicación son propios, y todo cambio pasa por revisión humana, pruebas y control de versiones. Esa es la misma práctica declarada en mi CV, aplicada aquí de forma verificable.
Decisiones y alternativas
El contenido se validó con un esquema que prohíbe exagerar. La decisión más determinante no fue de infraestructura sino de modelo de datos. Un caso de estudio no puede declarar una métrica sin indicar su fuente, ni omitir una imagen en silencio: el esquema define uniones discriminadas donde una visual está lista con sus dimensiones y texto alternativo, o está pendiente con una razón escrita. La alternativa habitual —campos opcionales— permitía publicar vacíos indistinguibles de la ausencia deliberada. Aquí una ausencia siempre se explica. Esta misma página lo demuestra: sus métricas están pendientes y dicen por qué.
El alcance creció y quedó registrado. El documento de producto declaraba que el proyecto no incluiría backend, autenticación, panel administrativo ni blog. Todo eso existe hoy. La decisión de ampliarlo respondió a que un portfolio sin sistema propio deja sin demostrar justamente la capacidad que afirma. Se deja constancia del cambio en lugar de reescribir la historia: un alcance que se movió por razones explicables es información honesta sobre cómo se toman decisiones.
Sin framework de interfaz en el cliente. El sitio no carga React, Vue ni Svelte. El contenido principal es HTML servido y las islas interactivas se justifican por interacción real. La alternativa de adoptar un framework habría simplificado algunos componentes a cambio de un costo permanente para cada visitante.
Sin framework HTTP en la API. El enrutado se resuelve sobre la biblioteca estándar de Go. La alternativa era un router de terceros; se prefirió reducir superficie de dependencias en un servicio cuya complejidad de enrutado es acotada.
Sesiones opacas en lugar de tokens firmados. Las sesiones son identificadores opacos, hasheados, rotativos y revocables. Un token firmado habría evitado consultar la base de datos en cada petición, pero la revocación inmediata deja de ser real. Se priorizó poder cortar el acceso al instante.
Arquitectura y datos
El recorrido es navegador, Astro en modo servidor, proxy de mismo origen, API en Go y PostgreSQL.
El frontend se sirve con Astro en modo servidor sobre Vercel, con adaptador de Node para desarrollo. Diecinueve rutas cubren el sitio público, el área de sesión y el panel administrativo. El contenido editorial de los casos de estudio vive en archivos versionados con esquema tipado; el contenido dinámico —artículos, recursos y cursos— vive en la base de datos y se consume por API.
Entre ambos hay una decisión deliberada: el navegador nunca habla con la API directamente. Seis grupos de rutas proxy en el mismo origen median autenticación, edición, administración, privacidad e interacciones. Las cookies de sesión no cruzan orígenes y la dirección de la API no se expone al cliente.
La API expone cuarenta y nueve rutas documentadas en OpenAPI, organizadas en nueve paquetes internos: catálogo público, autenticación, interacciones, privacidad, administración editorial, medios, configuración, acceso a datos y capa HTTP. El esquema de datos evoluciona con once migraciones embebidas en el binario, inmutables tras el despliegue; una corrección en producción se hace con una migración nueva, nunca editando una ya desplegada.
Las páginas de catálogo degradan con elegancia: si la API no responde, resuelven las promesas en paralelo y renderizan un estado de servicio no disponible. El sitio no se cae cuando el backend sí.
Calidad, seguridad, CI y observabilidad
La política de seguridad de contenido no admite scripts en línea sin hash. Una prueba automatizada recorre el HTML servido, recalcula el hash de cada script y verifica que la política lo declare; si alguien agrega un script sin actualizar la política, la prueba falla antes del despliegue. La misma prueba comprueba las cabeceras de protección de tipo, encuadre y política de referente.
La accesibilidad se verifica, no se declara. Cada corrida audita siete rutas públicas con axe contra los criterios A y AA de WCAG 2.0, 2.1 y 2.2, comprueba el reflujo de los catálogos con zoom al doscientos por ciento sin desbordamiento horizontal, y calcula el contraste de los colores de marca en tema claro. El sistema de diseño está documentado en un archivo normativo de más de ochocientas líneas, y las instrucciones del repositorio establecen que una tarea de estilos está incompleta si ese documento no se actualizó en el mismo cambio.
En la última verificación el frontend ejecutó ciento cincuenta y dos pruebas unitarias en treinta archivos, catorce pruebas de extremo a extremo, comprobación de tipos sin errores ni advertencias en ciento cincuenta y dos archivos, análisis estático sin advertencias y compilación completa. La API está escrita con veintitrés archivos de prueba sobre cincuenta y tres archivos de código.
La autenticación usa OAuth de GitHub con parámetro de estado y PKCE. Los tokens de acceso de GitHub se usan una sola vez para leer el perfil y nunca se persisten. Las sesiones duran treinta días y son revocables; el cierre de sesión está protegido contra falsificación de petición entre sitios; los accesos administrativos quedan auditados.
La privacidad se trató como requisito de ingeniería y no como página legal. Existen exportación estructurada, bloqueo de tratamiento, borrado con lápida, acuses de aviso y retención auditada que exige una previsualización antes de ejecutarse. El inventario de datos, la política de retención, el registro de proveedores y el procedimiento de incidentes están documentados.
En operación hay registro estructurado en JSON, identificadores de petición, verificaciones de vida y disponibilidad, y métricas expuestas tras autenticación con etiquetas de ruta de cardinalidad acotada.
Resultado verificable
Lo que la evidencia sostiene hoy: un sistema en producción con diecinueve rutas de sitio y cuarenta y nueve de API; un modelo de contenido que impide publicar afirmaciones sin fuente; verificación automatizada de accesibilidad, seguridad y reflujo en cada corrida; autenticación con revocación real; y operaciones de privacidad implementadas con auditoría.
Lo que no se afirma: no hay métricas de rendimiento publicables, porque solo existe un presupuesto de transferencia verificado en pruebas y eso no equivale a una medición de experiencia real. No hay un resultado citable de la suite de pruebas del backend, porque no se ha ejecutado en un entorno con el toolchain de Go disponible. Las capturas y el diagrama de arquitectura están pendientes de material sanitizado.
Ese contraste es deliberado y es, en sí mismo, el resultado principal: el sistema fuerza a declarar el límite de lo que puede demostrarse.
Aprendizajes y mejoras
Poner la honestidad en el esquema de datos funciona mejor que ponerla en las buenas intenciones. Cuando el modelo exige una razón para cada ausencia, la tentación de omitir desaparece por construcción, y la página resultante es más creíble justamente porque enumera lo que todavía no puede probar.
Tratar la accesibilidad y la seguridad como pruebas ejecutables cambió su naturaleza. Dejaron de ser una revisión final que compite con la fecha de entrega y pasaron a ser una condición de mérito: el cambio que las rompe no llega a producción.
Documentar la desviación de alcance resultó más útil que corregir el documento en silencio. La distancia entre lo planificado y lo construido es información real sobre cómo evoluciona un producto.
Quedan mejoras claras. Falta ejecutar y registrar la suite de pruebas del backend en un entorno con Go instalado. Faltan capturas sanitizadas y un diagrama de arquitectura. Falta decidir si se publican métricas de rendimiento medidas. Y falta cerrar la verificación de extremo a extremo del flujo editorial completo contra la API real, hoy limitada por la ausencia de un entorno autenticado local.
Enlaces
- Ver el sitio en producción (abre en una nueva pestaña)
- Las visuales de este caso están declaradas como pendientes con su razón, según el mismo contrato de contenido que describe el caso.