# Despliegue en Banahosting

Guía para publicar el portal de reportes en `incide.com.co`.

---

## 1. Antes de empezar: tres decisiones

### 1.1 `www.incide.com.co` ya está ocupado

El dominio **no** apunta a un servidor vacío. Hoy responde con **WordPress**:

```
www.incide.com.co  →  CNAME  →  incide.com.co  →  50.31.177.135
50.31.177.135       →  hd-4910.banahosting.com  (LiteSpeed + WordPress)
```

Si subes el proyecto al `public_html` principal, **rompes el sitio corporativo**.

**Usa un subdominio.** En cPanel → *Domains* → *Subdomains*, crea `reportes`, y en *MultiPHP Manager* asígnale el mismo PHP que uses abajo. Todo lo de esta guía va en `public_html/reportes`.

### 1.2 La base de datos sí se puede leer desde Banahosting

Verificado en el servidor de Sihos:

```
CURRENT_USER() = 'incidebd'@'%'      ← no está atada a una IP
bind_address   = *
skip_networking = OFF
```

El usuario acepta conexiones desde cualquier dirección, así que el hosting puede leerla. **Lo único que hay que confirmar** es que Banahosting no bloquee salidas al puerto 3306; el paso 6 lo comprueba.

> Ojo: `incidebd` tiene `SELECT` sobre `*.*`, o sea **todas** las bases de Sihos, no solo la de pacientes. Vale la pena pedirle a Sihos una cuenta limitada a `sihos` para producción.

### 1.3 MySQL 5.6 es anterior a lo que pide Laravel 10

El servidor de Sihos responde `5.6.51-91.0`; Laravel 10 pide 5.7 o superior. **Hoy funciona** (solo lectura, y ya está verificado), pero anótalo por si Sihos actualiza y rompe algo.

---

## 2. Requisitos en cPanel

| Requisito | Valor | Notas |
|---|---|---|
| PHP | **8.1** a **8.3** | 8.2 o 8.3 recomendado |
| Extensiones | `curl`, `pdo_mysql`, `mbstring`, `gd`, `dom`, `xml`, `zip`, `sqlite3` | `sqlite3` es obligatoria: el portal guarda los enlaces de un solo uso en una base propia |
| `max_execution_time` | **300** | ver la sección 2.2, es el más importante |
| `max_input_time` | **300** | si queda en 60 s, corta antes que el anterior |
| `memory_limit` | **512M** | dompdf con 9 fotos necesita más de 128M |
| `upload_max_filesize` | `16M` | |
| SSL | activo (Let's Encrypt) | obligatorio: se manejan datos de salud |
| `display_errors` | `Off` | |

Activa las extensiones en **cPanel → Seleccionar versión de PHP → Extensiones**.

---

## 2.2 El límite de tiempo: lo que hace que funcionen los reportes

Este es el punto más importante de toda la instalación. Lo medí en el proyecto:

```
reporte en frío:   67 - 80 s   (tiene que descargar las imágenes de Sihos)
con caché:          0,44 s     (ya está en disco)
```

Con el `max_execution_time = 30` que trae el hosting por defecto, PHP se detiene
a los 30 segundos. El navegador muestra un error, y lo peor: **el PDF no se
guarda**, así que el siguiente intento empieza de cero y vuelve a tardar 70
segundos. El paciente nunca ve su reporte.

Cómo se arregla, en los dos sitios donde Banahosting guarda el valor:

**a) En el archivo `public/.user.ini`**

Viene en el paquete que subes. Ábrelo en el administrador de archivos de cPanel
y confírmalo. Si lo quitaste, crea uno en
`public_html/reportes/public/.user.ini`:

```ini
max_execution_time = 300
max_input_time = 300
memory_limit = 512M
```

> Debe quedar en la carpeta **`public/`**, que es donde está `index.php`. Si lo
> pones en la raíz del proyecto, PHP no lo lee.

**b) En el panel**

**cPanel → Seleccionar versión de PHP → *Options*** (o *Valores propios*), y pon
lo mismo. Hazlo también, porque si alguien cambia una opción desde el panel
puede pisar lo del archivo.

### Cómo saber si quedó bien

El comando de verificación lo mide:

```bash
php artisan instalacion:verificar
```

Debe mostrar algo así:

```
  ACCESO A SIHOS
   OK MySQL                       5.6.51-91.0
   OK Pacientes legibles          60.533
   OK PDF de prueba                2.279,0 KB (admisión 202610030002)
   OK primer intento               67,1 s (sin cache de Sihos)
   OK con cache                    0,44 s
   OK limite de tiempo             300 s para un reporte de 67 s
```

Si en vez de eso aparece un problema diciendo que `max_execution_time` está en 30
o menos, **el portal no va a funcionar** hasta que lo subas.

Si aparece `sin limite (0)`, mejor todavía.

### Si Banahosting te deja el límite en 30 y no hay forma de subirlo

Algunos planes compartidos lo topean. Hay un plan B que no necesita VPS:
poner la generación de reportes en una cola de trabajos y que un cron la
procese, de modo que la petición del paciente responda de inmediato y vaya
preguntando si el PDF ya está listo. La pantalla de espera que ya existe
(`public/espera.html`) sirve justamente para eso. Se puede montar con el driver
`database` de Laravel y un cron de cPanel, sin nada externo.

Dímelo y lo implemento.

---

## 3. Subir el proyecto

El paquete ya está armado y limpio de datos de pacientes:

```
incide-deploy.zip   11,23 MB   5.887 archivos
```

1. Descomprime el ZIP **en tu computador**.
2. cPanel → *Administrador de archivos* → entra a `public_html`.
3. Crea la carpeta `reportes`.
4. Entra a `reportes` y sube **el contenido** del ZIP (la carpeta `app`, la carpeta `vendor`, `artisan`, etc.), no el ZIP en sí.

Estructura final:

```
public_html/reportes/
├── app/          bootstrap/   config/   database/
├── public/       resources/   routes/   storage/
├── vendor/
├── artisan       composer.json   composer.lock   .env.example
```

**El `.env` no viene en el paquete.** Se crea en el paso 5, a mano.

> ¿Prefieres SSH? Sube solo el código sin `vendor` y ejecuta `composer install --no-dev -o`. Más rápido, pero requiere acceso SSH.

---

## 4. Permisos

En *Administrador de archivos*, clic derecho → *Cambiar permisos*:

```
reportes/storage                    755
reportes/storage/app                755
reportes/bootstrap/cache            755
reportes/database/sqlite            755
```

Y `.htaccess` debe verse como **archivo**, no como carpeta. En cPanel, *Configuración → Mostrar archivos ocultos*, o usa el administrador de archivos.

Si aun así dice "Sin permiso de escritura", sube esas carpetas a `775`.

---

## 5. Crear el `.env`

En *Administrador de archivos*, renombra `.env.example` a **`.env`** y ábrelo para editar.

### Lo que tienes que cambiar

```ini
APP_NAME="Reporte procedimientos INCIDE S.A.S."
APP_ENV=production
APP_KEY=                                    ← se genera en el paso 6
APP_DEBUG=false                             ← importante: hoy está en true
APP_URL=https://reportes.incide.com.co      ← con https://

DB_CONNECTION=mysql
DB_HOST=incide.sihos.com.co                 ← el hostname, NO la IP
DB_PORT=3306
DB_DATABASE=sihos
DB_USERNAME=incidebd
DB_PASSWORD=la_que_te_dio_sihos

# Ruta RELATIVA. Si copias la de Windows, nada funciona en el servidor.
SQLITE_DATABASE=database/sqlite/app_data.sqlite

SESSION_DOMAIN=null
SANCTUM_STATEFUL_DOMAINS=reportes.incide.com.co
SESSION_SECURE_COOKIE=true                  ← hoy está en false

SIHOS_URL=http://incide.sihos.com.co/sihos
SIHOS_URL_IP=http://incide.sihos.com.co
SIHOS_IP=186.115.199.25
SIHOS_USER=incidebd
SIHOS_PASSWORD=la_que_te_dio_sihos
SIHOS_DATABASE=sihos
SIHOS_USER_WEB=datalab
SIHOS_PASSWORD_WEB=la_que_te_dio_sihos
SIHOS_ENTIDAD=410010039801
SIHOS_PDF_AMOUNT=5
```

Las dos líneas que importan más y que hoy están mal en tu entorno local:

| Variable | Ahora | Debe ser | Por qué |
|---|---|---|---|
| `APP_DEBUG` | `true` | `false` | en `true` se muestran pantallas con rutas del servidor y datos internos |
| `SESSION_SECURE_COOKIE` | `false` | `true` | con `false` la cookie de sesión viaja sin cifrar |

`SQLITE_DATABASE` con la ruta de Windows (`C:\laragon\...`) hace que el servidor no encuentre la base y **todos** los enlaces de descarga fallen.

---

## 6. Comprobar la instalación

Abre **cPanel → Terminal** (o SSH):

```bash
cd ~/public_html/reportes

# 1. Crear la llave de cifrado y anotarla en el .env
php artisan key:generate --show

# 2. Crear carpetas, tablas y limpiar caché
php artisan instalacion:verificar --fix

# 3. Revisar
php artisan instalacion:verificar
```

El comando que agregué hace todo lo que `artisan migrate` no puede hacer aquí (tu cuenta es de solo lectura y la base local no tiene migraciones).

### Cómo leer el resultado

```
  ENTORNO
   OK APP_URL                 https://reportes.incide.com.co
   OK SQLITE_DATABASE         database/sqlite/app_data.sqlite

  PERMISOS DE ESCRITURA
   OK carpetas comprobadas    12

  BASE DE DATOS LOCAL (SQLite)
   OK DownloadsHojaProc       0 fila(s)
   OK UrlSignature            0 fila(s)

  ACCESO A SIHOS
   OK MySQL                   5.6.51-91.0
   OK Pacientes legibles      60,527
   OK PDF de prueba           4.913,4 KB (admisión 202610010003)
```

Si al final dice **"Todo correcto"**, el portal funciona.

### Si algo falla

| Mensaje | Causa | Solución |
|---|---|---|
| `No se pudo generar el PDF de prueba: ... Access denied` | Permisos | Paso 4, sube a `775` |
| `... Connection refused` o `timed out` | Banahosting bloquea el 3306 saliente | Escribe a soporte de Banahosting pidiendo habilitar salida a `incide.sihos.com.co:3306` |
| `Access denied for user 'incidebd'` | Credenciales del `.env` mal escritas | Revisa `DB_USERNAME` y `DB_PASSWORD` |
| `Unknown column 'Admision.FechAdmi'` | El paquete quedó a medias | Vuelve a subirlo entero |
| `No such file or directory .env` | No lo creaste | Paso 5 |

---

## 7. Probar desde el navegador

| Qué | Dirección | Resultado esperado |
|---|---|---|
| El sitio | `https://reportes.incide.com.co` | 404 de Laravel: **significa que arrancó** |
| La página de prueba | `https://reportes.incide.com.co/test.html` | Formulario de ingreso, azul, con el logo |
| API | `https://reportes.incide.com.co/api/Auth/Login` | JSON con el token |

Haz un ingreso completo: documento → listado de admisiones → *Ver reporte*. El PDF debe abrir en la pestaña nueva con la pantalla de espera.

> Un PDF que ya tengas abierto en una pestaña **no se actualiza solo**. Si cambiaste el maquetado, ciérrala y ábrela de nuevo.

---

## 8. Antes de entregarlo a los pacientes

Esto ya estaba pendiente antes del despliegue:

1. **La contraseña es el número de documento.** Cualquiera que conozca el documento de una persona entra a sus reportes. Es el problema más grave del sistema y hay que resolverlo antes de abrirlo al público: un PIN aleatorio por correo o WhatsApp, o verificación por SMS.
2. **`test.html` es una página de pruebas sin contraseña.** Mientras esté publicada, muestra el logo y el formulario a cualquiera. Bórrala cuando el portal real esté listo, o ponla detrás de contraseña en el servidor.
3. **`APP_DEBUG=false`** confirmado en el `.env` del servidor.
4. **Credenciales reales fuera del repositorio.** El `.env` con las contraseñas de Sihos está solo en tu máquina; asegúrate de que nunca se suba a Git ni a un ZIP compartido.

---

## 9. Problema conocido, no del portal

De 973 archivos de imagen revisados, **513 (53%) no existen en el servidor de Sihos**. La distribución por año:

| Año | Disponibles |
|---|---|
| 2026 | **100 %** |
| 2025 | 71,6 % |
| 2024 | 12,4 % |
| 2023 | 13,7 % |
| 2022 | 14,2 % |
| 2021 | 15,1 % |
| 2020 | 20,8 % |
| 2019 | 11,1 % |
| 2018 | 5,5 % |
| 2017 | 2,8 % |
| 2016 | 0 % |

Los pacientes con procedimientos de 2025 en adelante los ven completos. Los de archivo antiguo verán menos fotos de las que deberían, y algunos ninguna.

**Esto se le reporta a Sihos**, no se arregla del lado del portal. Lo razonable es que ellos restauren los archivos o limpien las filas huérfanas de la base.

---

## 10. Si actualizas el proyecto más adelante

```bash
cd ~/public_html/reportes
# sube solo lo que cambió
php artisan cache:clear
php artisan view:clear
php artisan instalacion:verificar
```

Si cambiaste el maquetado del PDF, sube `VERSION_REPORTE` en `app/Services/SihosHandler.php`. Los PDFs ya guardados llevan la versión en el nombre, así que los viejos se descartan y se rehacen solos.