> For the complete documentation index, see [llms.txt](https://elguerre.gitbook.io/de0an/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://elguerre.gitbook.io/de0an/capitulo-11-backstage-y-un-futuro-prometedor/publicacion-y-devops-moderno.md).

# Publicación y DevOps Moderno

El capítulo 10 fue la culminación del viaje: publicar la aplicación. Configuramos HockeyApp para distribución continua, integramos monetización con anuncios, compilamos en modo Release y finalmente publicamos en Microsoft Store. Fue el momento de decir: *"Está hecha, está aquí, el mundo puede usarla"*.

Hoy, el proceso de publicación ha evolucionado hacia lo que conocemos como **DevOps**: un conjunto de prácticas que unen desarrollo y operaciones en un flujo continuo y automatizado.

## De HockeyApp a observabilidad moderna

HockeyApp fue una herramienta pionera para distribución beta y monitoreo de fallos. Microsoft la adquirió y eventualmente la integró (y retiró) en favor de **App Center**, que a su vez ha dado paso a herramientas más maduras.

Hoy, la observabilidad se basa en tres pilares, conocidos como los "tres pilares de la observabilidad":

1. **Logs**: registro estructurado de eventos. No simples `Console.WriteLine`, sino logs con contexto, niveles y correlación.
2. **Métricas**: datos numéricos agregados. Tiempo de respuesta, tasa de errores, uso de CPU.
3. **Trazas distribuidas**: seguimiento de una petición a través de múltiples servicios. Del frontend al backend, pasando por la base de datos y el cache.

**OpenTelemetry** es el estándar abierto que unifica estos tres pilares, y .NET Aspire lo integra de serie. Cuando arrancas una aplicación Aspire, automáticamente obtienes un dashboard con logs, trazas y métricas de todos tus servicios.

## CI/CD con GitHub Actions

Donde antes usábamos VSTS (Azure DevOps) con builds manuales, hoy **GitHub Actions** permite automatizar todo el ciclo:

```yaml
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "9.0.x"

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "22"

      - name: Install frontend dependencies
        run: cd frontend && npm ci

      - name: Run frontend tests
        run: cd frontend && npm test -- --no-watch --code-coverage

      - name: Run backend tests
        run: dotnet test --configuration Release

      - name: Run Playwright tests
        run: cd frontend && npx playwright test

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to Azure
        run: dotnet publish -c Release
        # ... pasos de despliegue
```

Cada push o pull request ejecuta automáticamente: compilación, tests unitarios, tests de integración, tests end-to-end y, si todo pasa, despliegue. Sin intervención manual.

## Docker y contenedores

La compilación en modo Release del capítulo 10 generaba un paquete .appx para la Store. Hoy, el equivalente para aplicaciones web son los **contenedores Docker**:

```dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM base AS final
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "TaskIN.Api.dll"]
```

El contenedor encapsula tu aplicación con todas sus dependencias, garantizando que funciona igual en desarrollo, testing y producción. Aspire genera automáticamente la configuración de Docker para todos tus servicios.

## De la Microsoft Store a la web

La publicación de una aplicación web es diferente a la de una app de Store:

| Entonces (Cap. 10)               | Ahora                                                   |
| -------------------------------- | ------------------------------------------------------- |
| Certificación de Microsoft Store | No hay "certificación" (pero sí buenas prácticas)       |
| Paquete .appx                    | Contenedor Docker o archivos estáticos                  |
| Una tienda centralizada          | Tu propio dominio, CDN, o plataformas cloud             |
| Actualizaciones vía Store        | Despliegue continuo (cada commit puede ser una release) |
| HockeyApp para beta testing      | Feature flags, despliegues canary                       |

La web te da control total sobre tu proceso de publicación. No hay intermediarios, no hay tiempos de revisión, no hay restricciones de contenido impuestas por una tienda. Pero con ese poder viene la responsabilidad de gestionar tu propia infraestructura, seguridad y disponibilidad.

## Despliegue con Aspire

.NET Aspire simplifica también el despliegue. Con `azd` (Azure Developer CLI), puedes desplegar toda tu aplicación (frontend, backend, base de datos, cache) en Azure con unos pocos comandos:

```bash
azd init
azd provision
azd deploy
```

Aspire genera la infraestructura necesaria (App Service, Container Apps, PostgreSQL, Redis) y la configura automáticamente.

## Monitorización en producción

Una vez desplegada, la aplicación necesita monitorización continua. OpenTelemetry + un backend de observabilidad (como Azure Monitor, Grafana, o Jaeger) te permite:

* Ver cuánto tarda cada endpoint en responder.
* Detectar errores antes de que los reporten los usuarios.
* Entender patrones de uso para priorizar mejoras.
* Recibir alertas automáticas cuando algo falla.

## La lección que permanece

Publicar no es el final; es el comienzo. Una aplicación en producción necesita monitorización, mantenimiento y mejora continua. La automatización del pipeline CI/CD y la observabilidad con OpenTelemetry no son lujos: son la diferencia entre una aplicación que evoluciona con confianza y una que se mantiene con miedo. Como dijimos en el capítulo 10: la publicación es el paso definitivo, pero el camino no termina ahí.
