docs: actualizar plan de onboarding con paquetes de 2 DMs y recordatorio

Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>
main
brobert 4 days ago
parent 7871d39e0a
commit 7bc7000c8c

@ -20,7 +20,7 @@ Estado actual relevante (resumen)
Principios
- Nunca escribimos mensajes en grupos (solo reacciones).
- Onboarding solo se dispara cuando se crea una tarea en un grupo (evento con “excusa” clara).
- Onboarding por usuario: máx. 2 DMs, separados al menos 14 días; si no interactúa, no insistimos más.
- Onboarding por usuario: máx. 2 paquetes (cada paquete = 2 DMs consecutivos con breve retraso), separados al menos 14 días y solo si no hubo interacción desde el primer paquete.
- Alias de comandos más cortos y claros para fomentar uso por DM.
---
@ -77,26 +77,29 @@ Impacto en tests
---
## Fase 2 — Infra de Onboarding por DM (sin migraciones)
## Fase 2 — Infra de Onboarding por DM en paquetes (2 DMs, migración mínima para interacción)
Objetivos
- Implementar un onboarding DM que se dispare al crear una tarea en un grupo, con 2 variantes:
- Mensaje 1 (initial): CTA “/t tomar {CÓDIGO}” + “/t info”.
- Mensaje 2 (reminder): minichuleta (“/t mias”, “/t todas”, “/t configurar …”, “/t web”).
- Cumplir reglas: máx. 2 DMs por usuario, separados ≥ 14 días; cap por evento; sin mensajes en grupos.
- Enviar un paquete de 2 DMs (Mensaje 1 + Mensaje 2) por usuario cuando se crea una tarea en un grupo.
- Mensaje 1: CTA “/t tomar {CÓDIGO}” + “/t info”.
- Mensaje 2: minichuleta (“/t mias”, “/t todas”, “/t configurar …”, “/t web”), 38 s después del Mensaje 1.
- Repetir el mismo paquete una única vez más si pasan ≥ 14 días sin interacción del usuario (si hubo interacción, no se envía el segundo paquete).
- Cap por evento; sin mensajes en grupos.
Archivos a modificar
- src/services/group-sync.ts (añadir listActiveMemberIds(groupId): string[])
- src/services/response-queue.ts (añadir helpers para onboarding: enqueueOnboarding y getOnboardingStats; reutilizar metadata JSON con kind='onboarding')
- src/services/command.ts (desencadenar onboarding tras crear tarea en grupo, respetando gating y caps)
- src/services/response-queue.ts (añadir helpers para onboarding con metadata { kind='onboarding', variant, part, bundle_id } y soporte de retraso para el segundo DM del paquete; getOnboardingStats)
- src/services/command.ts (desencadenar el paquete tras crear tarea en grupo, respetando gating y caps; actualizar users.last_command_at al recibir cualquier comando)
- src/services/allowed-groups.ts (usado para gating en modo enforce)
- src/db/migrations/* (añadir columna users.last_command_at) y wiring en src/db/migrator.ts
- src/services/identity.ts y src/services/contacts.ts (solo consumo; no se cambian)
Overview de cambios
- GroupSyncService: nuevo helper para obtener IDs de miembros activos del grupo (solo dígitos, grupos activos, no comunidad/archivados).
- ResponseQueue:
- enqueueOnboarding(recipient, message, metadata) con metadata canónica: { kind: 'onboarding', variant: 'initial'|'reminder', group_id, task_id, display_code }.
- getOnboardingStats(recipient): { total, lastSentAt } consultando response_queue por metadata.kind='onboarding'.
- enqueueOnboarding(recipient, message, metadata) con metadata canónica: { kind: 'onboarding', variant: 'initial'|'reminder', part: 1|2, bundle_id, group_id, task_id, display_code }.
- getOnboardingStats(recipient): { total, lastSentAt, lastVariant?: 'initial'|'reminder' } consultando response_queue por metadata.kind='onboarding'.
- Soportar programar el segundo DM del paquete con next_attempt_at = now + ONBOARDING_BUNDLE_DELAY_MS (por defecto 40008000ms).
- CommandService (en /t nueva):
- Tras crear la tarea en grupo, construir candidatos:
- miembros activos del grupo (GroupSync.listActiveMemberIds),
@ -105,31 +108,33 @@ Overview de cambios
- si GROUP_GATING_MODE=enforce y el grupo no está allowed → no enviar.
- Cap por evento (ONBOARDING_EVENT_CAP, p. ej. 30).
- Para cada destinatario:
- stats.total=0 → enviar Mensaje 1.
- stats.total=1 y lastSentAt <= now-14 días → enviar Mensaje 2.
- Si no hay paquetes previos → encolar paquete 'initial' con 2 DMs (part=1 ahora; part=2 con retraso).
- Si hay paquete 'initial' y han pasado ≥14 días SIN interacción (users.last_command_at ≤ primer paquete) → encolar paquete 'reminder' (2 DMs).
- En cualquier otro caso → no enviar.
- Envío inmediato (next_attempt_at = now). Ventanas horarias opcionales (ver Fase 4).
- Envío del primer DM del paquete inmediato (next_attempt_at = now) y el segundo con pequeño retraso. Ventanas horarias opcionales (ver Fase 4).
Copys de onboarding (exactos)
- Mensaje 1:
- Mensaje 1 (en ambos disparos):
- “Hola, soy el bot de tareas. En {Grupo} acaban de crear una tarea: #{CÓDIGO} {descripción corta}
Encárgate: envíame /t tomar {CÓDIGO} por privado· Más info: /t info (también por privado)
Nota: Solo respondo por privado. (Este mensaje solo lo envío una vez)
- Mensaje 2 (minichuleta, solo si no interactuó aún):
Encárgate: /t tomar {CÓDIGO} · Más info: /t info
Nota: nunca respondo en grupos; solo por privado.
- Mensaje 2 (minichuleta; se envía tras 38 s, en ambos disparos):
- “Guía rápida (este es un mensaje único):
· Tus tareas: /t mias · Todas: /t todas
· Recordatorios: /t configurar diario | lv | semanal
· Recordatorios: /t configurar diario | lv | semanal | off
· Web: /t web”
Impacto en tests
- Tests unitarios para:
- Construcción de destinatarios (exclusiones, cap).
- Idempotencia por usuario (0 → initial; 1 y >14d → reminder; resto skip).
- Paquetes: por disparo se encolan 2 DMs/usuario (part=1 y part=2 con retraso).
- Recordatorio a los ≥14 días solo si no hubo interacción desde el primer paquete; si la hubo, skip.
- Gating enforce (grupo no allowed → no enviar).
- Metadata de enqueue (kind='onboarding', variant correcto).
- Metadata de enqueue (kind='onboarding', variant initial|reminder, part 1|2, bundle_id).
Notas sobre migraciones
- No se requiere migración: se usa response_queue como fuente de verdad para conteo/fecha de onboarding por usuario (consultando metadata.kind='onboarding').
- Migración mínima recomendada: añadir users.last_command_at para registrar la última interacción del usuario y así decidir si enviar el segundo paquete tras ≥14 días. Actualizar este campo al procesar cualquier comando entrante.
- Si no se implementa, el recordatorio se puede degradar a “si han pasado ≥14 días desde el primer paquete”, sin comprobar interacción (menos preciso).
---
@ -171,9 +176,10 @@ Archivos a modificar
- src/services/metrics.ts (no requiere cambios de API)
Métricas propuestas
- onboarding_dm_sent_total (labels: variant=initial|reminder, group_id)
- onboarding_dm_sent_total (labels: variant=initial|reminder, part=1|2, group_id)
- onboarding_bundle_sent_total (labels: variant=initial|reminder, group_id) — opcional
- onboarding_dm_skipped_total (labels: reason, group_id)
- reasons: 'cooldown_active', 'capped_event', 'not_allowed', 'disabled', 'no_members', 'no_group', 'not_group_context', 'no_display_code'
- reasons: 'cooldown_active', 'capped_event', 'not_allowed', 'disabled', 'no_members', 'no_group', 'not_group_context', 'no_display_code', 'had_interaction'
- onboarding_recipients_capped_total (labels: group_id)
- commands_alias_used_total (labels: action=info|mias|todas)
- commands_blocked_total (ya existe para gating; mantener)
@ -182,6 +188,7 @@ Flags/env sugeridas
- ONBOARDING_DM_ENABLED=true
- ONBOARDING_DM_COOLDOWN_DAYS=14
- ONBOARDING_EVENT_CAP=30
- ONBOARDING_BUNDLE_DELAY_MS=4000
- ONBOARDING_ENABLE_IN_TEST=false (o true si se van a probar envíos en tests)
- GROUP_GATING_MODE=enforce|off (ya existente)
- Opcional (si se diferencia horario amable): ONBOARDING_SILENCE_HOURS=22-08 (futuro)
@ -207,10 +214,10 @@ Objetivos
- Contexto grupo:
- Invocar listados desde un grupo responde por DM con transición (no lista en el grupo).
- Onboarding:
- Evento de creación en grupo dispara destinatarios esperados (excluye creador/asignados/bot; cap).
- 0 → initial, 1 y >14 días → reminder, resto → skip.
- Por evento de creación en grupo se encolan 2 DMs/usuario (part=1 inmediato y part=2 con retraso).
- Tras ≥14 días sin interacción desde el primer paquete, se encola un segundo paquete idéntico; si hubo interacción, no se encola.
- Gating enforce: grupos no permitidos → no enviar.
- Metadata de response_queue correcta (kind, variant).
- Metadata de response_queue correcta (kind, variant, part, bundle_id).
- Help v2 actualizado (snapshots).
- CTAs añadidos al final de DMs operativos.

Loading…
Cancel
Save