# 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 — 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).
