# Novasis Pay — Guía de instalación (dev/staging on-prem)

Guía paso a paso para levantar el stack completo (`novasis-pay` + `novasis-pay-admin` + `novasis-pay-checkout`) detrás de Apache con 3 subdominios y certificado autofirmado (o Let's Encrypt en producción).

> Asume Ubuntu/Debian, Node 20+, pnpm 10+, PostgreSQL ≥14, Redis ≥6, Apache 2.4 con `mod_proxy`, `mod_ssl`, `mod_rewrite` habilitados, y PM2 para procesos.

---

## 0. Variables que cambian por instalación

| Variable        | Ejemplo                          |
| --------------- | -------------------------------- |
| Dominio raíz    | `factupy.es`                     |
| Sub-API         | `novasispay-api.factupy.es`      |
| Sub-Admin       | `novasispay-admin.factupy.es`    |
| Sub-Checkout    | `novasispay-checkout.factupy.es` |
| Puerto backend  | `3010`                           |
| Base path repos | `/var/www/html`                  |
| DB / user       | `novasis_pay` / `novasis_pay`    |
| Redis DB index  | `2` (separar del ERP)            |

Reemplazá estos valores en los bloques siguientes.

---

## 1. Prerrequisitos del servidor

```bash
sudo apt update
sudo apt install -y postgresql redis-server apache2 certbot python3-certbot-apache
sudo a2enmod proxy proxy_http ssl rewrite headers expires
sudo systemctl restart apache2
# Node + pnpm + pm2 (si no están)
node -v && pnpm -v && pm2 -v
```

---

## 2. Base de datos

```bash
sudo -u postgres psql <<'SQL'
CREATE USER novasis_pay WITH PASSWORD 'CAMBIAR_ESTO';
CREATE DATABASE novasis_pay OWNER novasis_pay;
GRANT ALL PRIVILEGES ON DATABASE novasis_pay TO novasis_pay;
SQL
```

---

## 3. Backend (`novasis-pay`)

```bash
cd /var/www/html/novasis-pay
cp .env.example .env
```

**Editar `.env`** (mínimo a tocar):

```env
NODE_ENV=production
PORT=3010
LOG_LEVEL=info

DATABASE_URL=postgresql://novasis_pay:CAMBIAR_ESTO@localhost:5432/novasis_pay?schema=public

REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=

# Generar con: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
MASTER_ENCRYPTION_KEY=...
# Generar con: node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
ADMIN_JWT_SECRET=...

CHECKOUT_BASE_URL=https://novasispay-checkout.factupy.es
API_BASE_URL=https://novasispay-api.factupy.es

# CORS — orígenes permitidos para llamadas cross-origin desde admin/checkout SPA.
# Vacío = permite cualquier origen (solo dev). En prod listar los exactos.
PUBLIC_CORS_ORIGINS=https://novasispay-admin.factupy.es,https://novasispay-checkout.factupy.es

DLOCAL_GO_BASE_URL=https://api-sbx.dlocalgo.com
DLOCAL_GO_MODE=sandbox
```

Instalar, migrar, buildear y arrancar con PM2:

```bash
pnpm install --frozen-lockfile
pnpm prisma:generate
pnpm prisma:migrate:deploy
pnpm build
pnpm seed:admin --email admin@empresa.com --name "Nombre Apellido" --password "supersecreto"
   # crea el usuario admin inicial

pm2 start dist/main.js --name novasis-pay-api --update-env
pm2 save
pm2 startup systemd -u $USER --hp $HOME   # solo la primera vez
```

Verificación:

```bash
curl -i http://127.0.0.1:3010/health
```

---

## 4. Frontends (Vite estático)

### 4.1 Admin

```bash
cd /var/www/html/novasis-pay-admin
cat > .env.production <<'EOF'
# URL absoluta a la API — el client lo respeta. Incluí /v1.
VITE_API_BASE_URL=https://novasispay-api.factupy.es/v1
EOF
pnpm install --frozen-lockfile
pnpm build
# salida en dist/
```

### 4.2 Checkout

```bash
cd /var/www/html/novasis-pay-checkout
cat > .env.production <<'EOF'
VITE_API_BASE_URL=https://novasispay-api.factupy.es/v1
EOF
pnpm install --frozen-lockfile
pnpm build
```

> Los `dist/` se sirven directo desde Apache. No corre PM2.

---

## 5. Certificado autofirmado (dev/staging)

```bash
sudo mkdir -p /etc/apache2/ssl/novasispay
sudo openssl req -x509 -nodes -days 825 -newkey rsa:2048 \
  -keyout /etc/apache2/ssl/novasispay/novasispay.key \
  -out    /etc/apache2/ssl/novasispay/novasispay.crt \
  -subj "/C=PY/ST=Central/L=Asuncion/O=Novasis/CN=novasispay-api.factupy.es" \
  -addext "subjectAltName=DNS:novasispay-api.factupy.es,DNS:novasispay-admin.factupy.es,DNS:novasispay-checkout.factupy.es"
sudo chmod 600 /etc/apache2/ssl/novasispay/novasispay.key
```

> En producción real, reemplazar por: `sudo certbot --apache -d novasispay-api.factupy.es -d novasispay-admin.factupy.es -d novasispay-checkout.factupy.es`

---

## 6. Apache vhosts

### 6.1 API — `/etc/apache2/sites-available/novasispay-api.conf`

```apache
<VirtualHost *:80>
    ServerName novasispay-api.factupy.es
    Redirect permanent / https://novasispay-api.factupy.es/
</VirtualHost>

<VirtualHost *:443>
    ServerName novasispay-api.factupy.es

    SSLEngine on
    SSLCertificateFile      /etc/apache2/ssl/novasispay/novasispay.crt
    SSLCertificateKeyFile   /etc/apache2/ssl/novasispay/novasispay.key

    ProxyPreserveHost On
    ProxyRequests Off
    ProxyPass        / http://127.0.0.1:3010/
    ProxyPassReverse / http://127.0.0.1:3010/

    RequestHeader set X-Forwarded-Proto "https"

    ErrorLog  ${APACHE_LOG_DIR}/novasispay-api-error.log
    CustomLog ${APACHE_LOG_DIR}/novasispay-api-access.log combined
</VirtualHost>
```

### 6.2 Admin — `/etc/apache2/sites-available/novasispay-admin.conf`

```apache
<VirtualHost *:80>
    ServerName novasispay-admin.factupy.es
    Redirect permanent / https://novasispay-admin.factupy.es/
</VirtualHost>

<VirtualHost *:443>
    ServerName novasispay-admin.factupy.es

    SSLEngine on
    SSLCertificateFile      /etc/apache2/ssl/novasispay/novasispay.crt
    SSLCertificateKeyFile   /etc/apache2/ssl/novasispay/novasispay.key

    DocumentRoot /var/www/html/novasis-pay-admin/dist

    <Directory /var/www/html/novasis-pay-admin/dist>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted

        # SPA fallback
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^ index.html [L]
    </Directory>

    <FilesMatch "\.(js|css|woff2?|svg|png|jpg|webp)$">
        Header set Cache-Control "public, max-age=31536000, immutable"
    </FilesMatch>

    ErrorLog  ${APACHE_LOG_DIR}/novasispay-admin-error.log
    CustomLog ${APACHE_LOG_DIR}/novasispay-admin-access.log combined
</VirtualHost>
```

### 6.3 Checkout — `/etc/apache2/sites-available/novasispay-checkout.conf`

Igual al admin, cambiando `ServerName` y `DocumentRoot` a `/var/www/html/novasis-pay-checkout/dist`.

### 6.4 Activar

```bash
sudo a2ensite novasispay-api novasispay-admin novasispay-checkout
sudo apachectl configtest
sudo systemctl reload apache2
```

---

## 7. DNS

Apuntar los 3 subdominios al IP público del server:

```
novasispay-api.factupy.es       A   <IP>
novasispay-admin.factupy.es     A   <IP>
novasispay-checkout.factupy.es  A   <IP>
```

---

## 8. Verificación end-to-end

```bash
curl -ki https://novasispay-api.factupy.es/health
curl -kI https://novasispay-admin.factupy.es/
curl -kI https://novasispay-checkout.factupy.es/
```

- `/health` → 200 con JSON `status: ok`
- `/docs` → Swagger (solo si `NODE_ENV != production`)
- Admin: login con el usuario creado por `seed:admin`
- Checkout: probar flujo de cobro sandbox dLocal

---

## 9. Updates / redeploy

```bash
cd /var/www/html/novasis-pay
git pull
pnpm install --frozen-lockfile
pnpm prisma:migrate:deploy
pnpm build
pm2 reload novasis-pay-api

cd ../novasis-pay-admin   && git pull && pnpm install --frozen-lockfile && pnpm build
cd ../novasis-pay-checkout && git pull && pnpm install --frozen-lockfile && pnpm build
```

---

## 10. Troubleshooting

| Síntoma                                | Causa probable                                                                               |
| -------------------------------------- | -------------------------------------------------------------------------------------------- |
| `502 Bad Gateway` en API               | PM2 caído (`pm2 logs novasis-pay-api`) o puerto distinto al del vhost                        |
| CORS bloqueado en admin/checkout       | `API_BASE_URL` / `CHECKOUT_BASE_URL` mal seteados en `.env` del backend                      |
| `P1001` Prisma                         | DATABASE_URL incorrecto o postgres no acepta conexiones locales                              |
| Migración falla por orden              | Verificar nombres de directorios en `prisma/migrations/` — Prisma los aplica alfabéticamente |
| Cert autofirmado da warning en browser | Importar `novasispay.crt` como trusted en el equipo cliente, o usar Let's Encrypt            |
| Webhooks del provider no llegan        | `API_BASE_URL` debe ser público; en dev exponer con cloudflared/ngrok                        |

---

## 11. Checklist de seguridad antes de exponer

- [ ] `.env` con permisos `600` y owner correcto
- [ ] `MASTER_ENCRYPTION_KEY` y `ADMIN_JWT_SECRET` únicos por entorno (nunca commiteados)
- [ ] Password de DB rotada
- [ ] Redis bindeado a `127.0.0.1` o protegido con password
- [ ] `NODE_ENV=production` para deshabilitar Swagger
- [ ] Firewall: solo 80/443 expuestos públicamente; 3010, 5432, 6379 cerrados
- [ ] Backups automáticos de la DB
