|
|
|
|
@ -0,0 +1,142 @@
|
|
|
|
|
# Plan de Sincronización de Miembros (Grupos de WhatsApp)
|
|
|
|
|
|
|
|
|
|
Este documento define el plan para implementar una sincronización robusta de miembros por grupo, usando Evolution API como fuente de verdad y una réplica local en SQLite para consultas rápidas y lógica de negocio.
|
|
|
|
|
|
|
|
|
|
## Objetivos y alcance
|
|
|
|
|
- Mantener una lista actualizada de miembros por grupo (JID @g.us), con:
|
|
|
|
|
- Estado: activo/inactivo (soft delete).
|
|
|
|
|
- Rol: admin/miembro.
|
|
|
|
|
- Trazabilidad temporal: first_seen_at, last_seen_at, last_role_change_at.
|
|
|
|
|
- Fuente: Evolution API (full sync + eventos incrementales por webhook).
|
|
|
|
|
- Consistencia: idempotencia, tolerancia a webhooks perdidos (reconciliación periódica).
|
|
|
|
|
- Privacidad: almacenar solo IDs normalizados y metadatos mínimos.
|
|
|
|
|
|
|
|
|
|
## Modelo de datos (migración inicial)
|
|
|
|
|
- Tabla groups
|
|
|
|
|
- group_id TEXT PK (JID completo, p.ej. 123@g.us)
|
|
|
|
|
- name TEXT
|
|
|
|
|
- active BOOLEAN
|
|
|
|
|
- last_verified TEXT (ISO) opcional
|
|
|
|
|
- updated_at TEXT
|
|
|
|
|
- Tabla group_members
|
|
|
|
|
- group_id TEXT NOT NULL
|
|
|
|
|
- user_id TEXT NOT NULL (teléfono normalizado; dígitos)
|
|
|
|
|
- is_admin BOOLEAN NOT NULL DEFAULT 0
|
|
|
|
|
- is_active BOOLEAN NOT NULL DEFAULT 1
|
|
|
|
|
- first_seen_at TEXT NOT NULL
|
|
|
|
|
- last_seen_at TEXT NOT NULL
|
|
|
|
|
- last_role_change_at TEXT
|
|
|
|
|
- PK compuesta (group_id, user_id)
|
|
|
|
|
- Índices:
|
|
|
|
|
- group_members(group_id, is_active)
|
|
|
|
|
- group_members(user_id, is_active)
|
|
|
|
|
- Normalización:
|
|
|
|
|
- group_id: mantener sufijo @g.us
|
|
|
|
|
- user_id: usar normalizeWhatsAppId existente
|
|
|
|
|
|
|
|
|
|
## Estrategia de sincronización
|
|
|
|
|
1) Full sync (reconciliación periódica)
|
|
|
|
|
- Listar grupos bajo WHATSAPP_COMMUNITY_ID.
|
|
|
|
|
- Para cada grupo activo:
|
|
|
|
|
- Obtener miembros (paginado si aplica).
|
|
|
|
|
- Upsert de cada miembro presente:
|
|
|
|
|
- is_active=true, last_seen_at=now.
|
|
|
|
|
- is_admin si el rol viene en la respuesta; actualizar last_role_change_at cuando cambie.
|
|
|
|
|
- Marcar como inactivos los que ya no aparezcan (is_active=false, last_seen_at=now).
|
|
|
|
|
- Intervalo configurable (e.g., cada 6–24h); en test/desarrollo puede ser menor.
|
|
|
|
|
|
|
|
|
|
2) Incremental por webhooks (near-real-time)
|
|
|
|
|
- Suscripción a eventos de Evolution API:
|
|
|
|
|
- Alta de participante (join/add).
|
|
|
|
|
- Baja de participante (leave/remove).
|
|
|
|
|
- Cambio de rol (promote/demote).
|
|
|
|
|
- Renombrado/archivado de grupo.
|
|
|
|
|
- Handler idempotente:
|
|
|
|
|
- Upsert por (group_id, user_id).
|
|
|
|
|
- Cambios de estado/rol atómicos (transacción si se tocan varias filas).
|
|
|
|
|
- Si el payload es parcial (sin rol), no pisar is_admin.
|
|
|
|
|
|
|
|
|
|
## Consistencia y fallos
|
|
|
|
|
- La app consulta siempre is_active=true.
|
|
|
|
|
- Full sync corrige drift por webhooks perdidos o desordenados.
|
|
|
|
|
- Backoff y rate limiting al hablar con Evolution API.
|
|
|
|
|
- Logs con contexto: group_id, user_id, evento/tipo, resultado.
|
|
|
|
|
|
|
|
|
|
## Uso en la aplicación (consumidores)
|
|
|
|
|
- “/t ver todo” y recordatorios:
|
|
|
|
|
- Incluir “sin responsable” únicamente de grupos donde el usuario sea miembro activo.
|
|
|
|
|
- Fallback: si aún no hay snapshot de membresías, usar heurística (grupos con tareas del usuario).
|
|
|
|
|
- Validación (opcional por fase):
|
|
|
|
|
- Antes de operar sobre una tarea de grupo, comprobar membresía activa.
|
|
|
|
|
|
|
|
|
|
## Privacidad y seguridad
|
|
|
|
|
- Solo almacenar user_id normalizado y rol/fechas.
|
|
|
|
|
- No persistir nombres salvo que ya exista caché controlada.
|
|
|
|
|
- Webhook y full sync preferiblemente en red interna; si no, proteger con allowlist/proxy.
|
|
|
|
|
|
|
|
|
|
## Plan por etapas
|
|
|
|
|
Etapa 1 — Esquema + servicio
|
|
|
|
|
- Migración: crear groups y group_members + índices.
|
|
|
|
|
- Servicio GroupSync:
|
|
|
|
|
- syncGroups(): lista grupos + reconcilia miembros.
|
|
|
|
|
- reconcileGroup(groupId, membersSnapshot).
|
|
|
|
|
- Utilidades: timestamps ISO, normalización de IDs.
|
|
|
|
|
- Tests:
|
|
|
|
|
- Migración up-only.
|
|
|
|
|
- Reconciliación: de [A,B,C] a [A,C,D] → B inactivo, D añadido; tiempos/roles actualizados.
|
|
|
|
|
|
|
|
|
|
Etapa 2 — Integración con Evolution API
|
|
|
|
|
- Full sync: llamadas reales a endpoints (respetando paginación y límites).
|
|
|
|
|
- Webhooks: registro y handlers idempotentes (alta/baja/rol/rename).
|
|
|
|
|
- Tests:
|
|
|
|
|
- Fixtures de payloads típicos (duplicados, orden alterado).
|
|
|
|
|
- Reintentos/backoff en errores de red/5xx.
|
|
|
|
|
|
|
|
|
|
Etapa 3 — Consumidores (comandos y recordatorios)
|
|
|
|
|
- “/t ver todo” y RemindersService usan membership real.
|
|
|
|
|
- Fallback heurístico si no hay snapshot aún.
|
|
|
|
|
- Validaciones opcionales de pertenencia.
|
|
|
|
|
- Tests:
|
|
|
|
|
- Cobertura de ambos caminos (con y sin membership).
|
|
|
|
|
|
|
|
|
|
Etapa 4 — Observabilidad y mantenimiento
|
|
|
|
|
- Métricas:
|
|
|
|
|
- grupos sincronizados, miembros activos, difs por sync, errores de webhook.
|
|
|
|
|
- Estado de salud:
|
|
|
|
|
- último sync OK, edad de la snapshot.
|
|
|
|
|
- Mantenimiento:
|
|
|
|
|
- Re-sync diario.
|
|
|
|
|
- Purgado opcional de inactivos antiguos.
|
|
|
|
|
|
|
|
|
|
## Criterios de aceptación
|
|
|
|
|
- Tras una full sync, group_members refleja fielmente miembros activos por grupo.
|
|
|
|
|
- Webhooks de alta/baja actualizan el estado en <1s y son idempotentes.
|
|
|
|
|
- “/t ver todo” y recordatorios respetan la membresía y no rompen UX preexistente.
|
|
|
|
|
- 100% de tests existentes siguen pasando; nuevos tests cubren sync/reconciliación/handlers.
|
|
|
|
|
|
|
|
|
|
## Métricas y trazas sugeridas
|
|
|
|
|
- Contadores: sync_runs_total, sync_errors_total, webhook_events_total, webhook_errors_total.
|
|
|
|
|
- Gauges: active_groups, active_members.
|
|
|
|
|
- Logs estructurados: action, group_id, user_id, outcome, diff_counts.
|
|
|
|
|
|
|
|
|
|
## Riesgos y mitigaciones
|
|
|
|
|
- Webhooks perdidos: reconciliación periódica.
|
|
|
|
|
- Cambios de API o límites: backoff + degradación controlada.
|
|
|
|
|
- Coste de consultas: índices adecuados; joins simples.
|
|
|
|
|
- Privacidad: minimización de datos, documentación en README/STATUS.
|
|
|
|
|
|
|
|
|
|
## Estimación
|
|
|
|
|
- Etapa 1: 0.5–1 día.
|
|
|
|
|
- Etapa 2: 1–1.5 días.
|
|
|
|
|
- Etapa 3: 0.5 día.
|
|
|
|
|
- Etapa 4 (opcional): 0.5 día.
|
|
|
|
|
Total: 2–3.5 días netos.
|
|
|
|
|
|
|
|
|
|
## Dependencias y archivos a tocar (cuando implementemos)
|
|
|
|
|
- src/db.ts (esquema base para nuevas instalaciones).
|
|
|
|
|
- src/db/migrations/index.ts (migración up-only: tablas e índices).
|
|
|
|
|
- src/services/webhook-manager.ts (registro y handlers de eventos).
|
|
|
|
|
- src/services/group-sync.ts (full sync y reconciliación).
|
|
|
|
|
- src/services/command.ts (consumo en “/t ver todo”; validaciones opcionales).
|
|
|
|
|
- src/services/reminders.ts y src/tasks/service.ts (consultas usando membresía).
|
|
|
|
|
- tests/unit/services/* (sync, reconciliación, webhooks, consumidores).
|