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.

294 lines
15 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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