You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6.3 KiB
6.3 KiB
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
- 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.
- 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 — COMPLETADA
- 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 — COMPLETADA
- 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) — COMPLETADA
- “/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 — COMPLETADA
- Métricas:
- Contadores y gauges básicos expuestos en /metrics (Prometheus por defecto, JSON opcional): sync_runs_total, sync_errors_total, webhook_events_total_, webhook_errors_total, active_groups, active_members, last_sync_.
- Estado de salud:
- /health (full=1) incluye last_sync_at, snapshot_age_ms, active_groups, active_members.
- Mantenimiento:
- Job diario de purga de miembros inactivos con retención configurable (GROUP_MEMBERS_INACTIVE_RETENTION_DAYS; por defecto 180).
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).