# Manual de Despliegue

## Requisitos del Sistema

| Componente | Versión Mínima |
|------------|----------------|
| .NET SDK | 10.0 |
| Node.js | 22.x |
| SQL Server | 2022 |
| Docker | 24.x |
| Docker Compose | 2.x |

## Variables de Entorno

### Backend (.NET)

| Variable | Descripción | Ejemplo |
|----------|-------------|---------|
| `ConnectionStrings__DefaultConnection` | Connection string SQL Server | `Server=db;Database=StudentEnrollment;...` |
| `ASPNETCORE_ENVIRONMENT` | Ambiente | `Production` |
| `ASPNETCORE_URLS` | URLs de escucha | `http://+:5000` |

### Frontend (Angular)

| Variable | Descripción | Ejemplo |
|----------|-------------|---------|
| `API_URL` | URL del backend GraphQL | `https://api.example.com/graphql` |

## Despliegue con Docker

### 1. Estructura de Archivos

```
deploy/
└── docker/
    ├── Dockerfile.api
    ├── Dockerfile.frontend
    ├── docker-compose.yml
    └── nginx.conf
```

### 2. Dockerfile Backend

```dockerfile
# deploy/docker/Dockerfile.api
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src

COPY src/backend/ .
RUN dotnet restore Host/Host.csproj
RUN dotnet publish Host/Host.csproj -c Release -o /app

FROM mcr.microsoft.com/dotnet/aspnet:10.0
WORKDIR /app
COPY --from=build /app .

# Non-root user
RUN adduser --disabled-password --gecos '' appuser
USER appuser

EXPOSE 5000
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:5000/health || exit 1

ENTRYPOINT ["dotnet", "Host.dll"]
```

### 3. Dockerfile Frontend

```dockerfile
# deploy/docker/Dockerfile.frontend
FROM node:22-alpine AS build
WORKDIR /app

COPY src/frontend/package*.json ./
RUN npm ci

COPY src/frontend/ .
RUN npm run build -- --configuration production

FROM nginx:alpine
COPY --from=build /app/dist/student-enrollment/browser /usr/share/nginx/html
COPY deploy/docker/nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost/ || exit 1
```

### 4. Nginx Configuration

```nginx
# deploy/docker/nginx.conf
server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # Gzip
    gzip on;
    gzip_types text/plain text/css application/json application/javascript;

    # SPA routing
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Proxy GraphQL
    location /graphql {
        proxy_pass http://api:5000/graphql;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }

    # Security headers
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
}
```

### 5. Docker Compose

```yaml
# deploy/docker/docker-compose.yml
services:
  db:
    image: mcr.microsoft.com/mssql/server:2022-latest
    environment:
      - ACCEPT_EULA=Y
      - SA_PASSWORD=${DB_PASSWORD}
    ports:
      - "1433:1433"
    volumes:
      - sqlserver-data:/var/opt/mssql
    healthcheck:
      test: /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P $${SA_PASSWORD} -Q "SELECT 1" -C
      interval: 10s
      timeout: 3s
      retries: 10

  api:
    build:
      context: ../..
      dockerfile: deploy/docker/Dockerfile.api
    environment:
      - ConnectionStrings__DefaultConnection=Server=db;Database=StudentEnrollment;User Id=sa;Password=${DB_PASSWORD};TrustServerCertificate=True
      - ASPNETCORE_ENVIRONMENT=Production
    ports:
      - "5000:5000"
    depends_on:
      db:
        condition: service_healthy

  frontend:
    build:
      context: ../..
      dockerfile: deploy/docker/Dockerfile.frontend
    ports:
      - "80:80"
    depends_on:
      - api

volumes:
  sqlserver-data:
```

### 6. Ejecutar

```bash
cd deploy/docker

# Crear archivo .env
echo "DB_PASSWORD=Your_Str0ng_P@ssword!" > .env

# Build e iniciar
docker-compose up -d --build

# Ver logs
docker-compose logs -f

# Detener
docker-compose down
```

## Despliegue Manual

### Backend

```bash
cd src/backend/Host

# Build producción
dotnet publish -c Release -o ./publish

# Configurar connection string
export ConnectionStrings__DefaultConnection="Server=..."

# Ejecutar migraciones
dotnet ef database update --project ../Adapters/Driven/Persistence

# Iniciar
cd publish
dotnet Host.dll
```

### Frontend

```bash
cd src/frontend

# Build producción
ng build --configuration production

# Los archivos quedan en dist/student-enrollment/browser/
# Servir con cualquier servidor web (nginx, apache, etc.)
```

## Checklist Pre-Producción

### Seguridad

- [ ] Connection strings en variables de entorno (no en código)
- [ ] HTTPS habilitado
- [ ] CORS configurado solo para dominios permitidos
- [ ] Rate limiting activo
- [ ] Security headers configurados
- [ ] Logs sin datos sensibles

### Performance

- [ ] Response compression habilitado
- [ ] Output caching configurado
- [ ] Bundle Angular optimizado (< 200KB transferidos)
- [ ] Índices de BD aplicados

### Monitoreo

- [ ] Health checks funcionando (`/health`)
- [ ] Logs centralizados
- [ ] Métricas de aplicación

### Base de Datos

- [ ] Backup configurado
- [ ] Migraciones aplicadas
- [ ] Datos seed cargados (5 profesores, 10 materias)

## URLs de Verificación

| Servicio | URL | Esperado |
|----------|-----|----------|
| API Health | `http://api:5000/health` | 200 OK |
| GraphQL Playground | `http://api:5000/graphql` | Banana Cake Pop |
| Frontend | `http://frontend:80` | App Angular |

## Rollback

```bash
# Docker
docker-compose down
docker-compose up -d --no-build  # Usa imágenes anteriores

# Manual
# Restaurar versión anterior de DLLs/archivos
# Rollback de migraciones si es necesario:
dotnet ef database update <MigrationName>
```

---

## Despliegue en Kubernetes (k3s)

### Estructura de Manifiestos

```
deploy/k3s/
├── namespace.yaml      # Namespace dedicado
├── secrets.yaml        # Credenciales BD
├── configmap.yaml      # Configuración
├── sqlserver.yaml      # Base de datos
├── api.yaml            # Backend GraphQL
├── frontend.yaml       # Frontend Angular
├── ingress.yaml        # Traefik ingress
├── ingress-tls.yaml    # TLS con cert-manager
├── hpa.yaml            # Autoscaling
├── networkpolicy.yaml  # Seguridad de red
├── kustomization.yaml  # Kustomize config
└── deploy.sh           # Script de despliegue
```

### Requisitos k3s

- k3s instalado y funcionando
- kubectl configurado
- Acceso al cluster
- (Opcional) cert-manager para TLS

### Despliegue Rápido

```bash
cd deploy/k3s

# Opción 1: Con script
./deploy.sh all        # Build + Deploy

# Opción 2: Con kustomize
kubectl apply -k .

# Verificar estado
kubectl get all -n student-enrollment
```

### Comandos del Script

```bash
./deploy.sh build      # Construir imágenes Docker
./deploy.sh deploy     # Desplegar a k3s
./deploy.sh status     # Ver estado del cluster
./deploy.sh logs api   # Ver logs del API
./deploy.sh forward    # Port-forward para desarrollo
./deploy.sh delete     # Eliminar deployment
```

### Configurar Secrets

```bash
# Editar secrets antes de desplegar
kubectl create secret generic student-secrets \
  --namespace=student-enrollment \
  --from-literal=db-password='TuPasswordSeguro123!' \
  --from-literal=db-connection-string='Server=sqlserver;Database=StudentEnrollment;User Id=sa;Password=TuPasswordSeguro123!;TrustServerCertificate=True' \
  --dry-run=client -o yaml > secrets.yaml
```

### Acceso Local (Desarrollo)

```bash
# Agregar entrada en /etc/hosts
echo "127.0.0.1 students.local" | sudo tee -a /etc/hosts

# Port forward
./deploy.sh forward

# Acceder en:
# - Frontend: http://localhost:8080
# - API: http://localhost:5000/graphql
```

### Habilitar TLS (Producción)

```bash
# 1. Instalar cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml

# 2. Editar ingress-tls.yaml con tu dominio y email

# 3. Aplicar ingress con TLS
kubectl apply -f ingress-tls.yaml -n student-enrollment
```

### Scaling Manual

```bash
# Escalar API
kubectl scale deployment student-api -n student-enrollment --replicas=3

# Escalar Frontend
kubectl scale deployment student-frontend -n student-enrollment --replicas=2
```

### Monitoreo

```bash
# Estado de pods
kubectl get pods -n student-enrollment -w

# Logs en tiempo real
kubectl logs -n student-enrollment -l app=student-api -f

# Eventos
kubectl get events -n student-enrollment --sort-by='.lastTimestamp'

# Recursos
kubectl top pods -n student-enrollment
```

### Rollback en k3s

```bash
# Ver historial de deployments
kubectl rollout history deployment/student-api -n student-enrollment

# Rollback a versión anterior
kubectl rollout undo deployment/student-api -n student-enrollment

# Rollback a revisión específica
kubectl rollout undo deployment/student-api -n student-enrollment --to-revision=2
```

### Troubleshooting

```bash
# Pod no inicia
kubectl describe pod <pod-name> -n student-enrollment

# Conectar a pod
kubectl exec -it <pod-name> -n student-enrollment -- /bin/sh

# Verificar conectividad BD
kubectl exec -it <api-pod> -n student-enrollment -- \
  curl -v telnet://sqlserver:1433

# Verificar ingress
kubectl describe ingress student-ingress -n student-enrollment
```
