# DESPLIEGUE Y OPERACIÓN — Recarga.do API v1 ## Infraestructura actual | Elemento | Valor | |---|---| | Dominio API | `api.recarga.do` → 35.231.97.177 | | Dominio docs | `doc.recarga.do` → 35.231.97.177 | | DocumentRoot API | `/var/www/recarga.do/api/public` | | DocumentRoot docs | `/var/www/recarga.do/doc` | | Servidor | Apache 2 + PHP-FPM 8.4 | | TLS | Let's Encrypt (ECDSA), renovación automática vía `certbot.timer` | | Base de datos | MySQL 5.6.51 (Google Cloud SQL), `recargas_2` | VirtualHosts: - `/etc/apache2/sites-available/api.recarga.do.conf` (:80, redirige a HTTPS) - `/etc/apache2/sites-available/api.recarga.do-le-ssl.conf` (:443) - equivalentes para `doc.recarga.do` --- ## Configuración Los secretos viven **fuera del webroot**, en `/etc/recarga.do/api.env`: ``` -rw-r----- root:www-data /etc/recarga.do/api.env drwxr-x--- root:www-data /etc/recarga.do/ ``` Variables (plantilla completa en `api/.env.example`, sin valores reales): ```env APP_ENV=production APP_URL=https://api.recarga.do APP_DEBUG=false LOG_LEVEL=info DB_HOST=******** DB_PORT=3306 DB_DATABASE=******** DB_USERNAME=******** DB_PASSWORD=******** DB_TIMEOUT=10 MIDASRED_URL=******** MIDASRED_USERNAME=******** MIDASRED_PASSWORD=******** MIDASRED_API_KEY=******** MIDASRED_CONNECT_TIMEOUT=5 MIDASRED_TIMEOUT=30 MIDASRED_VERIFY_TLS=true RATE_LIMIT_PER_MINUTE=120 IDEMPOTENCY_TTL_HOURS=24 ``` `MIDASRED_VERIFY_TLS` debe permanecer en `true`. El sistema legado la desactiva (hallazgo A-03); no replicar ese comportamiento. --- ## Permisos ```bash chown -R www-data:www-data /var/www/recarga.do/api chmod -R 750 /var/www/recarga.do/api chmod 770 /var/www/recarga.do/api/storage/logs ``` Solo `public/` es alcanzable por HTTP. `app/`, `config/`, `routes/` y `database/` quedan fuera del DocumentRoot por diseño. --- ## Migraciones Las migraciones son SQL plano en `api/database/migrations/`, con su bloque de rollback documentado dentro del propio archivo. Aplicada el 2026-08-12: | Archivo | Efecto | Reversible | |---|---|---| | `2026_08_12_000001_api_v1_tables.sql` | Crea `api_idempotency_keys`, `api_rate_counters`, `api_audit_log` | Sí — `DROP TABLE` de las tres | Estrictamente aditiva: `CREATE TABLE IF NOT EXISTS` únicamente. No altera ni elimina ningún objeto preexistente, por lo que no afecta al sistema en producción. --- ## Verificación tras desplegar ```bash # Sintaxis find /var/www/recarga.do/api -name '*.php' -exec php -l {} \; | grep -v 'No syntax errors' # Configuración de Apache apache2ctl configtest && systemctl reload apache2 # Endpoints públicos curl -s https://api.recarga.do/v1/health curl -s https://api.recarga.do/v1/info # El acceso sin credenciales debe dar 401 curl -s -o /dev/null -w '%{http_code}\n' https://api.recarga.do/v1/balance # → 401 # Nada fuera de public/ debe ser servible curl -s -o /dev/null -w '%{http_code}\n' https://api.recarga.do/../config/app.php ``` --- ## Mantenimiento pendiente de instalar Ninguno de estos procesos está activo todavía. Los tres son necesarios: ### 1. Barrido de transacciones pendientes — **prioritario** Resuelve contra el proveedor las transacciones en estado `pendiente`, liberando o confirmando el importe retenido. Hay 367 pendientes históricas (RD$ 43,381.00). ```cron */5 * * * * www-data php /var/www/recarga.do/api/bin/reconcile.php >> /var/log/recarga-api-reconcile.log 2>&1 ``` ### 2. Purga de claves de idempotencia y contadores ```cron 0 3 * * * www-data php /var/www/recarga.do/api/bin/purge.php ``` ### 3. Rotación de logs `storage/logs/api-YYYY-MM-DD.log` crece sin límite. Configurar `logrotate` a 30 días. > Los scripts `bin/reconcile.php` y `bin/purge.php` **aún no están escritos**. La lógica > de reconciliación ya existe en `RechargeService::reconciliar()`; falta el envoltorio CLI. --- ## Monitoreo recomendado | Señal | Umbral de alerta | |---|---| | Transacciones en `pendiente` con más de 15 min | > 0 | | Tasa de `PROVIDER_TIMEOUT` | > 2 % de las recargas | | Empresas con `saldo_disponible < 0` | > 0 (hoy: 2) | | Diferencia `saldo_actual` vs `saldo_disponible + saldo_retenido` | ≠ 0 | | Latencia p95 de `POST /v1/recharges` | > 5 s | | Errores 500 | > 0 | Todas se obtienen de `api_audit_log`, `transacciones` y `empresa_balances`. --- ## Rollback La API v1 es independiente del sistema existente. Para desactivarla: ```bash a2dissite api.recarga.do.conf api.recarga.do-le-ssl.conf systemctl reload apache2 ``` El portal, el motor de recargas y los procesos automáticos siguen funcionando: no dependen de la API v1 en ningún punto. Si además se descarta el proyecto, ejecutar el bloque de rollback de la migración (`DROP TABLE` de las tres tablas nuevas). No hay otras dependencias.