# Task WhatsApp Chatbot

Un chatbot de WhatsApp para gestionar tareas en grupos, integrado con Evolution API. Diseño “solo DM”: el bot no publica en grupos; todas las respuestas se envían por mensaje directo al autor (opcionalmente puede enviarse un breve resumen al grupo al crear, configurable).

## Cómo se usa (mini guía para usuarios)
- Principios
  - Comandos con prefijo “/t” o “/tarea”.
  - En grupo: el bot responde por DM al autor (no escribe en el grupo).
  - Fechas en formato dd/MM en mensajes; puedes escribir “hoy” o “mañana” al crear; la zona horaria se controla con la variable de entorno TZ (por defecto Europe/Madrid).
- Comandos y alias principales
  - Crear: “/t nueva Acta reunión mañana @600123456”
  - Ver pendientes del grupo: “/t ver grupo”
  - Ver tus pendientes: “/t ver mis”
  - Completar: “/t x 26” (alias: hecho, completar, done)
  - Tomar: “/t tomar 26”
  - Soltar: “/t soltar 26”
  - Configurar recordatorios: “/t configurar daily|weekly|off”
  - Ayuda: “/t” o “/t ayuda”
- Notas y reglas
  - Si creas en grupo y no mencionas a nadie: queda “sin responsable”.
  - Si creas por DM y no mencionas a nadie: se asigna al creador.
  - En DM, WhatsApp no muestra chips de mención de terceros; se incluye @número como texto para acción rápida.
- Guía completa con alias, reglas y ejemplos: docs/USER_GUIDE.md

## Características
- Crear, listar, completar, tomar/soltar tareas; ayuda por DM.
- Recordatorios por DM (daily/weekly) por usuario; evita duplicados y respeta TZ.
- Cola de respuestas persistente con reintentos (backoff exponencial + jitter) y recuperación tras reinicios.
- Nombres amigables vía caché de contactos (sin llamadas de red en tests).
- Sincronización de miembros de grupos (snapshot periódica + webhooks incrementales; tolerante a fallos).
- Mensajes compactos con emojis y cursiva; fechas dd/MM; vencidas con ⚠️.
- Observabilidad mínima: /metrics (Prometheus por defecto, JSON opcional) y /health detallado.

## Requisitos
- Evolution API accesible (recomendado: misma red interna Docker).
- Bun para desarrollo local; Docker/CapRover para despliegue.
- SQLite embebido con persistencia en data/.

## Variables de entorno
- Requeridas
  - EVOLUTION_API_URL: URL de Evolution API (p.ej., http://evolution-api:3000).
  - EVOLUTION_API_KEY: API key de Evolution.
  - EVOLUTION_API_INSTANCE: nombre de la instancia en Evolution.
  - WHATSAPP_COMMUNITY_ID: comunidad principal desde la que sincronizar grupos (jid @g.us).
  - CHATBOT_PHONE_NUMBER: número normalizado del bot (evita auto-respuestas).
  - WEBHOOK_URL: URL (interna) donde Evolution enviará webhooks.
  - PORT: puerto del servidor webhook (p.ej., 3007).
- Opcionales — comportamiento
  - TZ: zona horaria para “hoy/mañana” y render de fechas; por defecto Europe/Madrid.
  - NOTIFY_GROUP_ON_CREATE: si “true”, envía resumen al grupo al crear (por defecto false).
  - GROUP_SYNC_INTERVAL_MS: intervalo de sync de grupos; por defecto 24h (mín 10s en desarrollo).
  - GROUP_MEMBERS_SYNC_INTERVAL_MS: intervalo de sync de miembros; por defecto 6h (mín 10s en desarrollo).
  - MAX_MEMBERS_SNAPSHOT_AGE_MS: edad máxima (ms) para considerar "fresca" la snapshot de miembros; por defecto 24h.
  - GROUP_MEMBERS_ENFORCE: si "true", aplica validación estricta de membresía cuando la snapshot es fresca; por defecto false.
  - REMINDERS_INCLUDE_UNASSIGNED_FROM_MEMBERSHIP: si "true", añade sección "sin responsable" en recordatorios solo de tus grupos con membresía activa; por defecto false.
  - RATE_LIMIT_PER_MIN: límite por usuario (tokens/min); por defecto 15.
  - RATE_LIMIT_BURST: capacidad del bucket; por defecto = RATE_LIMIT_PER_MIN.
- Opcionales — cola de respuestas
  - RQ_MAX_ATTEMPTS: reintentos máximos; por defecto 6.
  - RQ_BASE_BACKOFF_MS: backoff base en ms; por defecto 5000.
  - RQ_MAX_BACKOFF_MS: backoff máximo en ms; por defecto 3600000.
- Opcionales — migraciones
  - MIGRATOR_CHECKSUM_STRICT: si "false" desactiva validación estricta de checksum de migraciones; por defecto "true".
  - MIGRATIONS_LOG_PATH: ruta del fichero de log de migraciones; por defecto data/migrations.log.
- Opcionales — métricas y mantenimiento
  - METRICS_ENABLED: "true"|"false" para habilitar /metrics; por defecto true (desactivado en test).
  - METRICS_FORMAT: "prom"|"json"; por defecto "prom".
  - GROUP_MEMBERS_INACTIVE_RETENTION_DAYS: días para purgar miembros inactivos; 180 por defecto; 0 desactiva.
  - FORCE_SCHEDULERS: "true" para forzar arranque de jobs en NODE_ENV=test.
- Entorno
  - NODE_ENV: production | development | test.

Consulta .env.example para un listado comentado con valores de ejemplo.

## Puesta en marcha (local)
- bun install
- Copia .env.example a .env y ajústalo.
- bun run dev (arranca servidor con recarga).
- bun test (ejecuta pruebas con SQLite en memoria).

## Despliegue con Docker/CapRover
- Crea una app y configura:
  - Variables de entorno (ver arriba).
  - Health check: GET /health.
  - Volumen persistente: mapea /app/data a un volumen (persistencia de SQLite).
  - Red interna con Evolution API (ideal: no exponer públicamente el webhook).
- El worker de la cola arranca con el servidor (en NODE_ENV=test se desactiva).
- Plan operativo mínimo (CI/CD, healthcheck y backups): ver docs/CI-CD-PLAN.md (decisiones pendientes marcadas).

## Seguridad y buenas prácticas
- Mantén WEBHOOK_URL accesible desde Evolution API preferiblemente en red interna; si se expone, restringe IPs o usa reverse proxy/firewall.
- Gestiona secretos (API keys) como variables en el orquestador.
- Configura backups periódicos del fichero data/tasks.db (las migraciones hacen VACUUM INTO, pero no sustituyen un backup programado).

## Limitaciones conocidas
- Sin orden garantizado por destinatario en la cola.
- /metrics básico sin histogramas ni etiquetas; mejoras futuras.
- Permisos/roles y validación estricta de pertenencia a grupos no implementados.

## Roadmap
- Próximos pasos y estado detallado: ver STATUS.md.

## Testing
- Ejecuta la suite con “bun test”. Llama a Evolution API solo fuera de test.

## Contribución
- PRs bienvenidas. Añade pruebas, ejecuta “bun test” y describe los cambios.

6) Permisos y pertenencia a grupos
- Objetivo: control de quién puede qué, y pertenencia válida.
- Implica: roles y/o verificación de pertenencia; posibles migraciones y sincronización de miembros.

7) Historial de tareas (auditoría ligera)
- Objetivo: trazabilidad de cambios.
- Implica: tabla task_events; eventos en crear/asignar/tomar/soltar/completar; consulta “historial”.

8) Rate limiting (operación segura) — completado
- Objetivo: proteger ante abuso o loops.
- Implementado: token bucket por usuario con límites configurables (RATE_LIMIT_PER_MIN, RATE_LIMIT_BURST) y aviso con cooldown.

9) Sincronización de miembros (opcional)
- Objetivo: conocer miembros activos por grupo para features avanzadas.
- Implica: endpoints Evolution API para miembros; cache/migraciones.

10) Métricas y observabilidad
- Objetivo: visibilidad con bajo coste.
- Implementado: /metrics (Prometheus/JSON) con counters/gauges y /health detallado; pendiente: histogramas/latencias y logging estructurado avanzado.

## 🔑 Key Considerations & Caveats
*   **WhatsApp ID Normalization:** Crucial for consistently identifying users and groups. Needs careful implementation to handle edge cases. (Utility function exists).
*   **Response Latency:** Sending responses requires an API call back to Evolution. Ensure the `ResponseQueue` processing is efficient.
*   **Cola de respuestas:** Persistente en DB; con reintentos (backoff exponencial + jitter), recuperación tras reinicios y limpieza/retención configurables.
*   **Group Sync:** The current full sync might be slow or rate-limited with many groups. Delta updates are recommended long-term.
*   **Error Handling:** Failures in command processing or response sending should be logged clearly and potentially reported back to the user. Database operations should use transactions for atomicity (especially task+assignment creation).
*   **State Management:** The current design is stateless. Complex interactions might require state persistence later.
*   **Security:** Ensure group/user validation logic is robust once integrated.

## 🧪 Testing
### Running Tests
```bash
bun test
```

### Test Coverage
- Database initialization and basic operations (`db.test.ts`).
- Webhook validation (basic) (`webhook-manager.test.ts`).
- Command parsing (basic structure) (`command.test.ts`).
- Environment checks (`server.test.ts`).
- Basic error handling (`server.test.ts`).
- WhatsApp ID normalization (`whatsapp.test.ts`).
- Group sync operations (`group-sync.test.ts`).
- Webhook handlers de membresías (alta/baja/cambio de rol) (`group-sync.*.test.ts`).
- **Needed:** Tests for `ensureUserExists` integration, `isGroupActive` integration, `CommandService` logic, `ResponseQueue` processing (mocking API), `TaskService` operations.
- All 170 unit tests passing. Added unit tests for CommandService (date parsing "hoy/mañana", DM help, dd/MM formatting, default assignment rules) y para RemindersService (daily/weekly, duplicados por día, hora/TZ, “… y X más”) y configuración de recordatorios.

## 🧑‍💻 Contributing
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/implement-user-validation`)
3. Add/update tests for new functionality
4. Ensure tests pass (`bun test`)
5. Submit a pull request

## 📚 Documentation
For detailed API documentation and architecture decisions, see the [docs/](docs/) directory (if created).

---

## 📐 Diseño UX acordado (MVP y siguientes iteraciones)

Este apartado documenta las decisiones de UX aprobadas para el MVP y su evolución inmediata. Objetivo: mínima fricción, cero ruido en grupos y mensajes compactos.

### Principios
- Silencio en grupos: el bot NO publica mensajes en grupos. Cuando alguien usa un comando en un grupo, el bot responde solo por DM al autor, sin dejar mensaje en el grupo.
- Homogeneidad: mismos comandos y comportamiento tanto en la comunidad “Casa” como en la del AMPA.
- Mensajes compactos: máximo 2–3 líneas, usando emojis y formato WhatsApp (negritas, monoespacio) para legibilidad.
- Aprendizaje progresivo: alias cortos y ayuda accesible por DM.

### Comando base y alias
- Prefijo admitido: “/t” y “/tarea”.
- Subcomandos y sinónimos (aceptar cualquiera, mapear a una acción canónica):
  - Crear: n, nueva, crear, +
  - Ver: ver, mostrar, listar, ls
  - Completar: x, hecho, completar, done
  - Tomar: tomar, claim
  - Soltar: soltar, unassign
  - Ayuda: ayuda, help, ?
  - Configurar: configurar, config

### Gramática de “crear tarea”
- Texto libre: descripción.
- Fecha: soportar tokens “hoy” y “mañana” (MVP). Futuro: +2d, +1w, lun/mar/…
- Menciones: “@…” y menciones reales del cliente.
- Asignación por defecto:
  - En grupos: si no hay menciones → tarea queda “sin responsable”.
  - En DM: si no hay menciones → asignada al creador.
- Comandos de gestión de asignación:
  - /t tomar <id> → el usuario se asigna la tarea.
  - /t soltar <id> → elimina su asignación, devolviendo la tarea a “sin responsable” si no quedan asignados.

### Listados
- /t ver grupo → devuelve por DM las pendientes del grupo desde el que se invoca (incluye sección “sin responsable”).
- /t ver mis → devuelve por DM las pendientes del usuario agregadas de todos sus grupos.
- Listas extensas: mostrar top N (p. ej., 10) y resumen “y X más…”.

### Completar
- /t x <id> (alias: /t hecho <id>, /t completar <id>)
- Registro de quién completó. Por ahora no se restringe a asignados (permite fluidez); política configurable en el futuro.
- Confirmación solo por DM.

### Ayuda y onboarding
- “/t” sin parámetros o “ayuda” → siempre por DM, con guía corta y 2–3 ejemplos.
- En grupos: no se escribe nada en el grupo; únicamente el DM al autor.

### Mensajes: plantillas compactas
- Confirmación al crear (DM al creador):
  - 📝 26 _Acta de la reunión_
  - 📅 12/09
  - 🚫👤 sin responsable (Junta AMPA) — o — 👤 @Juan
- DM a asignados:
  - 📬 Tarea 26 — 📅 12/09
  - _Acta de la reunión_
  - Grupo: Junta AMPA
  - Completar: /t x 26
- Listado (enviado por DM):
  - Junta AMPA
    - 26) _Acta…_ — 📅 12/09 — 👤 @Juan
    - 27) _Carteles fiesta_ — 📅 10/09 — 🚫👤 sin responsable
    - … y 3 más
- Completar (feedback por DM):
  - ✅ 26 completada — _Acta…_
  - Gracias, Juan.

### Preferencias (MVP)
- Única preferencia: frecuencia de recordatorios por DM: daily | off.
- MVP sin web: el usuario escribe “configurar” por DM y el bot le ofrece elegir “diario” u “off”.
- Por defecto: off (evitar spam). Futuro: hora y zona horaria configurables; magic link a web de configuración.

### Recordatorios
- Resumen diario por DM (si el usuario eligió “diario”):
  - ⏰ Recordatorio diario — hoy 12/09
    - 26) _Acta…_ — 📅 12/09 — Junta AMPA
    - 31) _Pagar comedor_ — hoy — Casa
    - 33) _…_ — 📅 15/09 — Casa
  - Completar: /t x <id>
- Un solo DM con secciones por comunidad para evitar múltiples mensajes.

### No objetivos del MVP
- No asignar por defecto a “todo el grupo” (evita DMs masivos y responsabilidad difusa).
- No canal “Tareas” compartido por defecto (riesgo de ruido). Se considerará en el futuro solo si hay demanda y opt‑in.

### Plan de implementación (iteraciones)
- Iteración A — UX base y silencios
  - Alias de comandos y sinónimos en CommandService.
  - Respuestas de todos los comandos únicamente por DM (incluido cuando se invocan en grupos).
  - Mensajes compactos con plantillas.
  - Soporte de “hoy/mañana”.
  - Default sin dueño en grupos; asignar al creador en DMs.
  - Nuevos comandos: tomar y soltar.
  - Ayuda por DM.
- Iteración B — Listados y completar
  - /t ver grupo, /t ver mis.
  - /t x <id> con registro de quién completa.
  - Tests para alias, hoy/mañana, ver y x.
- Iteración C — Recordatorios
  - Preferencia reminder_freq (daily|off) por usuario via “configurar” por DM.
  - Job diario que envía el resumen (solo “tus tareas” en MVP).
- Iteración D — (Opcional) Miembros de grupo
  - Sincronizar miembros si se necesita incluir “sin responsable” por grupo en recordatorios.

### Cambios técnicos asociados (resumen)
- src/services/command.ts
  - Mapeo de sinónimos a acciones canónicas.
  - Parser de “hoy/mañana”.
  - Subcomandos: ver grupo|mis, x, tomar, soltar.
  - Render de mensajes compactos.
- src/server.ts
  - Detección de contexto grupo vs DM; nunca responder en grupo (solo DM al autor).
- src/tasks/service.ts
  - Permitir tareas sin asignaciones.
  - Métodos: claimTask(user_id), unassignTask(user_id), completeTask(id, completed_by).
- src/services/response-queue.ts
  - Envío de DMs para ayuda, confirmaciones, listados y recordatorios.
- (Futuro) Preferencias
  - Tabla user_preferences(user_id PK, reminder_freq TEXT, updated_at).
  - “configurar” por DM en MVP; más adelante, web con magic link (user_tokens).

### Testing sugerido
- Alias de comandos y “/t” sin parámetros → DM de ayuda.
- Crear en grupo sin menciones → sin responsable; no hay mensaje en el grupo; DM al autor.
- Crear en DM sin menciones → asignada al creador.
- “hoy/mañana” en fechas.
- ver grupo y ver mis → DM con paginación/resumen.
- completar, tomar y soltar → reglas y feedback por DM.
