6.5 KiB
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:
- 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
- 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_TOKENFCM_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.
Default:uploads/trips/statusdentro del proyecto.TRIP_STATUS_PHOTO_STORAGE_MODE(opcional):localodual.
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:
TRIP_STATUS_PHOTO_STORAGE_MODE=dual
TRIP_STATUS_SFTP_HOST=194.164.175.51
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
{
"incidencia": "Retraso por tráfico",
"notificar": 0,
"notificar_cr": 0
}
Notas:
incidenciaes obligatoria (string,trim, no vacía).notificar/notificar_crse ignoran; backend fuerzaind_aviso_cli=1yind_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 (tripIdinválido oincidenciavacía)401: no autenticado403: usuario autenticado sin acceso al viaje404: viaje no existe500: error interno
cURL
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
{
"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_estadoes obligatorio.id_puntoes opcional.- Si se envía
id_punto,id_estadosolo puede ser3,4o5. - Sin
id_punto, se permite cualquier estado válido ent_viaje_estados. fecha_y_horaes 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_estadoconactualizado_automaticamente=1. - Si hay
id_punto, también actualizac_viajes_puntosconactualizado_automaticamente=1para disparartrg_c_viajes_puntos_tracking_au.
Responses
200: estado automático registrado400: payload inválido401: no autenticado403: usuario autenticado sin acceso al viaje404: viaje o punto no existe422:id_puntoenviado conid_estadofuera de3/4/5500: 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_photopara carnet: esa ruta es solo parafoto_perfily ahora rechaza payloads dedriver_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 (hexde 64 chars obase64, opcional prefijobase64:).DRIVER_LICENSE_KEY_VERSION(opcional, defaultv1).DRIVER_LICENSE_STORAGE_DIR(opcional, default./secure_storage/driver-license).DRIVER_LICENSE_RETENTION_DAYS(opcional, default365).DRIVER_LICENSE_PURGE_BATCH_SIZE(opcional, default100).
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