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