0004 — Etiquetas de conversación como capacidad de plataforma
Estado: aceptada · Fecha: 2026-09-15
Contexto
Hacía falta que el bot clasificara conversaciones ("viene por seguro") sin transferirlas, y que la bandeja mostrara esas etiquetas. Ya existían etiquetas de conversación, pero en el CRM:
- Tablas sin versionar.
crm_tags,crm_lead_tagsycrm_conversation_tagsse crearon a mano en producción; no había migración, y DEV y PROD podían divergir sin que nadie lo viera. - Atadas a un módulo opcional. El catálogo solo se gestionaba en
/dashboard/crm/tags, detrás del módulo CRM, que el paquete de clínica no activa. - Accesos abiertos, según el volcado de PROD del 2026-09-15:
GRANT ALLaanonen tablas y vistas;- cualquier miembro del tenant editaba el catálogo;
- el pivote comprobaba que la conversación fuera del tenant, pero no la etiqueta.
Decisión
Las etiquetas de conversación son plataforma, con las mismas tablas. No se crean tablas nuevas: un tenant con CRM y sin él comparten un único catálogo, y el widget del CRM sigue viendo lo que pone el bot.
- Migración
20261007000002.- Versiona el esquema de forma idempotente (no-op donde ya existe).
- Revoca
anon. - Exige
core.tags.manage(ocrm.tags.manage, por compatibilidad) para gestionar el catálogo yconversation.replypara etiquetar, con etiqueta y conversación del mismo tenant. Leer las etiquetas exige poder ver la conversación. - Publica el pivote en Realtime.
- La prueba de roles está en
supabase/tests/conversation_tags/.
- Migración
20261007000003. Añadecore.tags.managea los dos caminos de alta de tenant (grant_tenant_admin_core_permissionsyrole_presets.adminde los paquetes de industria) y crea el menú Configuración → Etiquetas sinmodule_code. - Backend.
ConversationTagsService(core) resuelve etiquetas por código o nombre, solo del catálogo del tenant, y nunca las crea.- La herramienta
tag_conversationno declararequiresModuley solo aparece si el tenant tiene etiquetas de conversación.
- Frontend. Las vistas del catálogo reciben sus rutas (
TagRoutes) y se montan en Configuración y en el CRM.
El nombre crm_* de las tablas se conserva a propósito: renombrarlas obligaría a tocar el CRM y
sus vistas sin ningún beneficio para quien usa el producto.
Consecuencias
- Pierden la gestión del catálogo los miembros sin rol admin y sin
crm.tags.manage, que antes podían editarlo. La migración reparte el permiso nuevo a admins y a quien ya tenía el del CRM. - Pierde la opción de etiquetar quien no tiene
conversation.reply. Es coherente: tampoco puede responder en esa conversación. - El motivo del traspaso (
conversations.handoff_reason) es otra cosa: un estado temporal que se borra al reactivar el bot. Las etiquetas son clasificación persistente. - Pendiente:
crm_lead_tags, las vistascrm_*_vdel resto del CRM y sus tablas siguen sin versionar. Esta decisión solo cubre lo que usa la bandeja.