|  |  | # Plan de habilitación multi‑comunidades con control de acceso
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Propósito
 | 
						
						
						
							|  |  | - Permitir que el bot opere en varias comunidades/grupos sin perder control.
 | 
						
						
						
							|  |  | - Introducir un mecanismo de whitelist (allowed_groups) y un flujo de aprobación administrativa.
 | 
						
						
						
							|  |  | - Mantener las mismas funcionalidades en todos los grupos aprobados.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Resumen de estrategia
 | 
						
						
						
							|  |  | - Instancia única multi‑comunidad con “gating” por grupo permitido.
 | 
						
						
						
							|  |  | - Descubrimiento seguro: registrar grupos desconocidos como pending y no operar hasta aprobación.
 | 
						
						
						
							|  |  | - Comandos/admin y notificaciones para aprobar/bloquear grupos.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Estructura del plan por etapas
 | 
						
						
						
							|  |  | Cada etapa indica objetivos y archivos a tocar. La implementación es incremental y desplegable paso a paso.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 0 — Preparación y criterios
 | 
						
						
						
							|  |  | Objetivos
 | 
						
						
						
							|  |  | - Alinear alcance y criterios de aceptación.
 | 
						
						
						
							|  |  | - Definir nuevas variables de entorno y defaults.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Criterios de aceptación
 | 
						
						
						
							|  |  | - Variables definidas:
 | 
						
						
						
							|  |  |   - ADMIN_USERS: lista de user_ids normalizados con permisos de administración.
 | 
						
						
						
							|  |  |   - ALLOWED_GROUPS: lista inicial (semilla) de group_ids a marcar como allowed.
 | 
						
						
						
							|  |  |   - AUTO_APPROVE_PATTERNS (opcional): patrones de nombre de grupo confiables (con cautela).
 | 
						
						
						
							|  |  | - Comportamiento por defecto para grupos desconocidos: registrar como pending y no operar.
 | 
						
						
						
							|  |  | - Decidir si el bot responde (o guarda silencio) en grupos pending/blocked.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Archivos a tocar
 | 
						
						
						
							|  |  | - Documentación (docs/operations.md, docs/architecture.md) — actualización en Etapa 6.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 1 — Esquema y servicio AllowedGroups (sin gating todavía)
 | 
						
						
						
							|  |  | Objetivos
 | 
						
						
						
							|  |  | - Crear tabla allowed_groups con estados: pending | allowed | blocked.
 | 
						
						
						
							|  |  | - Implementar servicio con caché en memoria y API:
 | 
						
						
						
							|  |  |   - upsertPending(groupId, label?, discoveredBy?) → pending
 | 
						
						
						
							|  |  |   - isAllowed(groupId) → boolean
 | 
						
						
						
							|  |  |   - setStatus(groupId, status, label?) → boolean
 | 
						
						
						
							|  |  |   - listByStatus(status) → {group_id, label}[]
 | 
						
						
						
							|  |  |   - seedFromEnv(ALLOWED_GROUPS)
 | 
						
						
						
							|  |  | - Métricas básicas por estado (gauges).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Cambios de datos
 | 
						
						
						
							|  |  | - Tabla allowed_groups:
 | 
						
						
						
							|  |  |   - group_id TEXT PRIMARY KEY
 | 
						
						
						
							|  |  |   - label TEXT NULL
 | 
						
						
						
							|  |  |   - status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','allowed','blocked'))
 | 
						
						
						
							|  |  |   - discovered_at TEXT NOT NULL DEFAULT now
 | 
						
						
						
							|  |  |   - updated_at TEXT NOT NULL DEFAULT now
 | 
						
						
						
							|  |  |   - discovered_by TEXT NULL
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Archivos a tocar
 | 
						
						
						
							|  |  | - src/db/migrations/index.ts: añadir una nueva migración (v9) para crear allowed_groups e índices.
 | 
						
						
						
							|  |  | - src/services/allowed-groups.ts (nuevo): implementación del servicio con caché y métodos arriba.
 | 
						
						
						
							|  |  | - src/services/metrics.ts: gauges allowed_groups_total{status} (opcional en esta etapa).
 | 
						
						
						
							|  |  | - tests/unit/services/allowed-groups.test.ts (nuevo).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 2 — Descubrimiento seguro de grupos (registrar, no operar)
 | 
						
						
						
							|  |  | Objetivos
 | 
						
						
						
							|  |  | - Al recibir tráfico de un group_id desconocido:
 | 
						
						
						
							|  |  |   - Insertar/actualizar en allowed_groups con status=pending y label (si disponible).
 | 
						
						
						
							|  |  |   - No ejecutar lógica de negocio (comandos, sync, recordatorios).
 | 
						
						
						
							|  |  | - Métricas y logs del descubrimiento.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Archivos a tocar
 | 
						
						
						
							|  |  | - src/server.ts:
 | 
						
						
						
							|  |  |   - handleMessageUpsert: antes de cualquier operación de grupo, consultar AllowedGroups.
 | 
						
						
						
							|  |  |   - Si no existe: upsertPending y retornar sin procesar comandos.
 | 
						
						
						
							|  |  |   - Añadir métricas: unknown_groups_discovered_total.
 | 
						
						
						
							|  |  | - src/services/contacts.ts:
 | 
						
						
						
							|  |  |   - Helper opcional para obtener/actualizar el nombre del grupo si el webhook lo trae (si no, dejar label=null).
 | 
						
						
						
							|  |  | - src/services/metrics.ts: contador unknown_groups_discovered_total.
 | 
						
						
						
							|  |  | - tests/unit/server/unknown-group-discovery.test.ts (nuevo).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 3 — Gating mínimo en superficies críticas
 | 
						
						
						
							|  |  | Objetivos
 | 
						
						
						
							|  |  | - Bloquear procesamiento de comandos si el group_id no está allowed.
 | 
						
						
						
							|  |  | - Asegurar que sincronización de grupos/miembros solo opere sobre grupos allowed.
 | 
						
						
						
							|  |  | - Responder con mensaje breve o permanecer en silencio para pending/blocked (configurable).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Archivos a tocar
 | 
						
						
						
							|  |  | - src/services/command.ts:
 | 
						
						
						
							|  |  |   - Al inicio de processTareaCommand cuando se esté en grupo: consultar AllowedGroups.isAllowed().
 | 
						
						
						
							|  |  |   - Si no allowed: devolver mensaje breve o [] según política (config).
 | 
						
						
						
							|  |  |   - Sustituir usos de GroupSyncService.isGroupActive por AllowedGroups.isAllowed para el gating de creación de tareas con group_id.
 | 
						
						
						
							|  |  | - src/services/group-sync.ts:
 | 
						
						
						
							|  |  |   - Filtrar y operar únicamente sobre grupos allowed al sincronizar (scheduler + reconcile).
 | 
						
						
						
							|  |  |   - Donde se cachean grupos activos, cruzar con allowed_groups o cambiar la fuente de verdad a AllowedGroups si procede.
 | 
						
						
						
							|  |  | - src/server.ts:
 | 
						
						
						
							|  |  |   - En handleMessageUpsert, antes de encolar/ejecutar comandos, exigir allowed en caso de que sea un grupo.
 | 
						
						
						
							|  |  | - src/services/metrics.ts:
 | 
						
						
						
							|  |  |   - commands_blocked_total
 | 
						
						
						
							|  |  |   - sync_skipped_group_total (si se decide contabilizar grupos saltados por no allowed)
 | 
						
						
						
							|  |  | - tests/unit/services/command.gating.test.ts (nuevo).
 | 
						
						
						
							|  |  | - tests/unit/services/group-sync.gating.test.ts (nuevo).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 4 — Flujo de aprobación administrativa y notificaciones
 | 
						
						
						
							|  |  | Objetivos
 | 
						
						
						
							|  |  | - Comandos admin:
 | 
						
						
						
							|  |  |   - /admin habilitar-aquí
 | 
						
						
						
							|  |  |   - /admin deshabilitar-aquí
 | 
						
						
						
							|  |  |   - /admin pendientes
 | 
						
						
						
							|  |  |   - /admin allow-group <group_id>
 | 
						
						
						
							|  |  |   - /admin block-group <group_id>
 | 
						
						
						
							|  |  | - Validación de permisos con ADMIN_USERS (IDs normalizados).
 | 
						
						
						
							|  |  | - Notificación automática a ADMIN_USERS al descubrir un grupo pending (con nombre si se conoce).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Archivos a tocar
 | 
						
						
						
							|  |  | - src/server.ts:
 | 
						
						
						
							|  |  |   - Router para comandos /admin → nuevo servicio AdminService.
 | 
						
						
						
							|  |  |   - Validación de ADMIN_USERS en validateEnv (no obligatorio pero recomendable).
 | 
						
						
						
							|  |  | - src/services/admin.ts (nuevo):
 | 
						
						
						
							|  |  |   - Implementa los subcomandos y policy de permisos.
 | 
						
						
						
							|  |  | - src/services/allowed-groups.ts:
 | 
						
						
						
							|  |  |   - Exponer setStatus, listByStatus, maybe get(groupId).
 | 
						
						
						
							|  |  | - src/services/response-queue.ts o src/services/webhook-manager.ts:
 | 
						
						
						
							|  |  |   - Utilizar ResponseQueue para notificar a ADMIN_USERS por DM cuando se descubra un grupo pending.
 | 
						
						
						
							|  |  | - tests/unit/services/command.admin-approval.test.ts (nuevo).
 | 
						
						
						
							|  |  | - tests/unit/services/admin.test.ts (nuevo).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 5 — Integración con servicios dependientes (recordatorios, tareas, rate limit)
 | 
						
						
						
							|  |  | Objetivos
 | 
						
						
						
							|  |  | - Recordatorios: si incluyen contexto de grupo, operar solo en grupos allowed; si no, DM sin dependencia del gating de grupo.
 | 
						
						
						
							|  |  | - Tareas: validar group_id permitido al crear desde un grupo (ya resuelto en Etapa 3).
 | 
						
						
						
							|  |  | - Rate limit (opcional): aislar por grupo si se desea (clave compuesta groupId+userId).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Archivos a tocar
 | 
						
						
						
							|  |  | - src/services/reminders.ts:
 | 
						
						
						
							|  |  |   - Al componer secciones por grupo (y “sin responsable”), filtrar por AllowedGroups.isAllowed(gid) si aplica.
 | 
						
						
						
							|  |  | - src/tasks/service.ts:
 | 
						
						
						
							|  |  |   - Mantener la lógica de setear group_id=null si no existe/permitido, delegando la decisión al llamador (CommandService).
 | 
						
						
						
							|  |  | - src/services/rate-limit.ts (opcional):
 | 
						
						
						
							|  |  |   - Añadir variantes de clave por grupo (ej. `${userId}:${groupId || 'dm'}`) si se activa por env.
 | 
						
						
						
							|  |  | - tests/unit/services/reminders.gating.test.ts (nuevo).
 | 
						
						
						
							|  |  | - tests/unit/tasks/service.gating.test.ts (nuevo).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 6 — Observabilidad y operaciones
 | 
						
						
						
							|  |  | Objetivos
 | 
						
						
						
							|  |  | - Métricas agregadas y documentación operativa.
 | 
						
						
						
							|  |  | - Logs claros en cambios de estado y descubrimientos.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Archivos a tocar
 | 
						
						
						
							|  |  | - src/services/metrics.ts:
 | 
						
						
						
							|  |  |   - allowed_groups_total{status}, unknown_groups_discovered_total, commands_blocked_total, admin_actions_total{action}.
 | 
						
						
						
							|  |  | - src/server.ts:
 | 
						
						
						
							|  |  |   - Confirmar exposición de métricas en /metrics.
 | 
						
						
						
							|  |  | - docs/operations.md:
 | 
						
						
						
							|  |  |   - Documentar ADMIN_USERS, ALLOWED_GROUPS, AUTO_APPROVE_PATTERNS, comportamiento de pending/blocked, y comandos admin.
 | 
						
						
						
							|  |  | - docs/architecture.md:
 | 
						
						
						
							|  |  |   - Añadir sección “Control de acceso por grupos (allowed_groups)”.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 7 — Hardening, pruebas de regresión y rollout
 | 
						
						
						
							|  |  | Objetivos
 | 
						
						
						
							|  |  | - Pruebas E2E con múltiples grupos en estados allowed/pending/blocked.
 | 
						
						
						
							|  |  | - Verificación de que no hay rutas sin gating (comandos, schedulers, envíos).
 | 
						
						
						
							|  |  | - Plan de despliegue gradual: 
 | 
						
						
						
							|  |  |   1) Activar registro (Etapas 1–2) sin gating duro.
 | 
						
						
						
							|  |  |   2) Activar gating (Etapa 3) con política de silencio o mensaje breve.
 | 
						
						
						
							|  |  |   3) Habilitar comandos admin (Etapa 4).
 | 
						
						
						
							|  |  |   4) Ajustar recordatorios/tareas (Etapa 5).
 | 
						
						
						
							|  |  |   5) Cerrar documentación y métricas (Etapa 6).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Archivos a tocar
 | 
						
						
						
							|  |  | - tests/** (nuevos casos integrados multi‑grupo).
 | 
						
						
						
							|  |  | - scripts de CI (si aplican) para asegurar la ejecución de nuevas suites.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Mapa rápido de archivos por etapa (resumen)
 | 
						
						
						
							|  |  | - Etapa 1:
 | 
						
						
						
							|  |  |   - src/db/migrations/index.ts (nueva migración v9)
 | 
						
						
						
							|  |  |   - src/services/allowed-groups.ts (nuevo)
 | 
						
						
						
							|  |  |   - src/services/metrics.ts (gauges)
 | 
						
						
						
							|  |  | - Etapa 2:
 | 
						
						
						
							|  |  |   - src/server.ts
 | 
						
						
						
							|  |  |   - src/services/contacts.ts (opcional)
 | 
						
						
						
							|  |  |   - src/services/metrics.ts (counter)
 | 
						
						
						
							|  |  | - Etapa 3:
 | 
						
						
						
							|  |  |   - src/services/command.ts
 | 
						
						
						
							|  |  |   - src/services/group-sync.ts
 | 
						
						
						
							|  |  |   - src/server.ts
 | 
						
						
						
							|  |  |   - src/services/metrics.ts
 | 
						
						
						
							|  |  | - Etapa 4:
 | 
						
						
						
							|  |  |   - src/server.ts
 | 
						
						
						
							|  |  |   - src/services/admin.ts (nuevo)
 | 
						
						
						
							|  |  |   - src/services/allowed-groups.ts (extensiones)
 | 
						
						
						
							|  |  |   - src/services/response-queue.ts (notificaciones a admins)
 | 
						
						
						
							|  |  | - Etapa 5:
 | 
						
						
						
							|  |  |   - src/services/reminders.ts
 | 
						
						
						
							|  |  |   - src/tasks/service.ts (validación indirecta ya cubierta por llamador)
 | 
						
						
						
							|  |  |   - src/services/rate-limit.ts (opcional)
 | 
						
						
						
							|  |  | - Etapa 6:
 | 
						
						
						
							|  |  |   - src/services/metrics.ts
 | 
						
						
						
							|  |  |   - docs/operations.md
 | 
						
						
						
							|  |  |   - docs/architecture.md
 | 
						
						
						
							|  |  | - Etapa 7:
 | 
						
						
						
							|  |  |   - tests/** integración/regresión
 | 
						
						
						
							|  |  |   - CI (si aplica)
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Variables de entorno previstas (añadidos)
 | 
						
						
						
							|  |  | - ADMIN_USERS: lista separada por comas de IDs de usuario administradores (normalizados).
 | 
						
						
						
							|  |  | - ALLOWED_GROUPS: lista separada por comas de group_ids iniciales a permitir.
 | 
						
						
						
							|  |  | - AUTO_APPROVE_PATTERNS (opcional): patrones para auto‑aprobar por nombre (con cautela).
 | 
						
						
						
							|  |  | - MAX_MEMBERS_SNAPSHOT_AGE_MS: ya usada; garantizar coherencia en gating si se cruza con membresía.
 | 
						
						
						
							|  |  | - METRICS_ENABLED, NODE_ENV, TZ: respetadas.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Riesgos y mitigaciones
 | 
						
						
						
							|  |  | - Fuga de operaciones en grupos no permitidos: tests específicos (Etapas 3 y 7).
 | 
						
						
						
							|  |  | - Identificación de nombres de grupo: si no se dispone de “subject” en eventos, almacenar solo group_id; completar label más tarde desde comando admin o tras un fetch.
 | 
						
						
						
							|  |  | - Sobrecarga de DB por descubrimiento: caché en AllowedGroups + operaciones idempotentes; escribir solo si no existe o cambió estado/label.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Criterios de “hecho” globales
 | 
						
						
						
							|  |  | - El bot solo opera en grupos con status=allowed.
 | 
						
						
						
							|  |  | - Flujo de aprobación funciona desde grupo (/admin habilitar-aquí) y por DM (/admin allow-group <id>).
 | 
						
						
						
							|  |  | - Métricas y logs permiten auditar descubrimientos y cambios de estado.
 | 
						
						
						
							|  |  | - Documentación de operación actualizada.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Notas de implementación
 | 
						
						
						
							|  |  | - Mantener compatibilidad hacia atrás: en creación de tareas, si el group_id no está allowed, persistir sin group_id (null).
 | 
						
						
						
							|  |  | - No bloquear DMs por diseño (gating aplica solo a grupos).
 | 
						
						
						
							|  |  | - Reutilizar ResponseQueue para todas las notificaciones (incluyendo admins).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Plan detallado etapa por etapa (con impacto en tests y archivos a tocar)
 | 
						
						
						
							|  |  | Convenciones transversales para no romper la suite:
 | 
						
						
						
							|  |  | - Nueva variable GROUP_GATING_MODE = 'off' | 'discover' | 'enforce'. Valor por defecto: 'off' (especialmente en tests). Solo se activará en tests específicos.
 | 
						
						
						
							|  |  | - Helper de tests tests/helpers/db.ts:
 | 
						
						
						
							|  |  |   - makeMemDb(), injectAllServices(db), seedAllowed(db, groupIds[]), resetServices().
 | 
						
						
						
							|  |  | - Opcional tests/setup.ts (o equivalente): fija GROUP_GATING_MODE='off' por defecto para toda la suite.
 | 
						
						
						
							|  |  | - AllowedGroups con dbInstance inyectable, caché con clearCache/resetForTests y métodos idempotentes.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 0 — Preparación y criterios (tests-first)
 | 
						
						
						
							|  |  | Objetivo
 | 
						
						
						
							|  |  | - Asegurar un “harness” de tests estable y predecible para DB y servicios estáticos.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Cambios de código
 | 
						
						
						
							|  |  | - Ninguno funcional. Solo infraestructura de tests (helpers y, si procede, setup global).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Archivos a tocar (código)
 | 
						
						
						
							|  |  | - tests/helpers/db.ts (nuevo)
 | 
						
						
						
							|  |  | - tests/setup.ts (opcional, si existe configuración global de tests)
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests nuevos a añadir
 | 
						
						
						
							|  |  | - tests/unit/db/migrations.smoke.test.ts: comprueba que initializeDatabase en :memory: no lanza y crea tablas base (sin allowed_groups aún).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests existentes a actualizar
 | 
						
						
						
							|  |  | - Ninguno obligatorio. Opcional: migrar suites que crean DB manualmente a usar tests/helpers/db.ts.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 1 — Esquema y servicio AllowedGroups (sin gating todavía)
 | 
						
						
						
							|  |  | Objetivo
 | 
						
						
						
							|  |  | - Crear tabla allowed_groups y servicio con caché. No bloquear nada aún.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Cambios de código
 | 
						
						
						
							|  |  | - src/db/migrations/index.ts: añadir migración v9_allowed_groups (CREATE TABLE IF NOT EXISTS ...).
 | 
						
						
						
							|  |  | - src/services/allowed-groups.ts (nuevo): métodos upsertPending, isAllowed, setStatus, listByStatus, seedFromEnv, clearCache/resetForTests.
 | 
						
						
						
							|  |  | - src/services/metrics.ts: gauges allowed_groups_total{status} (best-effort).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests nuevos a añadir
 | 
						
						
						
							|  |  | - tests/unit/services/allowed-groups.test.ts
 | 
						
						
						
							|  |  | - tests/unit/db/migrations.allowed-groups.test.ts
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests existentes a actualizar
 | 
						
						
						
							|  |  | - Ninguno. La migración se ejecuta en initializeDatabase de suites que ya lo llaman.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 2 — Descubrimiento seguro de grupos (registrar, no operar)
 | 
						
						
						
							|  |  | Objetivo
 | 
						
						
						
							|  |  | - Registrar grupos desconocidos como pending en modo 'discover', sin cambiar comportamiento por defecto de la suite.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Cambios de código
 | 
						
						
						
							|  |  | - src/server.ts:
 | 
						
						
						
							|  |  |   - handleMessageUpsert: si GROUP_GATING_MODE='discover' y es group_id desconocido → upsertPending y return temprano sin procesar comandos/sync.
 | 
						
						
						
							|  |  |   - Métrica unknown_groups_discovered_total (src/services/metrics.ts).
 | 
						
						
						
							|  |  | - src/services/contacts.ts (opcional): obtener label/subject si viene en el webhook.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests nuevos a añadir
 | 
						
						
						
							|  |  | - tests/unit/server/unknown-group-discovery.test.ts
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests existentes a actualizar
 | 
						
						
						
							|  |  | - tests/unit/server.test.ts: asegurar que:
 | 
						
						
						
							|  |  |   - Setea GROUP_GATING_MODE='off' en beforeEach, o
 | 
						
						
						
							|  |  |   - Si prueba mensajes de grupo, usar seedAllowed(db, ['<group_id>']).
 | 
						
						
						
							|  |  | - Resto de suites: sin cambios esperados.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 3 — Gating mínimo en superficies críticas
 | 
						
						
						
							|  |  | Objetivo
 | 
						
						
						
							|  |  | - Bloquear comandos y sync en grupos no allowed cuando GROUP_GATING_MODE='enforce'.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Cambios de código
 | 
						
						
						
							|  |  | - src/services/command.ts:
 | 
						
						
						
							|  |  |   - Al inicio, si message viene de grupo y GROUP_GATING_MODE='enforce', llamar AllowedGroups.isAllowed(groupId). Si no allowed: política por defecto “silencio” o respuesta breve configurable.
 | 
						
						
						
							|  |  | - src/services/group-sync.ts:
 | 
						
						
						
							|  |  |   - Filtrar operaciones a solo grupos AllowedGroups.isAllowed.
 | 
						
						
						
							|  |  | - src/server.ts:
 | 
						
						
						
							|  |  |   - Antes de encolar/ejecutar comandos, si es grupo y 'enforce', exigir allowed.
 | 
						
						
						
							|  |  | - src/services/metrics.ts:
 | 
						
						
						
							|  |  |   - commands_blocked_total
 | 
						
						
						
							|  |  |   - sync_skipped_group_total (opcional)
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests nuevos a añadir
 | 
						
						
						
							|  |  | - tests/unit/services/command.gating.test.ts
 | 
						
						
						
							|  |  | - tests/unit/services/group-sync.gating.test.ts
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests existentes a actualizar
 | 
						
						
						
							|  |  | - tests/unit/services/command.claim-unassign.test.ts: sembrar grupo allowed en beforeAll/beforeEach o fijar GROUP_GATING_MODE='off'.
 | 
						
						
						
							|  |  | - tests/unit/services/command.reminders-config.test.ts: idem si el test ejecuta comandos en contexto de grupo.
 | 
						
						
						
							|  |  | - tests/unit/services/command.date-parsing.test.ts: normalmente DM; no tocar salvo que simule grupo.
 | 
						
						
						
							|  |  | - tests/unit/services/group-sync.members.test.ts: sembrar grupo allowed para '123@g.us'.
 | 
						
						
						
							|  |  | - tests/unit/services/group-sync.scheduler.test.ts: sembrar grupos allowed en el scheduler o setear mode='off'.
 | 
						
						
						
							|  |  | - tests/unit/tasks/claim-unassign.test.ts: si hay contexto de grupo, seedAllowed; si es DM, sin cambios.
 | 
						
						
						
							|  |  | - tests/unit/services/cleanup-inactive.test.ts, tests/unit/services/metrics-health.test.ts, tests/unit/services/response-queue*.test.ts, tests/unit/services/reminders.test.ts: no deberían requerir cambios; si alguno falla por simulación de grupo, aplicar seedAllowed o mode='off'.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 4 — Flujo de aprobación administrativa y notificaciones
 | 
						
						
						
							|  |  | Objetivo
 | 
						
						
						
							|  |  | - Permitir a ADMIN_USERS aprobar/bloquear grupos y consultar pendientes; notificar a admins al descubrir pending.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Cambios de código
 | 
						
						
						
							|  |  | - src/services/admin.ts (nuevo): /admin habilitar-aquí, deshabilitar-aquí, pendientes, allow-group <id>, block-group <id>.
 | 
						
						
						
							|  |  | - src/server.ts: router para /admin y validación de ADMIN_USERS; usar ResponseQueue para notificaciones.
 | 
						
						
						
							|  |  | - src/services/allowed-groups.ts: asegurar setStatus, listByStatus, get(groupId).
 | 
						
						
						
							|  |  | - src/services/response-queue.ts (o webhook-manager): enviar DM a ADMIN_USERS en descubrimiento pending (best-effort y detrás de flag para no romper tests existentes).
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests nuevos a añadir
 | 
						
						
						
							|  |  | - tests/unit/services/admin.test.ts
 | 
						
						
						
							|  |  | - tests/unit/services/command.admin-approval.test.ts
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests existentes a actualizar
 | 
						
						
						
							|  |  | - tests/unit/server.test.ts: si parsea /admin, agregar casos explícitos o mantener aislado con mode='off' para suites no relacionadas.
 | 
						
						
						
							|  |  | - No tocar otras suites.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 5 — Integración con recordatorios y tareas
 | 
						
						
						
							|  |  | Objetivo
 | 
						
						
						
							|  |  | - Recordatorios y operaciones por grupo respetan AllowedGroups cuando hay contexto de grupo. DMs no se ven afectados.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Cambios de código
 | 
						
						
						
							|  |  | - src/services/reminders.ts: filtrar por AllowedGroups.isAllowed(gid) cuando el recordatorio/consulta use contexto de grupo.
 | 
						
						
						
							|  |  | - src/tasks/service.ts: sin cambios funcionales (seguir permitiendo group_id=null).
 | 
						
						
						
							|  |  | - src/services/rate-limit.ts (opcional): clave compuesta por grupo.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests nuevos a añadir
 | 
						
						
						
							|  |  | - tests/unit/services/reminders.gating.test.ts
 | 
						
						
						
							|  |  | - tests/unit/tasks/service.gating.test.ts
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests existentes a actualizar
 | 
						
						
						
							|  |  | - tests/unit/services/reminders.test.ts: si usa contexto de grupo, seedAllowed o mode='off' para mantener expectativas.
 | 
						
						
						
							|  |  | - Resto: sin cambios.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 6 — Observabilidad y operaciones
 | 
						
						
						
							|  |  | Objetivo
 | 
						
						
						
							|  |  | - Métricas agregadas y documentación.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Cambios de código
 | 
						
						
						
							|  |  | - src/services/metrics.ts: allowed_groups_total{status}, unknown_groups_discovered_total, commands_blocked_total, admin_actions_total{action}.
 | 
						
						
						
							|  |  | - docs/operations.md: documentar variables y comportamiento.
 | 
						
						
						
							|  |  | - docs/architecture.md: sección de control de acceso por grupos.
 | 
						
						
						
							|  |  | - Confirmar /metrics en src/server.ts.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests nuevos a añadir
 | 
						
						
						
							|  |  | - Opcional: tests/unit/services/metrics-health.test.ts puede ampliar cobertura para nuevos contadores (no estricta; tolerar ausencia si METRICS_ENABLED='false').
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests existentes a actualizar
 | 
						
						
						
							|  |  | - tests/unit/services/metrics-health.test.ts: si asume conjunto exacto de métricas, flexibilizar aserciones o aislar nuevas métricas tras METRICS_ENABLED.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Etapa 7 — Hardening, regresión y rollout
 | 
						
						
						
							|  |  | Objetivo
 | 
						
						
						
							|  |  | - Validar que no hay rutas sin gating y que la activación progresiva no rompe nada.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Cambios de código
 | 
						
						
						
							|  |  | - Ninguno obligatorio más allá de ajustes menores.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests nuevos a añadir
 | 
						
						
						
							|  |  | - tests/integration/multi-groups.e2e.test.ts (si procede).
 | 
						
						
						
							|  |  | - Casos combinados con varios estados: allowed/pending/blocked + discover/enforce.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Tests existentes a actualizar
 | 
						
						
						
							|  |  | - Ninguno; mantener GROUP_GATING_MODE='off' por defecto y activar explícitamente en tests que cubren gating.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Checklist por etapa para mantener la suite en verde
 | 
						
						
						
							|  |  | - Antes de tocar código de gating: añadir tests nuevos primero (TDD light).
 | 
						
						
						
							|  |  | - Default en tests: GROUP_GATING_MODE='off'.
 | 
						
						
						
							|  |  | - Donde haya contexto de grupo en tests existentes: seedAllowed(memdb, ['<gid>']) en el setup del archivo.
 | 
						
						
						
							|  |  | - Limpiar cachés entre tests: AllowedGroups.resetForTests() en afterEach/afterAll cuando el servicio se use.
 | 
						
						
						
							|  |  | - initializeDatabase(memdb) siempre presente en suites con DB en memoria para aplicar migraciones (incluida v9).
 |