Propuesta de Desarrollo: POLIFON SEGURO
Esta propuesta detalla la arquitectura para una API unificada de seguridad y telemetría. El objetivo es gestionar la seguridad personal de los usuarios mediante una red de confianza, geocercas inteligentes y protocolos de emergencia en tiempo real.
Base URL Propuesta
https://api.polifon-seguro.mx
Autenticación
Header requerido en todas las peticiones:
Authorization: Bearer <token>
Módulo de Contactos Seguros
Gestión de red de confianza y validación de identidad por canal externo (SMS).
API Endpoints
Registra un nuevo contacto en estado "Pendiente" y dispara un SMS con un enlace de invitación.
{
"alias": "Papá",
"phoneNumber": "+529511234567",
"email": "contacto@ejemplo.com"
}
{
"contactId": "cont-98765",
"status": "PENDING",
"message": "Invitación enviada exitosamente vía SMS"
}
Endpoint que utiliza el contacto para aceptar la invitación.
{
"token": "inv_abc123xyz",
"accepted": true
}
{
"status": "ACTIVE",
"sharedUserName": "Uriel Manzano"
}
Retorna listado y estado.
[
{
"id": "cont-98765",
"alias": "Papá",
"phoneNumber": "+529511234567",
"status": "ACTIVE",
"hasApp": true
}
]
Eliminar un contacto de la red.
Flujo de Registro (UX)
Captura de datos
El usuario ingresa Nombre, Teléfono y Correo en la app Flutter.
Solicitud al Backend
La app envía los datos. El contacto aparece con ícono de reloj (ámbar) indicando estado "Pendiente".
Disparo de Invitación
El backend genera un Token Único y envía SMS al número registrado.
- SMS: "Uriel te ha invitado... haz clic aquí: polifon.com.mx/v/token"
- Web View: Se abre Landing Page ligera para aceptar.
- Resultado: Recibirá SMS con enlace a Mapa Web en emergencias.
- Detección: Backend detecta el número registrado en BD.
- Dual Notificación: SMS (Deep Link) + Push Notification.
- Resultado: Notificación Crítica y Mapa nativo dentro de la app.
Comparativa de Validación y Alerta
| Característica | Contacto SIN App | Contacto CON App |
|---|---|---|
| Canal de Invitación | Solo SMS | SMS + Push Notification |
| Método de Aceptación | Portal Web Móvil | Interfaz Nativa App |
| Canal de Alerta | SMS con enlace web | Notificación Push Crítica + SMS |
| Visualización Mapa | Navegador (Google Maps Web) | Mapa Nativo (SDK) |
| Privacidad | Enlace expira tras emergencia | Acceso se revoca desde backend |
Módulo de Zonas Seguras (Geocercas)
Este módulo permite al usuario definir perímetros geográficos y reglas de tiempo para automatizar la vigilancia de su seguridad.
API Endpoints
Registra una nueva geocerca vinculada al usuario. Soporta configuraciones de "Única vez" (eventos) o "Recurrentes" (rutinas).
{
"id": "abc-123",
"name": "Oficina",
"latitude": 17.0654,
"longitude": -96.7236,
"radiusMeters": 150,
"type": "RECURRENT",
"schedule": [
{ "day": 1, "enabled": true, "arrivalTime": "09:00", "waitTimeMinutes": 30 },
{ "day": 2, "enabled": true, "arrivalTime": "09:00", "waitTimeMinutes": 15 }
],
"date": null,
"arrivalTime": null,
"waitTimeMinutes": null,
"createdAt": "2026-02-04T10:00:00Z",
"updatedAt": "2026-02-04T10:00:00Z"
}
{
"id": "abc-123",
"name": "Oficina",
"latitude": 17.0654,
"longitude": -96.7236,
"radiusMeters": 150,
"type": "UNIQUE",
"schedule": [],
"date": 1738713600000,
"arrivalTime": "18:00",
"waitTimeMinutes": 20,
"createdAt": "2026-02-04T10:00:00Z",
"updatedAt": "2026-02-04T10:00:00Z"
}
Actualiza los datos de una geocerca existente. Se debe enviar el payload completo.
{
"name": "Oficina Nueva Ubicación",
"latitude": 17.0700,
"longitude": -96.7300,
"radiusMeters": 200,
"type": "RECURRENT",
"schedule": [
{ "day": 1, "enabled": true, "arrivalTime": "08:30", "waitTimeMinutes": 30 }
]
}
[
{
"id": "abc-123",
"name": "Oficina",
"latitude": 17.0654,
"longitude": -96.7236,
"radiusMeters": 150,
"type": "UNIQUE",
"schedule": [],
"date": 1738713600000,
"arrivalTime": "18:00",
"waitTimeMinutes": 20,
"createdAt": "2026-02-04T10:00:00Z",
"updatedAt": "2026-02-04T10:00:00Z"
}
]
Elimina una geocerca y detiene el monitoreo.
{
"status": "DELETED",
"message": "Monitoreo de zona cancelado."
}
Flujo de Registro (Lado del Usuario)
Selección Geográfica
El usuario visualiza el mapa en la App (Flutter) y posiciona un marcador. Ajusta el radio mediante un slider.
Configuración de Reglas
Elige si es una ruta para un evento único o rutina diaria. Define la hora de llegada esperada.
Persistencia Local & Sincronización
La App guarda copia en Hive (local) y envía el JSON al Backend mediante POST /api/zones.
Activación de Monitor
El Backend recibe la zona y agenda una tarea en su motor de base de datos/cola de procesos.
Resumen de Responsabilidades
Frontend (App)
- Renderizar el círculo de la geocerca en el mapa en tiempo real.
- Solicitar y gestionar permisos de ubicación "Siempre" (Background Location).
- Detectar mediante GPS si el usuario entró o salió de la zona para actualizar estado visual.
Backend (Server)
- Almacenar las coordenadas y las reglas de periodicidad.
- Ejecutar el "reloj" que verifica si el usuario envió telemetría dentro de la zona.
- Disparar las notificaciones de alerta si no se recibe confirmación de llegada.
Consideraciones y Retos Técnicos
Consideraciones
- Zonas Mínimas: Radio mínimo 50m para evitar falsas alertas.
- Zonas Horarias: Backend en UTC, Frontend envía offset local.
- Solapamiento: Priorizar zona con menor wait_time.
Retos Backend
- Precisión de Jobs: Gestionar miles de cronómetros simultáneos.
- Cálculo Geoespacial: Validaciones eficientes (Haversine Formula) para telemetría.
Retos Frontend
- Permisos: Convencer a iOS/Android para ubicación en segundo plano.
- Batería: Despertar GPS solo cerca de la hora de ruta activa.
Módulo de Telemetría y Ubicación
Recolecta, envía y distribuye datos de ubicación y estado del dispositivo en tiempo real.
API Endpoints
El frontend envía periódicamente coordenadas y estado. Soporta envío por lote (batch).
{
"dn": "5661293833",
"records": [
{
"coords": {
"lat": 17.06542,
"lng": -96.72365,
"accuracy": 5.0,
"altitude": 1550.0
},
"deviceStatus": {
"batteryLevel": 82,
"isCharging": false,
"signalStrength": "EXCELLENT",
"connectionType": "4G"
},
"contextMode": "IN_ROUTE",
"timestamp": "2026-01-28T09:45:00Z"
}
]
}
{
"status": "RECEIVED",
"nextSyncIntervalSeconds": 120,
"activeEmergency": false
}
El usuario confirma que está a salvo tras recibir notificación preventiva.
{
"status": "SAFE",
"confirmationCode": "1234"
}
{ "status": "MONITORING_RESUMED" }
Consultada por portal web o app del contacto en caso de emergencia.
{
"userAlias": "Uriel Manzano",
"currentCoords": { "lat": 17.06, "lng": -96.72 },
"history": [ { "lat": 17.05, "lng": -96.71 }, ... ], // Últimos 30 min
"deviceStatus": { "battery": 82, "signal": "4G" }
}
Flujos de Comunicación (App → Backend)
Envío Estándar
-
1Activación Sensor App despierta GPS según modo (Standby, Ruta o Emergencia).
-
2Filtrado Ignora coordenadas con precisión > 50m (evita saltos en mapa).
-
3Transmisión Envío HTTPS. Si falla, guarda en caché local (Hive) para reintento.
Flujo Check-in / Ruta Activa
-
1Trigger Backend Si tiempo de gracia (ej. 15 min) se agota sin llegar al destino.
-
2Notificación Push Pregunta al usuario: "¿Estás bien?".
-
3Decisión (2 min) Confirma: Protocolo se detiene.
No confirma: Backend activa Emergencia.
Recepción: ¿Cómo lo ve el contacto?
| Característica | Contacto SIN App | Contacto CON App |
|---|---|---|
| Interfaz | Navegador Web (Ligero) | App Nativa (Fluido) |
| Notificaciones | Solo SMS | Push constantes + SMS |
| Tecnología Mapa | Google Maps JS API (Polling) | SDK Nativo + WebSockets |
| Consumo de Datos | Medio (Recarga mapa completo) | Bajo (Streaming solo puntos) |
Estrategia Técnica
Backend (Cerebro)
- Persistencia Temporal: Redis para historial de 2h ("estela" de ruta).
- Gatekeeper: Bloquea acceso a ubicación si NO hay emergencia activa.
- Cálculo Inactividad: >10min sin señal en Ruta Activa = Alerta preventiva.
Retos y Consideraciones
- Frontend: Bajar precisión GPS si usuario no se mueve (Ahorro Energía).
- Android 14+: Requiere notificación persistente para Foreground Service.
- Interiores: Usar "Last Known Location" si precisión GPS cae.
Protocolo Crítico de Emergencia
Gestión de alertas y transición a estado de pánico con comunicación ininterrumpida.
API Endpoints
Informa al servidor que el usuario ha iniciado un protocolo de emergencia (manual o silencioso).
{
"type": "SILENT", // "NORMAL" o "SILENT"
"triggerSource": "USER_BUTTON",
"initialCoords": {
"lat": 17.06542, "lng": -96.72365,
"accuracy": 3.5
},
"deviceStatus": { "battery": 22, "signal": "4G" }
}
{
"eventId": "panic_556677",
"status": "EMERGENCY_ACTIVE",
"timestamp": "2026-01-28T10:15:00Z"
}
Detiene el protocolo. Requiere validación de identidad (PIN) para evitar coacción.
{
"eventId": "panic_556677",
"securityPin": "1234",
"reason": "FALSE_ALARM"
}
{
"status": "RESOLVED",
"message": "Protocolo finalizado."
}
Matriz de Responsabilidades (Fases)
1. Activación
Frontend: Detectar clic o fin de temporizador. Enviar POST /panic inmediato.
Backend: Registrar evento. Cambiar estado usuario a EMERGENCY en DB.
2. Notificación
Frontend: Si silencioso, simular apagado. Si normal, pantalla de alerta.
Backend: Disparar Push (Alta prioridad) y SMS con token de rastreo.
3. Seguimiento
Frontend: Iniciar Foreground Service. Enviar GPS cada 10-15s sin falta.
Backend: Habilitar WebSockets. Servir portal de emergencia externo.
4. Cierre
Frontend: Solicitar PIN seguro. Enviar POST /cancel.
Backend: Validar PIN. Notificar cierre y revocar accesos.
Recepción de Alerta: Comparativa
| Característica | Contacto SIN App | Contacto CON App |
|---|---|---|
| Alertas | Solo SMS inicial | Push persistente + SMS |
| Mapa | Portal Web (Google Maps JS) | App Nativa (SDK) |
| Actualización | Polling HTTP (Cada 10s) | WebSocket (Fluido) |
| Interactividad | Solo visualización | Botón llamada 911 directo |
Consideraciones Críticas
Backend & Infra
- Alta Disponibilidad: Servidores redundantes para alertas.
- Tokenización: URLs temporales para no-usuarios.
- Autocontrol: Disparar alerta si app muere en zona peligrosa.
Frontend & App
- Foreground Service: Evitar que Android cierre la app.
- Modo Silencioso: Cero feedback visual para el agresor.
- Seguridad PIN: Bloquear cierre forzado de app.
Tipos de Disparador
- Manual: Botón de Pánico (Normal/Silencioso).
- Automático: Check-in fallido en Geocerca.
- Inactividad: Pérdida de señal en ruta activa.