ABIANAPP_NODE_PRODUCCION/README.md

221 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# tablas que tenemos que actualizar en la base de datos de producción
c_cambios_estado
c_cambios_estado_eliminados
c_viajes_puntos
c_viajes_puntos_tracking
c_viajes_incidencias
v_viajes_incidencias
trg_c_viajes_puntos_tracking_au
trg_c_cambios_estado_bd
# Node Gestión API Firebase Admin
Este proyecto incluye un script de prueba para enviar notificaciones con Firebase Admin SDK.
## Configuración segura de credenciales
La opción más segura para persistir `GOOGLE_APPLICATION_CREDENTIALS` en Linux es usar un archivo de entorno protegido y cargarlo desde tu gestor de procesos (systemd o PM2). Ejemplo con systemd:
1. Crea un archivo de entorno fuera del repo, con permisos restrictivos:
```
# /etc/node-gestion-api.env
GOOGLE_APPLICATION_CREDENTIALS=/var/www/node.gestion.abianservice.com/notabser-firebase-adminsdk-fbsvc-bf88758663.json
FIREBASE_DATABASE_URL=https://<DATABASE_NAME>.firebaseio.com
```
```
sudo chown root:root /etc/node-gestion-api.env
sudo chmod 600 /etc/node-gestion-api.env
```
2. En tu servicio systemd:
```
EnvironmentFile=/etc/node-gestion-api.env
```
Si trabajas localmente, puedes usar `.env` (ya soportado por `dotenv`) y mantenerlo fuera del control de versiones.
## Script de prueba (FCM)
El script está en `src/scripts/sendTestNotification.js`.
Variables esperadas (pueden ir en `.env`):
- `GOOGLE_APPLICATION_CREDENTIALS` (ruta absoluta)
- `FIREBASE_DATABASE_URL` (opcional)
- `FCM_TEST_TOKEN`
- `FCM_TEST_TITLE` (opcional)
- `FCM_TEST_BODY` (opcional)
## Uso rápido
Ejemplo de envío real:
```
node src/scripts/sendTestNotification.js --token "<FCM_DEVICE_TOKEN>" --title "Hola" --body "Prueba"
```
Ejemplo de validación sin enviar (dry run):
```
node src/scripts/sendTestNotification.js --token "<FCM_DEVICE_TOKEN>" --dry-run
```
Self-test de inicialización (no envía):
```
node src/scripts/sendTestNotification.js --self-test
```
También puedes usar el script de npm:
```
npm run notify:test -- --token "<FCM_DEVICE_TOKEN>" --dry-run
```
## Fotos de estado de viaje (almacenamiento temporal dual)
Para `POST /api/trips/:id/status`, las fotos pueden guardarse en local y replicarse por SFTP en paralelo.
- `TRIP_STATUS_UPLOAD_DIR` (opcional): base local. Admite una ruta o varias rutas candidatas separadas por `;`; si son relativas, se resuelven desde la raiz del proyecto Node.
Default: `uploads/trips/status` dentro del proyecto.
- `TRIP_STATUS_PHOTO_STORAGE_MODE` (opcional): `local` o `dual`.
Default: `local`.
- `TRIP_STATUS_SFTP_HOST`: host SFTP remoto.
- `TRIP_STATUS_SFTP_PORT` (opcional): puerto SFTP.
Default: `22`.
- `TRIP_STATUS_SFTP_USERNAME`: usuario SFTP.
- `TRIP_STATUS_SFTP_PASSWORD`: password SFTP.
- `TRIP_STATUS_SFTP_REMOTE_BASE_DIR`: directorio base remoto.
Ejemplo de modo temporal dual:
```bash
TRIP_STATUS_PHOTO_STORAGE_MODE=dual
TRIP_STATUS_SFTP_HOST=localhost
TRIP_STATUS_SFTP_PORT=22
TRIP_STATUS_SFTP_USERNAME=ssh_fotos_estado
TRIP_STATUS_SFTP_PASSWORD=********
TRIP_STATUS_SFTP_REMOTE_BASE_DIR=/var/www/vhosts/gestion.abianservice.com/httpdocs/produccion/app/fotos_estado_react_native
```
## API: Crear incidencia de viaje
Endpoint: `POST /api/trips/:tripId/incidencias`
Auth: `Bearer <JWT>` obligatorio.
### Request JSON
```json
{
"incidencia": "Retraso por tráfico",
"notificar": 0,
"notificar_cr": 0
}
```
Notas:
- `incidencia` es obligatoria (string, `trim`, no vacía).
- `notificar`/`notificar_cr` se ignoran; backend fuerza `ind_aviso_cli=1` y `ind_aviso_cr=1`.
### Responses
- `201`:
- `{ "success": true, "message": "correcto" }`
- `{ "success": true, "message": "correcto", "warning": "email_failed" }` (si falla SMTP, sin revertir insert)
- `400`: payload inválido (`tripId` inválido o `incidencia` vacía)
- `401`: no autenticado
- `403`: usuario autenticado sin acceso al viaje
- `404`: viaje no existe
- `500`: error interno
### cURL
```bash
curl -X POST "http://127.0.0.1:3001/api/trips/248230/incidencias" \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{
"incidencia": "Cliente no localizable en punto de recogida",
"notificar": 0,
"notificar_cr": 0
}'
```
## API: Estado automático de viaje (auditoría)
Endpoint: `POST /api/trips/:id/auto-status`
Auth: `Bearer <JWT>` obligatorio.
### Request JSON
```json
{
"id_estado": 5,
"id_punto": 8123,
"observaciones": "Estado actualizado automáticamente",
"ind_fallido": 0,
"latitud": "40.416775",
"longitud": "-3.703790",
"fecha_y_hora": "2026-02-17 12:34:56"
}
```
Notas:
- `id_estado` es obligatorio.
- `id_punto` es opcional.
- Si se envía `id_punto`, `id_estado` solo puede ser `3`, `4` o `5`.
- Sin `id_punto`, se permite cualquier estado válido en `t_viaje_estados`.
- `fecha_y_hora` es opcional: si no es válida se usa hora servidor.
- No se soportan fotos (`fotos_concat`/multipart).
- Este endpoint no actualiza `c_viajes.id_estado`.
- Siempre inserta en `c_cambios_estado` con `actualizado_automaticamente=1`.
- Si hay `id_punto`, también actualiza `c_viajes_puntos` con `actualizado_automaticamente=1` para disparar `trg_c_viajes_puntos_tracking_au`.
### Responses
- `200`: estado automático registrado
- `400`: payload inválido
- `401`: no autenticado
- `403`: usuario autenticado sin acceso al viaje
- `404`: viaje o punto no existe
- `422`: `id_punto` enviado con `id_estado` fuera de `3/4/5`
- `500`: error interno
## Driver license seguro (backend)
Este backend soporta carga y acceso seguro de carnet de conducir:
- `POST /api/update_driver_license` (alias: `POST /api/upload_driver_license`)
- No usar `POST /update_profile_photo` para carnet: esa ruta es solo para `foto_perfil` y ahora rechaza payloads de `driver_license`.
- `GET /api/secure/driver-license/side/:side?dni=...&id_proveedor=...` (`side`: `front|back`)
- `GET /api/secure/driver-license/:publicId` (compatibilidad)
- `DELETE /api/secure/driver-license/:publicId` (borrado lógico)
### Variables de entorno nuevas
- `DRIVER_LICENSE_ENCRYPTION_KEY` (obligatoria): clave AES-256-GCM de 32 bytes (`hex` de 64 chars o `base64`, opcional prefijo `base64:`).
- `DRIVER_LICENSE_KEY_VERSION` (opcional, default `v1`).
- `DRIVER_LICENSE_STORAGE_DIR` (opcional, default `./secure_storage/driver-license`).
- `DRIVER_LICENSE_RETENTION_DAYS` (opcional, default `365`).
- `DRIVER_LICENSE_PURGE_BATCH_SIZE` (opcional, default `100`).
### Migración SQL
Aplicar:
```
mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" < src/sql/migrations/20260216_driver_license_security.sql
mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" < src/sql/migrations/20260216_driver_license_sides.sql
```
### Purga física por retención
```
npm run purge:driver-licenses
```