Consultas útiles
Para comprobar resultados sin depender de lo que muestre la interfaz. Si la pantalla y la base discrepan, la base manda.
Conexión: psql -h 127.0.0.1 -U sunathub -d crm
Webhooks
-- ¿Está llegando algo de Meta?
SELECT provider, event_type, signature_ok, processed_at, error, received_at
FROM webhook_events ORDER BY received_at DESC LIMIT 20;
-- ¿Cuántos se rechazaron por firma? (indicio de manipulación o de secreto mal puesto)
SELECT provider, count(*) FILTER (WHERE NOT signature_ok) AS rechazados, count(*) AS total
FROM webhook_events GROUP BY provider;
Conversaciones y mensajes
-- Estado de una conversación por número
SELECT id, channel, status, phone, customer_id,
window_expires_at, window_expires_at > now() AS ventana_abierta,
bot_greeted_at, handoff_at, unread_count
FROM conversations WHERE phone LIKE '%999888777%';
-- Hilo completo, en orden
SELECT created_at, direction, sender_type, kind, status, left(body, 60) AS texto
FROM messages
WHERE conversation_id = '...'
ORDER BY created_at;
-- Mensajes fallidos con su motivo
SELECT created_at, status, error_code, error_message, left(body, 50)
FROM messages WHERE status = 'fallido' ORDER BY created_at DESC LIMIT 20;
Tickets creados desde mensajería
SELECT t.code, t.type, t.priority, t.status, t.channel, t.source_reference,
t.first_response_minutes, t.resolution_minutes,
t.first_contact_resolution, t.is_overdue, u.full_name AS asignado
FROM tickets t
LEFT JOIN users u ON u.id = t.assigned_user_id
WHERE t.channel IN ('whatsapp','facebook','messenger')
ORDER BY t.created_at DESC LIMIT 20;
Indicadores en vivo
-- Cualquier indicador, para un rango. Las claves están en kpi_targets.
SELECT * FROM kpi_value('tpaHours', now() - interval '30 days', now());
SELECT * FROM kpi_value('fcrPct', now() - interval '30 days', now());
-- Todos a la vez, con su meta
SELECT k.key, k.label, k.target_value, k.unit, (kpi_value(k.key, now() - interval '30 days', now())).value
FROM kpi_targets k WHERE k.is_active ORDER BY k.position;
Campañas
SELECT c.code, c.name, c.status,
c.total_recipients, c.sent_count, c.delivered_count,
c.read_count, c.replied_count, c.converted_count, c.revenue
FROM campaigns c ORDER BY c.created_at DESC LIMIT 10;
-- Desglose de por qué no se envió a alguien
SELECT status, excluded_reason, count(*)
FROM campaign_recipients WHERE campaign_id = '...'
GROUP BY status, excluded_reason ORDER BY count(*) DESC;
Tiempo hábil
-- Comprobar que el cálculo descuenta noches, domingos y feriados
SELECT business_minutes_between(
timestamptz '2026-08-22 20:00 America/Lima',
timestamptz '2026-08-24 08:10 America/Lima');
-- 10 (sábado noche -> lunes al abrir)
-- Cuándo vence un plazo contado en horario laboral
SELECT add_business_minutes(now(), 240);
Limpieza entre pruebas
-- Borra la conversación de un número y sus mensajes. Los tickets se conservan.
DELETE FROM conversations WHERE phone LIKE '%999888777%';
-- Desbloquear una cuenta bloqueada por intentos fallidos
UPDATE users SET failed_logins = 0, locked_until = NULL WHERE email = '...';