|
-- ===================================================================== |
|
-- He4rt Developers — Pack de queries de engajamento VÁLIDAS |
|
-- Gerado 2026-06-20 a partir da investigação multi-agente (verificadas). |
|
-- Inclui APENAS KPIs com pipeline saudável e SQL que sobreviveu à verificação |
|
-- adversarial (sql_correct=true OU com correção aplicada). |
|
-- Excluídos: moderação/economia (tabelas vazias), gamificação (dormente 2023), |
|
-- e métricas de qualidade de texto/conteúdo fora da janela válida. |
|
-- TZ de exibição: America/Sao_Paulo | hoje: 2026-06-20 |
|
-- ===================================================================== |
|
|
|
|
|
-- ##################################################################### |
|
-- NICHO: Engajamento de Texto (Discord messages) |
|
-- ##################################################################### |
|
|
|
-- [1] Membros Ativos Mensais (MAU) - texto (north_star) |
|
-- Definição: Contagem de external_identity_id distintos que enviaram >=1 mensagem nos ultimos 30 dias completos (21/05-19/06, exclui dia parcial de hoje). North-star do engajamento de texto: mede alcance real da conversa. |
|
-- Valor medido: MAU(30d) = 391 membros distintos |
|
-- ✔ Correção verificada: MAU(30d) = 390 (not 391) |
|
-- Viz: big number + sparkline mensal | Alvo: >= 400 | Alerta: < 300 por 2 semanas consecutivas |
|
WITH base AS (SELECT external_identity_id, COALESCE(sent_at,created_at) AT TIME ZONE 'America/Sao_Paulo' AS local_ts FROM messages WHERE COALESCE(sent_at,created_at) >= '2019-01-01') SELECT COUNT(DISTINCT external_identity_id) AS mau FROM base WHERE local_ts >= '2026-05-21' AND local_ts < '2026-06-20'; |
|
|
|
-- [2] DAU medio / WAU - texto (input) |
|
-- Definição: DAU medio dos ultimos 30 dias completos e WAU (semana completa 13-19/06). DAU calculado por dia em America/Sao_Paulo e depois media. Dia de hoje (parcial) EXCLUIDO. |
|
-- Valor medido: DAU medio(30d) = 37,6; WAU(13-19/06) = 165; faixa DAU diaria observada 17-84 (hoje parcial=15) |
|
-- ✔ Correção verificada: avg_dau_30d = 38.7 (not 37.6); daily DAU range 9-84 (not 17-84); WAU=165 (correct); n_days should be 30, not 31 |
|
-- Viz: line chart diario com banda partial-day destacada | Alvo: DAU medio >= 45 | Alerta: DAU medio < 25 (excluindo feriados) |
|
WITH daily AS (SELECT (COALESCE(sent_at,created_at) AT TIME ZONE 'America/Sao_Paulo')::date AS d, external_identity_id FROM messages WHERE COALESCE(sent_at,created_at) >= '2026-05-21' AND COALESCE(sent_at,created_at) < '2026-06-20'), per_day AS (SELECT d, COUNT(DISTINCT external_identity_id) AS dau FROM daily GROUP BY d) SELECT ROUND(AVG(dau),1) AS avg_dau_30d FROM per_day; |
|
|
|
-- [3] Stickiness DAU/MAU - texto (health) |
|
-- Definição: Razao DAU_medio / MAU nos ultimos 30 dias completos. Mede frequencia de retorno: quao 'pegajosa' e a conversa de texto. |
|
-- Valor medido: Stickiness = 9,63% (abaixo do benchmark saudavel ~20%) |
|
-- ✔ Correção verificada: Stickiness = 9.91% (not 9.63%) |
|
-- Viz: gauge + trend | Alvo: >= 15% | Alerta: < 8% |
|
WITH daily AS (SELECT (COALESCE(sent_at,created_at) AT TIME ZONE 'America/Sao_Paulo')::date AS d, external_identity_id FROM messages WHERE COALESCE(sent_at,created_at) >= '2026-05-21' AND COALESCE(sent_at,created_at) < '2026-06-20'), per_day AS (SELECT d, COUNT(DISTINCT external_identity_id) AS dau FROM daily GROUP BY d) SELECT ROUND(100.0*AVG(dau)/(SELECT COUNT(DISTINCT external_identity_id) FROM daily),2) AS stickiness_pct FROM per_day; |
|
|
|
-- [4] Mensagens por membro ativo (30d) (input) |
|
-- Definição: Total de mensagens / membros ativos distintos nos ultimos 30 dias completos. Intensidade de uso por pessoa. Atencao: inflada pelo canal Trabalho/Working (feed de status). |
|
-- Valor medido: 27.418 msgs / 391 ativos = 70,1 msgs por membro ativo (mediana muito menor devido a power-law) |
|
-- ✔ Correção verificada: 27.418 msgs / 390 ativos = 70.3 (denominator should be 390, not 391) |
|
-- Viz: bar + media vs mediana lado a lado | Alvo: monitorar tendencia (nao alvo absoluto) | Alerta: queda > 30% MoM |
|
WITH base AS (SELECT * FROM messages WHERE COALESCE(sent_at,created_at) >= '2026-05-21' AND COALESCE(sent_at,created_at) < '2026-06-20') SELECT COUNT(*) AS total, COUNT(DISTINCT external_identity_id) AS active, ROUND(COUNT(*)::numeric/NULLIF(COUNT(DISTINCT external_identity_id),0),1) AS msgs_per_active FROM base; |
|
|
|
-- [5] Concentracao de canais (share top-1) (health) |
|
-- Definição: Participacao do canal #1 no total de mensagens dos ultimos 30 dias completos, com join messages.channel_id = discord_channels.discord_channel_id. Mede saude da distribuicao da conversa. |
|
-- Valor medido: Top-1 'Trabalho/Working' = 62,57%; Top-2 'Reuniao Semanal' = 30,35% (top-2 acumulado 92,9%); 'bate-papo' so 3,99% |
|
-- Viz: treemap / pareto de canais | Alvo: top-1 < 40% (conversa mais distribuida) | Alerta: top-1 > 65% |
|
WITH base AS (SELECT m.channel_id FROM messages m WHERE COALESCE(m.sent_at,m.created_at) >= '2026-05-21' AND COALESCE(m.sent_at,m.created_at) < '2026-06-20'), ch AS (SELECT b.channel_id, dc.name, COUNT(*) AS n FROM base b LEFT JOIN discord_channels dc ON dc.discord_channel_id=b.channel_id GROUP BY b.channel_id, dc.name) SELECT name, n, ROUND(100.0*n/SUM(n) OVER (),2) AS pct FROM ch ORDER BY n DESC LIMIT 5; |
|
|
|
-- [6] Share do top 1% de membros (power-law) (health) |
|
-- Definição: % das mensagens geradas pelo 1% (e 10%) mais ativo dos membros nos ultimos 30 dias. Diagnostica dependencia de poucos super-usuarios. |
|
-- Valor medido: Top 1% = 34,28% das mensagens; Top 10% = 87,96%. 391 membros ativos no periodo. |
|
-- Viz: lorenz curve / concentracao | Alvo: top 1% < 25% | Alerta: top 1% > 40% |
|
WITH per_user AS (SELECT external_identity_id, COUNT(*) AS msgs FROM messages WHERE COALESCE(sent_at,created_at) >= '2026-05-21' AND COALESCE(sent_at,created_at) < '2026-06-20' GROUP BY external_identity_id), ranked AS (SELECT msgs, NTILE(100) OVER (ORDER BY msgs DESC) AS pctile, SUM(msgs) OVER () AS total FROM per_user) SELECT ROUND(100.0*SUM(msgs) FILTER (WHERE pctile=1)/MAX(total),2) AS top1pct, ROUND(100.0*SUM(msgs) FILTER (WHERE pctile<=10)/MAX(total),2) AS top10pct FROM ranked; |
|
|
|
-- [7] Taxa de reacao (janela valida) (content) |
|
-- Definição: % de mensagens com reactions_count>0. MEDIDA na ultima janela com metadata valido (16/02-18/03/2026), pois a ingestao de reacoes parou em ~2026-03-23. Proxy de ressonancia do conteudo. |
|
-- Valor medido: 0,05% na janela valida recente; lifetime 72.131/3.292.538 = 2,19%; 2024-ate-mar/2026 = 0,66% |
|
-- Viz: line com flag de 'metadata indisponivel' apos 18/03 | Alvo: > 1% (restaurar captura primeiro) | Alerta: ZERO em janela onde metadata deveria existir (= ingestao quebrada) |
|
WITH base AS (SELECT * FROM messages WHERE COALESCE(sent_at,created_at) >= '2026-02-16' AND COALESCE(sent_at,created_at) < '2026-03-18') SELECT ROUND(100.0*COUNT(*) FILTER (WHERE reactions_count>0)/COUNT(*),2) AS pct_reacted FROM base; |
|
|
|
-- [8] Taxa de resposta (reply rate, janela valida) (content) |
|
-- Definição: % de mensagens que sao replies (reply_to_message_id IS NOT NULL OR kind='reply'). kind='reply' captura mais que a FK. Mede densidade conversacional. Janela valida 16/02-18/03/2026. |
|
-- Valor medido: 0,74% (combinado) na janela valida; via FK isolada 0,72%; kind='reply' adiciona pouco neste periodo; 2024->mar2026 pct_reply_kind=2,24% vs FK=0,90% |
|
-- Viz: line com flag metadata | Alvo: > 3% (conversas mais encadeadas) | Alerta: 0% pos-18/03 = artefato de ingestao |
|
WITH base AS (SELECT * FROM messages WHERE COALESCE(sent_at,created_at) >= '2026-02-16' AND COALESCE(sent_at,created_at) < '2026-03-18') SELECT ROUND(100.0*COUNT(*) FILTER (WHERE reply_to_message_id IS NOT NULL OR kind='reply')/COUNT(*),2) AS pct_reply FROM base; |
|
|
|
-- [9] Taxa de edicao (janela valida) (content) |
|
-- Definição: % de mensagens com edited_at IS NOT NULL na janela valida 16/02-18/03/2026. Sinal de cuidado/correcao do autor. |
|
-- Valor medido: 0,03% na janela valida; lifetime 30.043/3.292.538 = 0,91%; 2024->mar2026 = 0,22% |
|
-- Viz: small number + flag | Alvo: informativo (sem alvo) | Alerta: 0% pos-18/03 = ingestao quebrada |
|
WITH base AS (SELECT * FROM messages WHERE COALESCE(sent_at,created_at) >= '2026-02-16' AND COALESCE(sent_at,created_at) < '2026-03-18') SELECT ROUND(100.0*COUNT(*) FILTER (WHERE edited_at IS NOT NULL)/COUNT(*),2) AS pct_edited FROM base; |
|
|
|
-- [10] Atividade de mencoes (content) |
|
-- Definição: Mencoes capturadas (message_mentions) e mencoes a everyone/role. Mede o quanto a conversa puxa pessoas para dentro. Tabela message_mentions tambem parou em 2026-03-23. |
|
-- Valor medido: 170.847 mencoes historicas, 21.298 identidades mencionadas distintas; ULTIMA mencao registrada 2026-03-23 (ingestao parou) |
|
-- Viz: rede de mencoes / counter com data da ultima captura | Alvo: restaurar captura + crescer mencoes/membro | Alerta: nenhuma nova linha em message_mentions por 7 dias |
|
SELECT (SELECT COUNT(*) FROM message_mentions) AS total_mention_rows, (SELECT COUNT(DISTINCT mentioned_identity_id) FROM message_mentions) AS distinct_mentioned, (SELECT MAX(COALESCE(m.sent_at,m.created_at)) FROM message_mentions mm JOIN messages m ON m.id=mm.message_id) AS last_mention_at; |
|
|
|
-- [11] Heatmap hora x dia-da-semana (texto) (input) |
|
-- Definição: Distribuicao de mensagens por (DOW, hora) em America/Sao_Paulo nos ultimos 90 dias. Revela janelas de pico para timing de anuncios/eventos. DOW: 0=domingo. |
|
-- Valor medido: Pico forte SEGUNDA (dow=1) 22h (9.252) e 23h (5.077) BRT = reuniao semanal; pico secundario QUARTA (dow=3) 19-20h; manha 11h (qui/sex) ativa |
|
-- Viz: heatmap 7x24 | Alvo: informativo (timing) | Alerta: n/a |
|
WITH base AS (SELECT COALESCE(sent_at,created_at) AT TIME ZONE 'America/Sao_Paulo' AS ts FROM messages WHERE COALESCE(sent_at,created_at) >= '2026-03-20' AND COALESCE(sent_at,created_at) < '2026-06-20') SELECT EXTRACT(DOW FROM ts)::int AS dow, EXTRACT(HOUR FROM ts)::int AS hour, COUNT(*) AS n FROM base GROUP BY 1,2 ORDER BY n DESC LIMIT 10; |
|
|
|
-- [12] Distribuicao por kind / source_kind (content) |
|
-- Definição: Mix de tipos de mensagem (kind) e origem (source_kind) nos ultimos ~6 meses. Importante porque NULL domina e webhook infla volume sem ser chat humano. |
|
-- Valor medido: kind NULL / source NULL = 83,37% (metadata ausente); default+webhook = 14,18%; default+bot = 1,57%; reply+bot 0,44%; user real (default+user) so 0,31% |
|
-- Viz: stacked bar kind x source | Alvo: reduzir NULL share apos correcao de ingestao | Alerta: NULL share > 80% (perda de metadata) |
|
SELECT kind, source_kind, COUNT(*) AS n, ROUND(100.0*COUNT(*)/SUM(COUNT(*)) OVER (),2) AS pct FROM messages WHERE COALESCE(sent_at,created_at) >= '2026-01-01' GROUP BY kind, source_kind ORDER BY n DESC LIMIT 10; |
|
|
|
-- ##################################################################### |
|
-- NICHO: Engajamento de Voz (voice_messages) |
|
-- ##################################################################### |
|
|
|
-- [13] Voice-hours per week (north_star) |
|
-- Definição: Total paired voice-hours (joined→left per external_identity_id+channel_name, sessions capped at 12h) bucketed by week in display tz. The core measure of voice engagement volume. |
|
-- Valor medido: Last reliable weeks (BRT): 2026-05-04=380.3h, 05-11=393.5h, 05-18=608.2h (peak), 05-25=522.3h, 06-01=503.5h. Total all-time ~109,473.4h across 170,861 sessions. Weeks after 2026-06-06 are 0/null due to pipeline break. |
|
-- ✔ Correção verificada: Confirmed exactly: 170,861 sessions, 109,473.4h total. Weekly BRT: 05-04=380.3, 05-11=393.5, 05-18=608.2 (peak), 05-25=522.3, 06-01=503.5. Single AT TIME ZONE (no double-convert), occurred_at>=2020-01-01 filter valid (min row 2020-01-01, 0 nulls). 06-01 week is partial (cut by pipeline break) and correctly flagged. |
|
-- Viz: line chart (weekly), with vertical marker at 2026-06-06 pipeline break | Alvo: Sustain >=500 voice-hours/week | Alerta: Alert if a COMPLETE week < 350h, OR if joined-event count for the trailing 3 days = 0 (pipeline-dead signal) |
|
WITH ordered AS (SELECT external_identity_id, channel_name, state, occurred_at, LEAD(state) OVER w AS next_state, LEAD(occurred_at) OVER w AS next_occurred FROM voice_messages WHERE state IN ('joined','left') AND occurred_at >= '2020-01-01' WINDOW w AS (PARTITION BY external_identity_id, channel_name ORDER BY occurred_at)), sessions AS (SELECT occurred_at, EXTRACT(EPOCH FROM (next_occurred - occurred_at))/3600.0 AS hours FROM ordered WHERE state='joined' AND next_state='left' AND next_occurred > occurred_at AND next_occurred - occurred_at <= interval '12 hours') SELECT date_trunc('week', occurred_at AT TIME ZONE 'America/Sao_Paulo')::date AS week, ROUND(SUM(hours)::numeric,1) AS voice_hours FROM sessions GROUP BY 1 ORDER BY 1; |
|
|
|
-- [14] Weekly active voice users (WAU-voice) (input) |
|
-- Definição: COUNT(DISTINCT external_identity_id) with at least one paired voice session in the week. Drives voice-hours. |
|
-- Valor medido: BRT weeks: 05-04=321, 05-11=300, 05-18=387 (peak), 05-25=245, 06-01=314 users. 0 after 2026-06-06 (pipeline). |
|
-- ✔ Correção verificada: Confirmed: 05-04=321, 05-11=300, 05-18=387, 05-25=245, 06-01=314. Uses COUNT(DISTINCT external_identity_id) correctly. |
|
-- Viz: line chart weekly | Alvo: >=300 active voice users/week | Alerta: Alert if complete-week WAU-voice < 200 |
|
WITH ordered AS (SELECT external_identity_id, channel_name, state, occurred_at, LEAD(state) OVER w AS next_state, LEAD(occurred_at) OVER w AS next_occurred FROM voice_messages WHERE state IN ('joined','left') AND occurred_at >= '2020-01-01' WINDOW w AS (PARTITION BY external_identity_id, channel_name ORDER BY occurred_at)), sessions AS (SELECT external_identity_id, occurred_at FROM ordered WHERE state='joined' AND next_state='left' AND next_occurred > occurred_at AND next_occurred - occurred_at <= interval '12 hours') SELECT date_trunc('week', occurred_at AT TIME ZONE 'America/Sao_Paulo')::date AS week, COUNT(DISTINCT external_identity_id) AS active_voice_users FROM sessions GROUP BY 1 ORDER BY 1; |
|
|
|
-- [15] Median session duration (health) |
|
-- Definição: Median (P50) minutes per paired voice session. Median used instead of mean because distribution is heavily right-skewed (drop-ins distort the mean). |
|
-- Valor medido: Median = 5.3 min, Mean = 38.4 min (all-time). Large gap confirms right-skew. |
|
-- ✔ Correção verificada: Confirmed: median=5.3 min, mean=38.4 min (170,861 sessions). PERCENTILE_CONT used correctly; median chosen over mean appropriately given right-skew. |
|
-- Viz: single stat + secondary mean stat to show skew | Alvo: Median trending up (more sticky sessions) | Alerta: Watch if median drops below 3 min |
|
WITH ordered AS (SELECT external_identity_id, channel_name, state, occurred_at, LEAD(state) OVER w AS next_state, LEAD(occurred_at) OVER w AS next_occurred FROM voice_messages WHERE state IN ('joined','left') AND occurred_at >= '2020-01-01' WINDOW w AS (PARTITION BY external_identity_id, channel_name ORDER BY occurred_at)), sessions AS (SELECT EXTRACT(EPOCH FROM (next_occurred - occurred_at))/3600.0 AS hours FROM ordered WHERE state='joined' AND next_state='left' AND next_occurred > occurred_at AND next_occurred - occurred_at <= interval '12 hours') SELECT ROUND((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY hours)*60)::numeric,1) AS median_min, ROUND((AVG(hours)*60)::numeric,1) AS mean_min FROM sessions; |
|
|
|
-- [16] Voice drop-in (bounce) rate (health) |
|
-- Definição: Share of paired sessions lasting < 1 minute. Proxy for accidental/curiosity joins that don't convert to real participation. |
|
-- Valor medido: Drop-in rate = 0.354 (35.4%; 60,554 of 170,861 sessions < 1 min). Buckets: <1m=60,554, 1-5m=24,069, 5-30m=34,188, 30-120m=37,427, >2h=14,623. |
|
-- ✔ Correção verificada: Confirmed: 0.354 (60,554/170,861 < 1 min). Buckets verified: <1m=60,554, 1-5m=24,069, 5-30m=34,188, 30-120m=37,427, >2h=14,623. |
|
-- Viz: gauge + duration-bucket histogram | Alvo: Reduce below 30% | Alerta: Alert if > 45% |
|
WITH ordered AS (SELECT external_identity_id, channel_name, state, occurred_at, LEAD(state) OVER w AS next_state, LEAD(occurred_at) OVER w AS next_occurred FROM voice_messages WHERE state IN ('joined','left') AND occurred_at >= '2020-01-01' WINDOW w AS (PARTITION BY external_identity_id, channel_name ORDER BY occurred_at)), sessions AS (SELECT EXTRACT(EPOCH FROM (next_occurred - occurred_at))/60.0 AS minutes FROM ordered WHERE state='joined' AND next_state='left' AND next_occurred > occurred_at AND next_occurred - occurred_at <= interval '12 hours') SELECT ROUND((COUNT(*) FILTER (WHERE minutes < 1)::numeric / COUNT(*)),3) AS drop_in_rate, COUNT(*) FILTER (WHERE minutes < 1) AS under_1min, COUNT(*) FILTER (WHERE minutes >= 120) AS over_2h FROM sessions; |
|
|
|
-- [17] Voice session pairing completeness (health) |
|
-- Definição: Share of 'joined' events that have a matching subsequent 'left' (per user+channel). A data-quality / instrumentation health metric — low values mean missed disconnects and undercounted hours. |
|
-- Valor medido: Pairing rate = 0.878 (173,528 matched / 197,743 joins). 24,215 orphan joins (12.2%). |
|
-- ✔ Correção verificada: Confirmed: 0.878 (173,528 matched / 197,743 joins). 24,215 orphan joins (12.2%). 2,275 sessions exceeded 12h cap (verified). |
|
-- Viz: single stat with red/green threshold | Alvo: >= 0.90 | Alerta: Alert if < 0.80 (instrumentation degrading) |
|
WITH ordered AS (SELECT external_identity_id, channel_name, state, occurred_at, LEAD(state) OVER w AS next_state FROM voice_messages WHERE state IN ('joined','left') AND occurred_at >= '2020-01-01' WINDOW w AS (PARTITION BY external_identity_id, channel_name ORDER BY occurred_at)) SELECT COUNT(*) FILTER (WHERE state='joined') AS joins, COUNT(*) FILTER (WHERE state='joined' AND next_state='left') AS matched, ROUND((COUNT(*) FILTER (WHERE state='joined' AND next_state='left')::numeric / NULLIF(COUNT(*) FILTER (WHERE state='joined'),0)),3) AS pairing_rate FROM ordered; |
|
|
|
-- [18] Peak voice concurrency (daily) (input) |
|
-- Definição: Max simultaneous users in voice per day, approximated by the running sum of +1(joined)/-1(left) over occurred_at within the day (display tz). Proxy for live-room peak load and event attendance. |
|
-- Valor medido: Recent BRT peaks: 06-01=45, 05-25=55 (weekly meeting spikes) vs single-digit baseline (2-10) on ordinary days. Goes to single digits / unreliable after 06-06 (only mute/unmute events remain). |
|
-- ✔ Correção verificada: Reproduced peaks: 05-25=55, 05-11=55, 05-04=51, 04-27=47, 06-01=45. Report cited 06-01=45 and 05-25=55 as examples (correct). Running-sum proxy ordered by occurred_at then delta DESC processes joins before lefts on ties, marginally inflating peak; acceptable for a proxy. Channel-agnostic so unaffected by the channel_name resolution issue. |
|
-- Viz: bar chart daily (last 30d), highlight weekly meeting peaks | Alvo: Sustain weekly peak >= 40 on meeting days | Alerta: Alert if weekly meeting-day peak < 20 |
|
WITH evt AS (SELECT occurred_at, CASE WHEN state='joined' THEN 1 WHEN state='left' THEN -1 ELSE 0 END AS delta, (occurred_at AT TIME ZONE 'America/Sao_Paulo')::date AS day FROM voice_messages WHERE state IN ('joined','left') AND occurred_at >= now() - interval '60 days'), running AS (SELECT day, SUM(delta) OVER (PARTITION BY day ORDER BY occurred_at, delta DESC) AS concurrent FROM evt) SELECT day, MAX(concurrent) AS peak_concurrent FROM running GROUP BY day ORDER BY day DESC; |
|
|
|
-- [19] Top voice channels by hours (concentration) (content) |
|
-- Definição: Voice-hours, sessions, distinct users and avg session length per channel_name (excluding unresolved numeric-ID names). Shows where engagement concentrates and channel personality. |
|
-- Valor medido: 🗣 Conversando 19,321.1h/4,834u/39.8min; ✅Reunião Semanal 10,744.8h/11,255u/15.1min (high churn event); 🏢 Trabalho/Working 5,700.0h/945u/82.4min (longest); 📖 Estudando 5,334.4h/53.0min; 😴 Ausente 3,446.4h/79.2min; 🗣 Conversando 2 2,865.7h; Spaces 2,008.2h/5,502u/9.5min. |
|
-- ✔ Correção verificada: Numbers for named channels reproduce exactly (Conversando 19,321.1h, Reuniao Semanal 10,744.8h, Trabalho 5,700.0h, etc). BUT the exclusion regex (channel_name !~ '^[0-9]+$') drops 4,700 distinct unresolved-ID channels totalling 58,562h = 53.5% of all 109,482 voice-hours and 66,166 sessions. The report claimed only '~15' such channels. The concentration denominator therefore covers under half of real voice-hours, so the 'single channel > 60% of weekly hours' alert is computed against a wrong base. Worse: in May-Jun 2026, 100% of join/left rows carry numeric channel_names, so this chart shows ZERO recent activity and is entirely historical. |
|
-- Viz: horizontal bar (top 10) + table with avg-min column | Alvo: n/a (distribution monitor) | Alerta: Flag if a single channel exceeds 60% of weekly hours (over-concentration) |
|
WITH ordered AS (SELECT external_identity_id, channel_name, state, occurred_at, LEAD(state) OVER w AS next_state, LEAD(occurred_at) OVER w AS next_occurred FROM voice_messages WHERE state IN ('joined','left') AND occurred_at >= '2020-01-01' WINDOW w AS (PARTITION BY external_identity_id, channel_name ORDER BY occurred_at)), sessions AS (SELECT channel_name, external_identity_id, EXTRACT(EPOCH FROM (next_occurred - occurred_at))/3600.0 AS hours FROM ordered WHERE state='joined' AND next_state='left' AND next_occurred > occurred_at AND next_occurred - occurred_at <= interval '12 hours') SELECT channel_name, COUNT(*) AS sessions, COUNT(DISTINCT external_identity_id) AS users, ROUND(SUM(hours)::numeric,1) AS voice_hours, ROUND((AVG(hours)*60)::numeric,1) AS avg_min FROM sessions WHERE channel_name !~ '^[0-9]+$' GROUP BY 1 ORDER BY voice_hours DESC LIMIT 10; |
|
|
|
-- [20] Voice mute ratio (health) |
|
-- Definição: Mute events per joined session. Low values = users speak/stay unmuted; very high values may indicate passive listening. NOTE: muted/unmuted instrumentation only became reliable from ~2026-06-06; the all-time number understates current behavior. |
|
-- Valor medido: All-time = 0.009 (1,808 mutes / 197,743 joins) — artificially low because mute events were barely captured before 06-06. Post-06-07: 1,746 muted + 953 unmuted events exist but with 0 joins to ratio against (pipeline split). |
|
-- ✔ Correção verificada: Confirmed: 0.009 (1,808 muted / 197,743 joins). Note total muted is only 1,808 across all time; the report's narrative '1,746 muted + 953 unmuted post-06-07' overstates post-break mutes (actual post-06-06 muted is well under 1,808). Ratio KPI itself is correct. |
|
-- Viz: single stat (scoped to >= 2026-06-07 window once join tracking is restored) | Alvo: Establish baseline once join+mute tracking coexist | Alerta: Re-baseline after pipeline fix |
|
SELECT ROUND((COUNT(*) FILTER (WHERE state='muted')::numeric / NULLIF(COUNT(*) FILTER (WHERE state='joined'),0)),3) AS mute_per_join FROM voice_messages WHERE occurred_at >= '2020-01-01'; |
|
|
|
-- [21] Voice-only vs also-text member split (cross_platform) |
|
-- Definição: Among all voice users, share who NEVER appear in messages (voice-only / silent listeners) vs those who also post text. Identifies a re-engagement segment. |
|
-- Valor medido: 19,896 voice users total: 9,429 (47.4%) also post text, 10,467 (52.6%) are voice-ONLY (never sent a text message). |
|
-- ✔ Correção verificada: Confirmed: 19,896 voice users; 9,429 (47.4%) also-text; 10,467 (52.6%) voice-only. messages filtered COALESCE(sent_at,created_at)>=2019-01-01 correctly excludes the 1999 junk (108,928 junk rows verified). Joined on external_identity_id (correct unifying key). |
|
-- Viz: donut chart | Alvo: Convert voice-only into text participants (reduce voice-only share) | Alerta: n/a (segment monitor) |
|
WITH voice_users AS (SELECT DISTINCT external_identity_id FROM voice_messages WHERE occurred_at >= '2020-01-01'), text_users AS (SELECT DISTINCT external_identity_id FROM messages WHERE COALESCE(sent_at, created_at) >= '2019-01-01') SELECT (SELECT COUNT(*) FROM voice_users) AS voice_users_total, (SELECT COUNT(*) FROM voice_users v WHERE EXISTS (SELECT 1 FROM text_users t WHERE t.external_identity_id=v.external_identity_id)) AS voice_and_text, (SELECT COUNT(*) FROM voice_users v WHERE NOT EXISTS (SELECT 1 FROM text_users t WHERE t.external_identity_id=v.external_identity_id)) AS voice_only; |
|
|
|
-- [22] Voice retention (multi-month return rate) (business) |
|
-- Definição: Share of voice users active in >=2 distinct calendar months (display tz). Measures whether voice creates a recurring habit, not a one-off. |
|
-- Valor medido: Multi-month retention = 0.501 (9,963 of 19,896 return in 2+ months); 9,933 one-month-only; 1,961 are 6+ month long-haulers (9.9%). Active in last 30d = 625 (inflated by mute/unmute-only rows post-06-06). |
|
-- ✔ Correção verificada: Confirmed: 0.501 (9,963/19,896); 6+ month=1,961 (9.9%). Single AT TIME ZONE month bucketing correct. |
|
-- Viz: single stat + cohort line for month-over-month retention | Alvo: >= 0.50 multi-month return | Alerta: Alert if multi-month rate drops below 0.40 |
|
WITH user_months AS (SELECT external_identity_id, COUNT(DISTINCT date_trunc('month', occurred_at AT TIME ZONE 'America/Sao_Paulo')) AS active_months FROM voice_messages WHERE occurred_at >= '2020-01-01' GROUP BY 1) SELECT COUNT(*) AS total, COUNT(*) FILTER (WHERE active_months>=2) AS multi_month, COUNT(*) FILTER (WHERE active_months>=6) AS six_plus, ROUND((COUNT(*) FILTER (WHERE active_months>=2)::numeric / COUNT(*)),3) AS multi_month_rate FROM user_months; |
|
|
|
-- [23] Month-over-month voice retention (business) |
|
-- Definição: Of users active in voice in month M, how many were also active in month M-1. A rolling stickiness signal. |
|
-- Valor medido: Active/retained by month (BRT): 2026-03=951/190 (20%), 04=816/296 (36%), 05=920/290 (32%), 06=425/201 (47% but June PARTIAL & join-tracking dead after 06-06). 2025-07=462/138 (30%). |
|
-- ✔ Correção verificada: Values reproduce exactly (2026-03=951/190, 04=816/296, 05=920/290, 06=425/201). BUT 'active' is defined as ANY voice_messages row (no state filter), so post-06-06 the muted/unmuted-only rows count as active. June 2026 active=425 includes mute-only users who have no paired session, while every other voice KPI defines activity via paired joined->left sessions. This is an inconsistent activity definition that inflates June and makes the June MoM number non-comparable. The report flags June as partial but does not flag the definition mismatch. |
|
-- Viz: line chart (retained vs active) last 12 months | Alvo: MoM retention >= 30% | Alerta: Alert on a complete month with MoM retention < 20% |
|
WITH monthly AS (SELECT DISTINCT external_identity_id, date_trunc('month', occurred_at AT TIME ZONE 'America/Sao_Paulo')::date AS mon FROM voice_messages WHERE occurred_at >= '2025-06-01') SELECT mon, COUNT(*) AS active_users, COUNT(*) FILTER (WHERE EXISTS (SELECT 1 FROM monthly p WHERE p.external_identity_id=m.external_identity_id AND p.mon = m.mon - interval '1 month')) AS retained_from_prev FROM monthly m GROUP BY mon ORDER BY mon; |
|
|
|
-- ##################################################################### |
|
-- NICHO: Crescimento e Churn de Membros |
|
-- ##################################################################### |
|
|
|
-- [24] Net Member Growth (window) (north_star) |
|
-- Definição: GUILD_MEMBER_ADD events minus GUILD_MEMBER_REMOVE events over the logged window. The single number that says whether the community is growing. |
|
-- Valor medido: +313 net (698 adds - 385 removes) over 2026-05-19 to 2026-06-20 (~32 days) |
|
-- ✔ Correção verificada: +313 net (698 adds - 385 removes) — confirmed exactly |
|
-- Viz: Stacked bar (adds up / removes down) + net line overlay, daily | Alvo: >= +250 net per ~30d window | Alerta: Alert if rolling 7-day net <= 0 on any full (non-partial) week |
|
SELECT COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_ADD') AS adds, COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_REMOVE') AS removes, COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_ADD') - COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_REMOVE') AS net_growth FROM discord_event_logs WHERE event_type IN ('GUILD_MEMBER_ADD','GUILD_MEMBER_REMOVE'); |
|
|
|
-- [25] Daily Churn Ratio (removes/adds) (health) |
|
-- Definição: Removes divided by adds per day (display tz). >1.0 means the guild shrank that day. A normalized ratio that is comparable across days regardless of traffic volume. |
|
-- Valor medido: Window avg 0.552. Daily range 0.19 to 2.60. Negative-net days: 2026-06-05 (1.167), 2026-06-16 (2.60), 2026-06-20 (1.167, PARTIAL day) |
|
-- ✔ Correção verificada: Window avg 0.552, daily range 0.191-2.600; neg-net days 06-05 (1.167), 06-16 (2.600), 06-20 partial (1.167) — confirmed. Single AT TIME ZONE, no double-conversion. |
|
-- Viz: Line chart, daily, with 1.0 reference band; shade current partial day | Alvo: < 0.60 | Alerta: Alert if churn_ratio > 1.0 on any full day, or 3-day rolling avg > 0.80 |
|
WITH d AS (SELECT (created_at AT TIME ZONE 'America/Sao_Paulo')::date AS day, COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_ADD') AS adds, COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_REMOVE') AS removes FROM discord_event_logs WHERE event_type IN ('GUILD_MEMBER_ADD','GUILD_MEMBER_REMOVE') GROUP BY 1) SELECT day, adds, removes, ROUND(removes::numeric/NULLIF(adds,0),3) AS churn_ratio FROM d ORDER BY day; |
|
|
|
-- [26] Daily Member Adds / Removes (input) |
|
-- Definição: Raw count of GUILD_MEMBER_ADD and GUILD_MEMBER_REMOVE events per day in display tz. The two input flows that drive net growth. |
|
-- Valor medido: Adds avg ~22/day (peak 47 on 05-23). Removes avg ~12/day (spike 26 on 06-16). 2026-06-20 is PARTIAL (6 adds / 7 removes by 18:37). |
|
-- ✔ Correção verificada: Peak adds 47 on 05-23, removes spike 26 on 06-16, 06-20 partial 6/7 — confirmed exactly |
|
-- Viz: Grouped daily bar chart | Alvo: Adds >= 20/day sustained | Alerta: Alert if adds 0 for a full day (likely ingestion outage, not real) |
|
SELECT (created_at AT TIME ZONE 'America/Sao_Paulo')::date AS day, COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_ADD') AS adds, COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_REMOVE') AS removes FROM discord_event_logs WHERE event_type IN ('GUILD_MEMBER_ADD','GUILD_MEMBER_REMOVE') GROUP BY 1 ORDER BY 1; |
|
|
|
-- [27] Weekly Net Growth Trend (north_star) |
|
-- Definição: Net member change bucketed by ISO week (display tz), to smooth daily noise and reveal the growth trajectory. Current week flagged PARTIAL. |
|
-- Valor medido: 05-18: +106 (churn 0.354) | 05-25: +45 (0.659) | 06-01: +54 (0.609) | 06-08: +64 (0.549) | 06-15: +44 (0.639, PARTIAL). Net is decelerating vs the first full week. |
|
-- ✔ Correção verificada: 05-18 +106 (0.354) | 05-25 +45 (0.659) | 06-01 +54 (0.609) | 06-08 +64 (0.549) | 06-15 +44 (0.639, PARTIAL) — confirmed exactly. Partial-week flag correct. |
|
-- Viz: Bar chart per week, current week styled as partial/striped | Alvo: Net >= +50/full week | Alerta: Alert if two consecutive full weeks show net < +30 |
|
WITH w AS (SELECT date_trunc('week',(created_at AT TIME ZONE 'America/Sao_Paulo'))::date AS wk, COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_ADD') AS adds, COUNT(*) FILTER (WHERE event_type='GUILD_MEMBER_REMOVE') AS removes FROM discord_event_logs WHERE event_type IN ('GUILD_MEMBER_ADD','GUILD_MEMBER_REMOVE') GROUP BY 1) SELECT wk, adds, removes, adds-removes AS net, ROUND(removes::numeric/NULLIF(adds,0),3) AS churn_ratio, CASE WHEN wk=date_trunc('week',DATE '2026-06-20')::date THEN 'PARTIAL' ELSE 'full' END AS week_status FROM w ORDER BY wk; |
|
|
|
-- [28] Join-Request Approval Rate (business) |
|
-- Definição: Share of resolved join requests that were APPROVED, of all resolved requests (APPROVED via GUILD_JOIN_REQUEST_UPDATE status='APPROVED' + abandoned/rejected via GUILD_JOIN_REQUEST_DELETE). Measures how permeable the onboarding gate is. |
|
-- Valor medido: 0.9648 (658 approved / (658 + 24 deleted)). 698 actual member adds slightly exceed approvals (rejoins/instant joins). |
|
-- ✔ Correção verificada: 0.9648 (658 approved / (658+24 deleted)) — confirmed. Minor: 5 null-status UPDATE events exist and are excluded from the denominator (unresolved requests); defensible and does not change the figure. |
|
-- Viz: Funnel: Join Requests -> Approved -> Member Add; plus single gauge for rate | Alvo: Maintain > 0.90 (gate not over-rejecting); investigate if it drops, may signal raid filtering | Alerta: Alert if approval_rate < 0.80 over a rolling week (possible raid or screening misconfig) |
|
SELECT COUNT(*) FILTER (WHERE event_type='GUILD_JOIN_REQUEST_UPDATE' AND payload->>'status'='APPROVED') AS approved, COUNT(*) FILTER (WHERE event_type='GUILD_JOIN_REQUEST_DELETE') AS deleted, ROUND(COUNT(*) FILTER (WHERE event_type='GUILD_JOIN_REQUEST_UPDATE' AND payload->>'status'='APPROVED')::numeric / NULLIF(COUNT(*) FILTER (WHERE event_type='GUILD_JOIN_REQUEST_UPDATE' AND payload->>'status'='APPROVED') + COUNT(*) FILTER (WHERE event_type='GUILD_JOIN_REQUEST_DELETE'),0),4) AS approval_rate FROM discord_event_logs; |
|
|
|
-- [29] Membership-Screening Gate Pass Rate (business) |
|
-- Definição: Share of GUILD_MEMBER_ADD events arriving with pending=true (must complete Discord membership screening before participating). Shows how much of the join flow is gated. |
|
-- Valor medido: 0.994 (694 of 698 joins arrive pending). 0 bot adds detected in payload->user->bot. |
|
-- ✔ Correção verificada: 0.994 (694/698 pending), 0 bot adds, 692 distinct joiners — confirmed exactly. Correctly uses payload#>>'{user,id}' (the user_id column is 99% NULL). |
|
-- Viz: Single stat card with sparkline | Alvo: Informational; near 1.0 confirms screening is enforced on all joins | Alerta: Alert if pending share suddenly drops (screening disabled) — a security/quality regression |
|
SELECT COUNT(*) AS add_events, COUNT(*) FILTER (WHERE (payload->>'pending')::boolean IS TRUE) AS pending_on_join, COUNT(*) FILTER (WHERE (payload#>>'{user,bot}')::boolean IS TRUE) AS bot_adds, COUNT(DISTINCT payload#>>'{user,id}') AS distinct_joiners FROM discord_event_logs WHERE event_type='GUILD_MEMBER_ADD'; |
|
|
|
-- [30] Early Churn Rate (7-day, last 30d cohort) (health) |
|
-- Definição: Of members who joined in the last 30 days, the share who left within 7 days of joining. The sharpest onboarding-quality signal — these never stuck. Uses discord_members.joined_at/left_at (fresh table). |
|
-- Valor medido: 15.43% (100 of 648 recent joiners left within 7 days) |
|
-- ✔ Correção verificada: 15.43% (100 of 648) — confirmed exactly. now()-based 30d window on timestamptz is correct (absolute time). |
|
-- Viz: Single stat card + trend line of weekly cohort early-churn | Alvo: < 10% | Alerta: Alert if early-churn rate > 20% for the trailing 30-day cohort |
|
SELECT ROUND(100.0 * COUNT(*) FILTER (WHERE joined_at >= now() - interval '30 days' AND left_at IS NOT NULL AND left_at <= joined_at + interval '7 days') / NULLIF(COUNT(*) FILTER (WHERE joined_at >= now() - interval '30 days'),0),2) AS early_churn_7d_pct, COUNT(*) FILTER (WHERE joined_at >= now() - interval '30 days') AS joined_last_30d, COUNT(*) FILTER (WHERE joined_at >= now() - interval '30 days' AND left_at IS NOT NULL AND left_at <= joined_at + interval '7 days') AS churned_within_7d FROM discord_members WHERE NOT is_bot; |
|
|
|
-- [31] Tenure Distribution of Churned Members (health) |
|
-- Definição: Histogram of how long churned members (left_at IS NOT NULL) stayed before leaving, bucketed from <1 day to 365+ days. Distinguishes 'never onboarded' churn from 'lost a veteran' churn. |
|
-- Valor medido: 377 churned w/ tenure. <1d: 70 (18.6%) | 1-7d: 37 (9.8%) | 7-30d: 33 (8.8%) | 30-90d: 37 (9.8%) | 90-365d: 50 (13.3%) | 365+d: 150 (39.8%). Median leaver tenure 106.7 days, avg 480.9 days. |
|
-- ✔ Correção verificada: 377 churned: <1d 70 (18.6%) | 1-7d 37 (9.8%) | 7-30d 33 (8.8%) | 30-90d 37 (9.8%) | 90-365d 50 (13.3%) | 365+d 150 (39.8%); median 106.7d, avg 480.9d — confirmed exactly |
|
-- Viz: Horizontal bar histogram by tenure bucket | Alvo: Reduce <1d + 1-7d combined share (currently 28.4%) below 20% | Alerta: Alert if <7-day tenure share of churn exceeds 40% in a week (onboarding failure or raid cleanup) |
|
WITH t AS (SELECT EXTRACT(EPOCH FROM (left_at - joined_at))/86400.0 AS tenure_days FROM discord_members WHERE left_at IS NOT NULL AND joined_at IS NOT NULL AND NOT is_bot) SELECT CASE WHEN tenure_days<1 THEN 'a. <1 day' WHEN tenure_days<7 THEN 'b. 1-7 days' WHEN tenure_days<30 THEN 'c. 7-30 days' WHEN tenure_days<90 THEN 'd. 30-90 days' WHEN tenure_days<365 THEN 'e. 90-365 days' ELSE 'f. 365+ days' END AS bucket, COUNT(*) AS n, ROUND(100.0*COUNT(*)/SUM(COUNT(*)) OVER (),1) AS pct FROM t GROUP BY 1 ORDER BY 1; |
|
|
|
-- [32] Current Active Member Count (live) (north_star) |
|
-- Definição: Count of non-bot members with left_at IS NULL from the fresh discord_members table. Replaces the stale discord_guilds.member_count for the live headline number. |
|
-- Valor medido: 25,031 active humans (vs stale guild member_count 24,723, synced 31 days ago — a 308-member gap). 5 bots, 377 lifetime churned-with-tenure. |
|
-- ✔ Correção verificada: 25031 active humans, stale guild count 24723, 31 days stale, 5 bots — confirmed exactly |
|
-- Viz: Big-number stat card with WoW delta | Alvo: Monotonic growth week over week | Alerta: Alert if live active count drops vs prior day (sustained net-negative churn) |
|
SELECT COUNT(*) FILTER (WHERE left_at IS NULL AND NOT is_bot) AS live_active_members, (SELECT member_count FROM discord_guilds WHERE id=1) AS guild_reported_stale, (SELECT EXTRACT(DAY FROM now() - synced_at)::int FROM discord_guilds WHERE id=1) AS guild_count_days_stale FROM discord_members; |
|
|
|
-- [33] Booster (Premium) Penetration (business) |
|
-- Definição: Share of active members who are server boosters (premium_since IS NOT NULL). A monetary/loyalty health signal tied to retention of the most invested members. |
|
-- Valor medido: 13 active boosters = 0.052% of active members |
|
-- ✔ Correção verificada: 13 active boosters = 0.052% of active members — confirmed exactly |
|
-- Viz: Stat card with booster count + trend | Alvo: Informational baseline; track absolute booster count for tier maintenance | Alerta: Alert if active booster count drops below boost-tier threshold needed to keep current perks |
|
SELECT COUNT(*) AS active_boosters, ROUND(100.0*COUNT(*)/NULLIF((SELECT COUNT(*) FROM discord_members WHERE left_at IS NULL AND NOT is_bot),0),3) AS pct_of_active FROM discord_members WHERE premium_since IS NOT NULL AND left_at IS NULL AND NOT is_bot; |
|
|
|
-- ##################################################################### |
|
-- NICHO: WhatsApp e Comparacao Cross-Platform |
|
-- ##################################################################### |
|
|
|
-- [34] Mensagens WhatsApp por dia (upserts/dia) (north_star) |
|
-- Definição: Volume diario de eventos messages.upsert do WhatsApp, bucketizado no fuso de exibicao (America/Sao_Paulo). E o pulso de atividade do canal WhatsApp. |
|
-- Valor medido: 06-14:190(parcial/inicio), 06-15:1333, 06-16:1512, 06-17:1444, 06-18:2156(pico), 06-19:1772, 06-20:680(PARCIAL ate 18:54). Media dias completos (15-19): ~1643/dia. |
|
-- ✔ Correção verificada: 06-14:190, 06-15:1333, 06-16:1512, 06-17:1444, 06-18:2156, 06-19:1772, 06-20:680(parcial). Total 9087. Exact match. |
|
-- Viz: bar chart diario com ultimo dia hachurado (parcial) | Alvo: manter >= 1500/dia em dias completos | Alerta: < 1000/dia em dia COMPLETO (excluir dia corrente parcial) |
|
SELECT (received_at AT TIME ZONE 'America/Sao_Paulo')::date AS dia, COUNT(*) AS upserts FROM whatsapp_event_logs WHERE type='messages.upsert' GROUP BY 1 ORDER BY 1; |
|
|
|
-- [35] Chats ativos distintos / dia (input) |
|
-- Definição: Numero de chat_jid distintos com ao menos 1 messages.upsert no dia. Mede largura do engajamento entre grupos. |
|
-- Valor medido: 06-14:2, 06-15:6, 06-16:4, 06-17:4, 06-18:4, 06-19:4, 06-20:4. Total distintos no periodo: 6 chats (apenas). |
|
-- ✔ Correção verificada: 06-14:2, 06-15:6, 06-16:4, 06-17:4, 06-18:4, 06-19:4, 06-20:4. 6 distinct total. Exact match. |
|
-- Viz: line chart | Alvo: >= 5 chats ativos/dia | Alerta: <= 2 chats ativos em dia completo |
|
SELECT (received_at AT TIME ZONE 'America/Sao_Paulo')::date AS dia, COUNT(DISTINCT chat_jid) AS chats_ativos FROM whatsapp_event_logs WHERE type='messages.upsert' GROUP BY 1 ORDER BY 1; |
|
|
|
-- [36] Indice de concentracao de chat (HHI / top-chat share) (health) |
|
-- Definição: Percentual de todas as mensagens WhatsApp concentradas no chat lider. Mede risco de dependencia de um unico grupo. |
|
-- Valor medido: Top chat (120363423768795942@g.us): 7955 msgs = 87,5% share. 2o chat: 8,1%. 3o: 2,5%. 4o: 1,8%. Concentracao extrema. |
|
-- ✔ Correção verificada: Top 87.5% (7955/9087), 2nd 8.1%, 3rd 2.5%, 4th 1.8%, plus two chats with 1 msg. Exact match. |
|
-- Viz: stacked bar / treemap por chat | Alvo: < 70% no top chat | Alerta: > 85% no top chat (estado atual: 87,5% - ALERTA) |
|
SELECT chat_jid, COUNT(*) AS msgs, ROUND(100.0*COUNT(*)/SUM(COUNT(*)) OVER (),1) AS pct_share FROM whatsapp_event_logs WHERE type='messages.upsert' GROUP BY 1 ORDER BY msgs DESC; |
|
|
|
-- [37] Taxa de reacao WhatsApp (reactions/upserts) (content) |
|
-- Definição: Razao entre eventos messages.reaction e messages.upsert. Proxy de qualidade/ressonancia do conteudo (mensagens que provocam resposta emocional). |
|
-- Valor medido: Agregado: 12,63% (1148 reactions / 9087 upserts). Por dia: 06-15:8,3% -> 06-18:12,3% -> 06-19:14,1% -> 06-20:14,1%. Tendencia de ALTA. |
|
-- ✔ Correção verificada: Aggregate 12.63% (1148/9087). Per-day 06-15:8.3, 06-16:13.8, 06-17:12.0, 06-18:12.3, 06-19:14.1, 06-20:14.1. Exact match. (Note 06-14:22.6 is a low-volume outlier the finding omitted from the trend narrative.) |
|
-- Viz: line chart com banda de meta | Alvo: >= 12% | Alerta: < 8% por dia completo |
|
SELECT ROUND(100.0*(SELECT COUNT(*) FROM whatsapp_event_logs WHERE type='messages.reaction')/NULLIF((SELECT COUNT(*) FROM whatsapp_event_logs WHERE type='messages.upsert'),0),2) AS reaction_rate_pct; |
|
|
|
-- [38] Variacao liquida de participantes de grupo (business) |
|
-- Definição: Soma diaria de participantes adicionados menos removidos, lendo o payload jsonb (action add/remove, jsonb_array_length(participants)). Crescimento liquido da base de grupos. |
|
-- Valor medido: 06-15:-16, 06-16:+12, 06-17:+2, 06-18:+177(pico onboarding), 06-19:+22, 06-20:+5. Liquido total janela: +202 (278 adds, 76 removes). |
|
-- ✔ Correção verificada: 06-15:-16, 06-16:+12, 06-17:+2, 06-18:+177, 06-19:+22, 06-20:+5. Net +202 (278 adds, 76 removes). Exact match. |
|
-- Viz: diverging bar (verde add / vermelho remove) + linha net | Alvo: net positivo semanal | Alerta: net negativo em 2+ dias completos consecutivos |
|
SELECT (received_at AT TIME ZONE 'America/Sao_Paulo')::date AS dia, SUM(CASE WHEN payload->>'action'='add' THEN jsonb_array_length(payload->'participants') WHEN payload->>'action'='remove' THEN -jsonb_array_length(payload->'participants') ELSE 0 END) AS net FROM whatsapp_event_logs WHERE type='group-participants.update' GROUP BY 1 ORDER BY 1; |
|
|
|
-- [39] Razao de churn de grupo (adds por remove) (health) |
|
-- Definição: Total de adds dividido por total de removes na janela. Mede saude do crescimento: >1 indica entrada superando saida. |
|
-- Valor medido: 3,66 adds por remove (278 adds / 76 removes) na janela de 7 dias. |
|
-- ✔ Correção verificada: 278/76 = 3.66. Exact match. |
|
-- Viz: gauge / big number | Alvo: >= 1.5 | Alerta: < 1.0 (saidas superam entradas) |
|
SELECT ROUND(SUM(CASE WHEN payload->>'action'='add' THEN jsonb_array_length(payload->'participants') ELSE 0 END)::numeric / NULLIF(SUM(CASE WHEN payload->>'action'='remove' THEN jsonb_array_length(payload->'participants') ELSE 0 END),0),2) AS churn_ratio FROM whatsapp_event_logs WHERE type='group-participants.update'; |
|
|
|
-- [40] Atividade horaria WhatsApp (pico de horario) (content) |
|
-- Definição: Distribuicao de messages.upsert por hora do dia no fuso de exibicao. Identifica janelas de maior engajamento para timing de conteudo/anuncios. |
|
-- Valor medido: Pico: 14h(860), 21h(805), 11h(733), 12h(688), 10h(652), 17h(630). Dois picos: comercial (10h-14h) e noite (21h). |
|
-- ✔ Correção verificada: 14h:860, 21h:805, 11h:733, 12h:688, 10h:652, 17h:630. Exact match. |
|
-- Viz: heatmap hora-x-dia ou bar por hora | Alvo: n/a (mapa de calor descritivo) | Alerta: n/a |
|
SELECT EXTRACT(HOUR FROM received_at AT TIME ZONE 'America/Sao_Paulo')::int AS hora, COUNT(*) AS upserts FROM whatsapp_event_logs WHERE type='messages.upsert' GROUP BY 1 ORDER BY 2 DESC; |
|
|
|
-- [41] Volume cross-platform: Discord/WhatsApp na mesma janela 7d (cross_platform) |
|
-- Definição: Razao de mensagens Discord (MESSAGE_CREATE) sobre WhatsApp (messages.upsert) por dia, restrito a janela sobreposta (>= 2026-06-14). Compara peso relativo dos canais. |
|
-- Valor medido: Janela 7d total: WhatsApp 9087 vs Discord 8382 msgs (Discord/WA = 0,92). Por dia dc_per_wa: 06-14:1.8, 06-15:2.7(evento Discord), 06-16:0.5, 06-17:1.4, 06-18:0.3, 06-19:0.5, 06-20:0.2. Apos 06-16 WhatsApp domina o volume diario. |
|
-- ✔ Correção verificada: Per-day dc_per_wa: 06-14:1.8, 06-15:2.7, 06-16:0.5, 06-17:1.4, 06-18:0.3, 06-19:0.5, 06-20:0.2. 7d totals WA 9087 vs Discord 8382 (0.92). Exact match. |
|
-- Viz: grouped bar (WA vs Discord) por dia | Alvo: n/a (monitoramento de mix de canal) | Alerta: n/a |
|
WITH wa AS (SELECT (received_at AT TIME ZONE 'America/Sao_Paulo')::date dia, COUNT(*) FILTER (WHERE type='messages.upsert') m FROM whatsapp_event_logs WHERE received_at >= '2026-06-14 00:00:00-03' GROUP BY 1), dc AS (SELECT (created_at AT TIME ZONE 'America/Sao_Paulo')::date dia, COUNT(*) FILTER (WHERE event_type='MESSAGE_CREATE') m FROM discord_event_logs WHERE created_at >= '2026-06-14 00:00:00-03' GROUP BY 1) SELECT COALESCE(wa.dia,dc.dia) dia, wa.m wa_msgs, dc.m dc_msgs, ROUND(dc.m::numeric/NULLIF(wa.m,0),1) dc_per_wa FROM wa FULL JOIN dc ON wa.dia=dc.dia ORDER BY 1; |
|
|
|
-- [42] Taxa de reacao comparada (WhatsApp vs Discord, mesma janela) (cross_platform) |
|
-- Definição: Reaction rate de cada plataforma na janela sobreposta: WA = messages.reaction/messages.upsert; Discord = MESSAGE_REACTION_ADD/MESSAGE_CREATE. Compara engajamento qualitativo entre canais. |
|
-- Valor medido: WA% vs Discord%: 06-15:8.3/13.7, 06-16:13.8/23.1, 06-17:12.0/15.0, 06-18:12.3/11.9, 06-19:14.1/20.0, 06-20:14.1/8.2. Discord tende a maior taxa de reacao, mas ambos na mesma ordem de grandeza (~12-20%). |
|
-- ✔ Correção verificada: WA/DC: 06-15:8.3/13.7, 06-16:13.8/23.1, 06-17:12.0/15.0, 06-18:12.3/11.9, 06-19:14.1/20.0, 06-20:14.1/8.2. Exact match. (06-14:22.6/6.7 omitted from narrative as low-volume edge.) |
|
-- Viz: dual line chart | Alvo: n/a (benchmark) | Alerta: n/a |
|
WITH wa AS (SELECT (received_at AT TIME ZONE 'America/Sao_Paulo')::date dia, COUNT(*) FILTER (WHERE type='messages.upsert') m, COUNT(*) FILTER (WHERE type='messages.reaction') r FROM whatsapp_event_logs WHERE received_at >= '2026-06-14 00:00:00-03' GROUP BY 1), dc AS (SELECT (created_at AT TIME ZONE 'America/Sao_Paulo')::date dia, COUNT(*) FILTER (WHERE event_type='MESSAGE_CREATE') m, COUNT(*) FILTER (WHERE event_type='MESSAGE_REACTION_ADD') r FROM discord_event_logs WHERE created_at >= '2026-06-14 00:00:00-03' GROUP BY 1) SELECT COALESCE(wa.dia,dc.dia) dia, ROUND(100.0*wa.r/NULLIF(wa.m,0),1) wa_pct, ROUND(100.0*dc.r/NULLIF(dc.m,0),1) dc_pct FROM wa FULL JOIN dc ON wa.dia=dc.dia ORDER BY 1; |
|
|
|
-- [43] Participantes distintos ativos / dia (WhatsApp) (input) |
|
-- Definição: Contagem de remetentes distintos (payload key.participant) que enviaram ao menos 1 mensagem no dia. Mede usuarios ativos reais, nao apenas volume. |
|
-- Valor medido: 06-14:16, 06-15:121, 06-16:114, 06-17:89, 06-18:134, 06-19:106, 06-20:70(parcial). Pico de DAU em 06-18 (134), alinhado ao pico de onboarding (+177 net). |
|
-- ✔ Correção verificada: 06-14:16, 06-15:121, 06-16:114, 06-17:89, 06-18:134, 06-19:106, 06-20:70(parcial). Exact match. |
|
-- Viz: line chart DAU | Alvo: >= 100 DAU/dia | Alerta: < 60 em dia completo |
|
SELECT (received_at AT TIME ZONE 'America/Sao_Paulo')::date AS dia, COUNT(DISTINCT payload->'key'->>'participant') AS participantes FROM whatsapp_event_logs WHERE type='messages.upsert' GROUP BY 1 ORDER BY 1; |
|
|
|
-- ##################################################################### |
|
-- NICHO: Gamificacao e Economia |
|
-- ##################################################################### |
|
|
|
-- [44] Weekly level-ups (gamification liveness) (north_star) |
|
-- Definição: Count of level-up events per ISO week from characters_leveling_logs, bucketed in America/Sao_Paulo. The primary heartbeat of the XP loop. |
|
-- Valor medido: Last level-up ever recorded: 2023-03-14. Monthly shape near the end: 2023-01=1021, 2023-02=392, 2023-03=134, then ZERO. Yearly totals: 2020=89, 2021=1481, 2022=1407, 2023=1547. Current weeks (2026) = 0 level-ups. The loop is dormant, not partial. |
|
-- ✔ Correção verificada: Confirmed. Single AT TIME ZONE (no double-convert). Monthly shape reproduced exactly: 2023-01=1021, 2023-02=392, 2023-03=134, then 0. Last level-up 2023-03-13 23:28 SP (report says 2023-03-14 = the UTC date; SP date is 2023-03-13). Total 4524 logs. Dormant since 2023-03, so 'partial current week' framing is correctly N/A. |
|
-- Viz: Time-series line, partial current bucket flagged | Alvo: >100 level-ups/week when system is live | Alerta: Alert if 0 level-ups for 7+ consecutive days (currently FIRING for ~3 years) |
|
SELECT date_trunc('week', created_at AT TIME ZONE 'America/Sao_Paulo') AS wk, COUNT(*) AS levelups, COUNT(DISTINCT character_id) AS chars FROM characters_leveling_logs GROUP BY 1 ORDER BY 1 DESC LIMIT 12; |
|
|
|
-- [45] XP velocity (median days between level-ups) (input) |
|
-- Definição: Median elapsed days between consecutive level-ups for the same character (LAG over level ordering). Lower = faster progression. Computed over historical transitions only. |
|
-- Valor medido: Median 13.92 days between level-ups, mean 79.5 days (heavy right tail), across 1,638 historical level-up transitions. All transitions are pre-2023-03; no recent velocity. |
|
-- ✔ Correção verificada: Confirmed exactly: median 13.92 days, mean 79.50 days, 1638 transitions. ::numeric cast avoids integer truncation in percentile_cont. PARTITION BY character_id ORDER BY level with created_at>=prev guard is sound. |
|
-- Viz: Big-number (median) + histogram of gap days | Alvo: median 7-14 days (steady progression) | Alerta: Alert if median > 30 days (stalled progression) |
|
WITH paired AS (SELECT character_id, level, created_at, LAG(created_at) OVER (PARTITION BY character_id ORDER BY level) AS prev FROM characters_leveling_logs) SELECT ROUND(AVG(EXTRACT(EPOCH FROM (created_at - prev))/86400.0)::numeric,2) AS avg_days, ROUND(percentile_cont(0.5) WITHIN GROUP (ORDER BY EXTRACT(EPOCH FROM (created_at - prev))/86400.0)::numeric,2) AS median_days, COUNT(*) AS transitions FROM paired WHERE prev IS NOT NULL AND created_at >= prev; |
|
|
|
-- [46] XP concentration (top-1% / top-10% share) (health) |
|
-- Definição: Share of total XP held by the top 1% and top 10% of XP-earning characters. A fairness/health signal; extreme concentration indicates the loop rewards a tiny core. |
|
-- Valor medido: Top 1% of XP-holding characters own 50.60% of all XP; top 10% own 97.11%. Extreme concentration. Of 39,388 characters: 11,492 have 0 XP, 26,604 have <1k, 1,220 have 1k-10k, only 72 have >=10k. |
|
-- ✔ Correção verificada: Confirmed exactly: top 1% = 50.60%, top 10% = 97.11%, over 27896 chars with XP>0. NTILE(100) over experience DESC, 100.0* and NULLIF guard correct. |
|
-- Viz: Lorenz curve / stacked share bar | Alvo: top 10% share < 70% | Alerta: Alert if top 1% share > 40% (currently 50.6%, FIRING) |
|
WITH ranked AS (SELECT experience, NTILE(100) OVER (ORDER BY experience DESC) AS pct FROM characters WHERE experience > 0) SELECT ROUND(100.0*SUM(experience) FILTER (WHERE pct=1)/NULLIF(SUM(experience),0),2) AS top1pct_share, ROUND(100.0*SUM(experience) FILTER (WHERE pct<=10)/NULLIF(SUM(experience),0),2) AS top10pct_share FROM ranked; |
|
|
|
-- [47] Badge claim penetration (content) |
|
-- Definição: Share of characters that have claimed at least one badge. Measures reach of the badge/reward content. |
|
-- Valor medido: 2.21% penetration (872 of 39,388 characters). Only ONE badge exists ('2023 Beta Tester', active=false), all 872 claims happened in a single 21-minute window on 2023-03-14 (03:52-04:13). No badge activity since. |
|
-- ✔ Correção verificada: Confirmed: 2.21% (872/39388). Denominator safe ONLY because every character has at most one badge (verified join_rows=distinct_chars=39388). COUNT(*) on a LEFT JOIN would inflate the denominator if any character ever held multiple badges; with multiple active badges this KPI would silently over-count. Recommend COUNT(DISTINCT c.id) for the denominator to be future-proof. |
|
-- Viz: Gauge + badge leaderboard table | Alvo: >15% penetration with multiple active badges | Alerta: Alert if active badges = 0 (currently 0 active badges, FIRING) |
|
SELECT COUNT(*) AS total_chars, COUNT(DISTINCT cb.character_id) AS chars_with_badge, ROUND(100.0*COUNT(DISTINCT cb.character_id)/NULLIF(COUNT(*),0),2) AS penetration_pct FROM characters c LEFT JOIN characters_badges cb ON cb.character_id=c.id; |
|
|
|
-- [48] Daily-bonus claim adoption (input) |
|
-- Definição: Share of characters that have ever claimed the daily_bonus, plus recency of last claim. Proxy for retention-loop engagement (the only economy-adjacent signal with data). |
|
-- Valor medido: 0.889% adoption (350 of 39,388 characters ever claimed). Last claim 2023-05-20 15:49 (Sao Paulo). No daily-bonus claims in ~3 years. |
|
-- ✔ Correção verificada: Confirmed: 0.889% adoption (350/39388 ever claimed). Single AT TIME ZONE correct. Last claim is 2023-05-20 12:49 SP, NOT 15:49. The report's '15:49 (Sao Paulo)' is the UTC value mislabeled as SP (15:49 UTC = 12:49 SP). Recency conclusion (~3 years stale) unaffected. |
|
-- Viz: Big-number + last-claim recency badge | Alvo: >10% of active characters claim daily | Alerta: Alert if 0 claims in last 7 days (FIRING) |
|
SELECT COUNT(*) AS total_chars, COUNT(*) FILTER (WHERE daily_bonus_claimed_at IS NOT NULL) AS ever_claimed, ROUND(100.0*COUNT(*) FILTER (WHERE daily_bonus_claimed_at IS NOT NULL)/NULLIF(COUNT(*),0),3) AS adoption_pct, MAX(daily_bonus_claimed_at AT TIME ZONE 'America/Sao_Paulo') AS last_claim FROM characters; |
|
|
|
-- [49] Donator conversion rate (business) |
|
-- Definição: Share of users flagged is_donator, both over all users and over users who ever logged in (first_login_at not null). The monetization conversion signal. |
|
-- Valor medido: 41 donators out of 45,723 users = 0.090% overall conversion. Of the 43 users who ever logged in (first_login_at set), 0 are donators (0.00%) — donators and the logged-in cohort are disjoint, suggesting is_donator was backfilled/imported rather than driven by the portal login flow. |
|
-- ✔ Correção verificada: Confirmed exactly: 41 donators / 45723 users = 0.090%; 43 logged-in users (first_login_at not null); 0 of them are donators = 0.00%. Disjoint-set claim verified. NULLIF guards correct. |
|
-- Viz: Funnel (users -> logged-in -> donators) + big-number | Alvo: >1% donator conversion | Alerta: Alert if conversion < 0.5% |
|
SELECT COUNT(*) AS users, COUNT(*) FILTER (WHERE is_donator) AS donators, ROUND(100.0*COUNT(*) FILTER (WHERE is_donator)/NULLIF(COUNT(*),0),3) AS conv_all_pct, COUNT(*) FILTER (WHERE first_login_at IS NOT NULL) AS active_users, ROUND(100.0*COUNT(*) FILTER (WHERE first_login_at IS NOT NULL AND is_donator)/NULLIF(COUNT(*) FILTER (WHERE first_login_at IS NOT NULL),0),2) AS conv_active_pct FROM users; |
|
|
|
-- [50] Coins in circulation (business) |
|
-- Definição: Sum of balances across all character/user wallets. Measures the monetary base of the economy. |
|
-- Valor medido: UNMEASURABLE / 0. wallets table = 0 rows, characters_wallet = 0 rows. No coins exist in the system; the economy ledger was never populated. |
|
-- ✔ Correção verificada: Confirmed: wallets=0 rows, characters_wallet=0 rows. COALESCE(SUM,0) correctly yields 0. Structurally unmeasurable / empty-state, correctly flagged. |
|
-- Viz: Big-number (currently empty-state card) | Alvo: non-zero, growing base once economy launches | Alerta: Alert if 0 wallets exist (FIRING) |
|
SELECT (SELECT COALESCE(SUM(balance),0) FROM wallets) AS wallets_total, (SELECT COALESCE(SUM(balance),0) FROM characters_wallet) AS characters_wallet_total, (SELECT COUNT(*) FROM wallets) AS wallet_rows, (SELECT COUNT(*) FROM characters_wallet) AS char_wallet_rows; |
|
|
|
-- [51] Transaction volume by type (business) |
|
-- Definição: Count and summed amount of transactions grouped by type (earn, spend, daily_bonus, etc.) per week. The core economy throughput metric. |
|
-- Valor medido: UNMEASURABLE / 0. transactions table = 0 rows. No transaction types, no volume. |
|
-- ✔ Correção verificada: Confirmed: transactions=0 rows. Unmeasurable / empty-state, correctly flagged. |
|
-- Viz: Stacked bar by type over time (empty-state card) | Alvo: non-zero once economy launches | Alerta: Alert if 0 transactions in last 7 days (FIRING) |
|
SELECT type, COUNT(*) AS tx, SUM(amount) AS total_amount FROM transactions GROUP BY type ORDER BY tx DESC; |
|
|
|
-- [52] Interaction-driven XP/coin awards (input) |
|
-- Definição: Volume of interactions and XP/coins awarded per week, grouped by interaction type and provider. The upstream input feeding the XP and economy loops. |
|
-- Valor medido: UNMEASURABLE / 0. interactions table = 0 rows. The award ledger that should drive XP velocity and coin emission is empty — confirming the gamification engine is not currently writing events. |
|
-- ✔ Correção verificada: Confirmed: interactions=0 rows. Unmeasurable / empty-state, correctly flagged. |
|
-- Viz: Stacked area by type (empty-state card) | Alvo: non-zero weekly award volume | Alerta: Alert if 0 interactions in last 24h (FIRING) |
|
SELECT type, provider, COUNT(*) AS n, SUM(xp_awarded) AS xp, SUM(coins_awarded) AS coins FROM interactions GROUP BY type, provider ORDER BY n DESC; |
|
|
|
-- [53] Character creation vs activation gap (health) |
|
-- Definição: Characters are still created daily, but XP/level/badge engagement is zero. Tracks the share of characters with any XP vs total, exposing the activation gap between account creation and gamification participation. |
|
-- Valor medido: 70.8% of characters have some XP (27,896 / 39,388) but that XP is legacy; new characters keep arriving (last 2026-06-20 21:37) while 29.2% (11,492) have 0 XP and ZERO recent level-ups exist. Growth in accounts is not converting into gamification activity. |
|
-- ✔ Correção verificada: Confirmed exactly: 70.82% of characters have XP>0 (27896/39388), 29.2% (11492) have 0 XP, last character created 2026-06-20 18:37 SP. Single AT TIME ZONE correct. |
|
-- Viz: Dual-axis: characters created vs level-ups over time | Alvo: >60% of new characters earn XP within 30 days | Alerta: Alert if new-character XP-activation < 20% |
|
SELECT COUNT(*) AS total_chars, COUNT(*) FILTER (WHERE experience > 0) AS chars_with_xp, ROUND(100.0*COUNT(*) FILTER (WHERE experience > 0)/NULLIF(COUNT(*),0),2) AS activation_pct, MAX(created_at) AS last_char_created FROM characters; |
|
|
|
-- ##################################################################### |
|
-- NICHO: Funil de Eventos em Tempo Real (Discord) |
|
-- ##################################################################### |
|
|
|
-- [54] Taxa de Conversão TYPING_START → MESSAGE_CREATE (60s) (north_star) |
|
-- Definição: Of all typing-start events, the % where the same user emits a MESSAGE_CREATE within 60 seconds. Measures intent-to-post follow-through — the core real-time funnel for this niche. |
|
-- Valor medido: 90.61% (29,558 of 32,622 typing events converted to a message within 60s) |
|
-- ✔ Correção verificada: 90.61% (29,558 of 32,622) — matches exactly |
|
-- Viz: Big-number gauge + 7-day trend line | Alvo: > 85% | Alerta: < 75% sustained over a complete day = users typing but not posting (friction, slow channels, or moderation deleting drafts) |
|
WITH typing AS (SELECT user_id, created_at FROM discord_event_logs WHERE event_type='TYPING_START' AND user_id IS NOT NULL), msgs AS (SELECT user_id, created_at FROM discord_event_logs WHERE event_type='MESSAGE_CREATE' AND user_id IS NOT NULL) SELECT COUNT(*) AS typing_events, ROUND(100.0 * COUNT(*) FILTER (WHERE EXISTS (SELECT 1 FROM msgs m WHERE m.user_id=t.user_id AND m.created_at>=t.created_at AND m.created_at<=t.created_at + interval '60 seconds'))/NULLIF(COUNT(*),0),2) AS conversion_pct FROM typing t; |
|
|
|
-- [55] Reações por Mensagem (content) |
|
-- Definição: MESSAGE_REACTION_ADD divided by MESSAGE_CREATE. Proxy for how much content resonates / sparks lightweight engagement. |
|
-- Valor medido: 0.1155 reactions/message (6,644 reactions over 57,529 messages, raw). NOTE: raw msg count inflated by bot channels; human-only ratio is higher (~0.13-0.15 in weeks without the bot firehose). |
|
-- ✔ Correção verificada: 0.1155 (6,644 / 57,529) — matches exactly |
|
-- Viz: Weekly trend line | Alvo: > 0.12 | Alerta: < 0.08 over a complete week = content not landing / passive audience |
|
SELECT ROUND(COUNT(*) FILTER (WHERE event_type='MESSAGE_REACTION_ADD')::numeric / NULLIF(COUNT(*) FILTER (WHERE event_type='MESSAGE_CREATE'),0),4) AS reactions_per_msg FROM discord_event_logs; |
|
|
|
-- [56] Taxa de Edição de Mensagens (MESSAGE_UPDATE/MESSAGE_CREATE) (health) |
|
-- Definição: Fraction of messages that get edited. High values can signal either care (refining posts) or churn (typos, reposts). Tracked as a health/quality signal. |
|
-- Valor medido: 0.2783 (16,009 edits / 57,529 messages). Per-week ranges 0.18 (06-01, bot-inflated denominator) to 0.52 (05-18). |
|
-- ✔ Correção verificada: 0.2783 (16,009 / 57,529) — matches exactly |
|
-- Viz: Weekly trend line with band overlay | Alvo: 0.15 – 0.30 (stable band) | Alerta: Sudden jump > 0.50 = possible edit-spam / bot loop; sudden drop with msg spike = bot flooding the denominator |
|
SELECT ROUND(COUNT(*) FILTER (WHERE event_type='MESSAGE_UPDATE')::numeric / NULLIF(COUNT(*) FILTER (WHERE event_type='MESSAGE_CREATE'),0),4) AS edit_rate FROM discord_event_logs; |
|
|
|
-- [57] Taxa de Deleção de Mensagens (MESSAGE_DELETE/MESSAGE_CREATE) (health) |
|
-- Definição: Fraction of messages deleted. Spikes indicate moderation sweeps, spam removal, or user regret. |
|
-- Valor medido: 0.0063 (362 deletes / 57,529 messages) — very low/healthy |
|
-- ✔ Correção verificada: 0.0063 (362 / 57,529) — matches exactly |
|
-- Viz: Daily trend with anomaly markers | Alvo: < 0.02 | Alerta: > 0.05 over a day = spam wave or mass moderation action — investigate MESSAGE_DELETE_BULK too |
|
SELECT ROUND(COUNT(*) FILTER (WHERE event_type='MESSAGE_DELETE')::numeric / NULLIF(COUNT(*) FILTER (WHERE event_type='MESSAGE_CREATE'),0),4) AS delete_rate FROM discord_event_logs; |
|
|
|
-- [58] Volume de Eventos de Voz (VOICE_STATE_UPDATE) (input) |
|
-- Definição: Count of voice state transitions — proxy for synchronous (voice) engagement volume, a key real-time signal distinct from text. |
|
-- Valor medido: 12,775 total over 32 days (~399/day avg). Evening-skewed: peaks 19h BRT (1,531) and 18h (1,025). |
|
-- ✔ Correção verificada: 12,775 total (~399/day). Hourly peak 19h=1,531; 2nd place is 20h=1,087, NOT 18h. |
|
-- Viz: Daily bar chart + hour-of-day heatmap | Alvo: Maintain > 300/day | Alerta: < 100/day on a complete day = voice channels going quiet |
|
SELECT (created_at AT TIME ZONE 'America/Sao_Paulo')::date AS day_local, COUNT(*) AS voice_events FROM discord_event_logs WHERE event_type='VOICE_STATE_UPDATE' GROUP BY 1 ORDER BY 1 DESC; |
|
|
|
-- [59] Adoção de Slash Commands (usuários distintos & cmds/usuário) (business) |
|
-- Definição: Distinct users issuing slash commands and average commands per user (INTERACTION_CREATE). Measures uptake of the bot's command surface. Actor must be read from payload->member->user->id (user_id column is NULL for these rows). |
|
-- Valor medido: 75 distinct slash users, 240 named-command events, 3.20 commands/user over 32 days |
|
-- ✔ Correção verificada: 75 distinct users, 240 named events, 3.20 cmds/user — matches exactly |
|
-- Viz: Number cards (distinct users, cmds/user) + top-command bar chart | Alvo: Growing distinct users week over week | Alerta: Distinct slash users < 5% of DAU = bot commands undiscovered/underused |
|
SELECT COUNT(DISTINCT COALESCE(payload->'member'->'user'->>'id', payload->'user'->>'id')) AS slash_users, COUNT(*) AS slash_events, ROUND(COUNT(*)::numeric / NULLIF(COUNT(DISTINCT COALESCE(payload->'member'->'user'->>'id', payload->'user'->>'id')),0),2) AS cmds_per_user FROM discord_event_logs WHERE event_type='INTERACTION_CREATE' AND COALESCE(payload->'data'->>'name', payload->>'name') IS NOT NULL; |
|
|
|
-- [60] Top Slash Commands por Volume (business) |
|
-- Definição: Breakdown of which slash commands are actually used (payload->data->name). Drives decisions on which bot features to invest in or deprecate. |
|
-- Valor medido: /apresentar=128 (onboarding, top), /sala=59 (voice room), /editar-perfil=21, /sala-limite=10, /perfil=7, /perguntar=4. (interaction_type=5 'unknown' n=93 are modal submits, type=3 are component interactions.) |
|
-- ✔ Correção verificada: /apresentar=128 (63 users), /sala=59 (14), /editar-perfil=21 (6), /sala-limite=10, /perfil=7, /perguntar=4 — matches. 'unknown'=126 (not 93 as summary narrative stated). |
|
-- Viz: Horizontal bar chart | Alvo: n/a (distribution) | Alerta: Onboarding command (/apresentar) dropping = funnel-top problem |
|
SELECT COALESCE(payload->'data'->>'name', payload->>'name','unknown') AS command_name, COUNT(*) AS cnt, COUNT(DISTINCT COALESCE(payload->'member'->'user'->>'id', payload->'user'->>'id')) AS distinct_users FROM discord_event_logs WHERE event_type='INTERACTION_CREATE' GROUP BY 1 ORDER BY cnt DESC LIMIT 15; |
|
|
|
-- [61] Throughput Horário de Eventos (hora-do-dia, BRT) (input) |
|
-- Definição: Total events bucketed by local hour (America/Sao_Paulo). Identifies peak engagement windows for scheduling events, announcements and moderation staffing. |
|
-- Valor medido: Peak at 22h BRT (17,471 events / 7,456 msgs — ~30% above next hour). Strong block 11h-23h. Trough 06h-07h (~650-900). Voice peaks 19h (1,531). |
|
-- ✔ Correção verificada: Peak 22h BRT = 17,471 events / 7,456 msgs (~30% over 21h=10,405) — matches exactly |
|
-- Viz: 24-bar hour-of-day chart (events + voice overlay) | Alvo: n/a (profile) | Alerta: Flattening of the 22h peak = loss of prime-time engagement |
|
SELECT EXTRACT(HOUR FROM created_at AT TIME ZONE 'America/Sao_Paulo')::int AS hour_local, COUNT(*) AS total_events, COUNT(*) FILTER (WHERE event_type='MESSAGE_CREATE') AS messages, COUNT(*) FILTER (WHERE event_type='VOICE_STATE_UPDATE') AS voice FROM discord_event_logs GROUP BY 1 ORDER BY 1; |
|
|
|
-- [62] Top Canais por Volume de Evento (humano vs bot) (content) |
|
-- Definição: Channels ranked by total events, paired with distinct-user count to separate genuine community channels from single-author bot/webhook firehoses. |
|
-- Valor medido: Top human channel: 853401652471398400 (22,563 events, 812 users). #1 by volume 1455191905523732510 (49,862 events, 424 users). BOT/WEBHOOK firehoses flagged: 1086368144911765647 (15,569 msgs, 1 author), 559224135251656704 (9,282 msgs, 2 authors), 540987396532207638 / 1045804587195576451 (1 author each). |
|
-- ✔ Correção verificada: Bot firehoses confirmed: 1086368144911765647 = 15,569 msgs / 1 author; 559224135251656704 = 9,282 / 2 authors; 540987396532207638 = 1,027 / 1; 1045804587195576451 = 697 / 1. Top human channel 853401652471398400 = 22,563 events / 812 users. |
|
-- Viz: Ranked table with a distinct-users column highlighted; flag rows where authors<=2 | Alvo: n/a (distribution) | Alerta: A new channel appearing with thousands of events and 1 author = misbehaving bot/webhook |
|
SELECT channel_id, COUNT(*) AS total_events, COUNT(*) FILTER (WHERE event_type='MESSAGE_CREATE') AS messages, COUNT(DISTINCT user_id) AS distinct_users FROM discord_event_logs WHERE channel_id IS NOT NULL GROUP BY channel_id ORDER BY total_events DESC LIMIT 15; |
|
|
|
-- [63] Usuários Ativos Diários (DAU) por sinal de evento (health) |
|
-- Definição: Distinct user_id active per local day across text+voice+reaction events. The denominator for normalizing all engagement rates. |
|
-- Valor medido: Recent complete days: 06-19=72, 06-18=139, 06-17=184, 06-15=170, 06-10=195. Today 06-20=38 (PARTIAL day, do not read as a drop). Range ~54-195 DAU. |
|
-- ✔ Correção verificada: Matches: 06-19=72, 06-18=139, 06-17=184, 06-15=170, 06-10=195; today 06-20=38 (PARTIAL). Uses COUNT(DISTINCT user_id) correctly. |
|
-- Viz: Daily line chart with the current (partial) day greyed/striped | Alvo: > 100 on weekdays | Alerta: < 50 on a complete weekday = engagement contraction |
|
SELECT (created_at AT TIME ZONE 'America/Sao_Paulo')::date AS day_local, COUNT(DISTINCT user_id) AS dau, COUNT(*) FILTER (WHERE event_type='MESSAGE_CREATE') AS messages FROM discord_event_logs WHERE created_at >= '2026-05-19' GROUP BY 1 ORDER BY 1 DESC LIMIT 14; |
|
|
|
-- ##################################################################### |
|
-- NICHO: Retencao por Coorte |
|
-- ##################################################################### |
|
|
|
-- [64] Retenção Week-1 (coortes maduras) (north_star) |
|
-- Definição: % de membros de uma coorte semanal (semana da primeira atividade em messages∪voice por external_identity_id) que voltam a estar ativos na semana N+1. Agregado sobre coortes com >=2 semanas decorridas para evitar censura à direita. |
|
-- Valor medido: 21.3% (W1 maduro). W4 maduro = 9.8% |
|
-- ✔ Correção verificada: 21.3% (reproduced exactly) |
|
-- Viz: big number + sparkline | Alvo: 30% | Alerta: < 15% |
|
WITH activity AS (SELECT external_identity_id, sent_at AS ts FROM messages WHERE sent_at >= '2019-01-01' UNION ALL SELECT external_identity_id, occurred_at FROM voice_messages WHERE occurred_at >= '2019-01-01'), weekly AS (SELECT DISTINCT external_identity_id, date_trunc('week',(ts AT TIME ZONE 'America/Sao_Paulo'))::date AS act_week FROM activity), first_week AS (SELECT external_identity_id, MIN(act_week) AS cohort_week FROM weekly GROUP BY 1), pu AS (SELECT DISTINCT w.external_identity_id, fw.cohort_week, (w.act_week-fw.cohort_week)/7 AS week_n FROM weekly w JOIN first_week fw USING(external_identity_id)), cs AS (SELECT cohort_week, COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=0) AS size, COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=1) AS r1 FROM pu GROUP BY 1) SELECT ROUND(100.0*SUM(r1)/NULLIF(SUM(size),0),1) AS w1 FROM cs WHERE cohort_week <= (date_trunc('week', now() AT TIME ZONE 'America/Sao_Paulo')::date - INTERVAL '2 weeks'); |
|
|
|
-- [65] Curva de retenção por coorte (heatmap W0..W8) (health) |
|
-- Definição: Para cada uma das ~12 coortes semanais recentes, % retido em week_n = 1,2,4,8. Triângulo de retenção; células de semanas ainda não decorridas devem aparecer vazias (censura), não como 0%. |
|
-- Valor medido: Ex.: coorte 2026-04-06 (n=59): W1 27.1%, W2 15.3%, W4 6.8%, W8 1.7%. Coorte 2026-05-04 (n=83): W1 30.1%, W2 16.9%, W4 13.3%. Coortes >= 2026-05-25 ainda censuradas em W4/W8. |
|
-- ✔ Correção verificada: Reproduced exactly: 2026-04-06 (n=59) W1 27.1/W2 15.3/W4 6.8/W8 1.7; 2026-05-04 (n=83) W1 30.1/W2 16.9/W4 13.3 |
|
-- Viz: cohort heatmap (triângulo) | Alvo: W4 >= 12% em todas as coortes | Alerta: W1 < 12% em coorte madura |
|
WITH activity AS (SELECT external_identity_id, sent_at AS ts FROM messages WHERE sent_at >= '2019-01-01' UNION ALL SELECT external_identity_id, occurred_at FROM voice_messages WHERE occurred_at >= '2019-01-01'), weekly AS (SELECT external_identity_id, date_trunc('week',(ts AT TIME ZONE 'America/Sao_Paulo'))::date AS act_week FROM activity), first_week AS (SELECT external_identity_id, MIN(act_week) AS cohort_week FROM weekly GROUP BY 1), pw AS (SELECT DISTINCT w.external_identity_id, fw.cohort_week, (w.act_week-fw.cohort_week)/7 AS week_n FROM weekly w JOIN first_week fw USING(external_identity_id)) SELECT cohort_week, COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=0) AS size, ROUND(100.0*COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=1)/NULLIF(COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=0),0),1) AS w1, ROUND(100.0*COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=2)/NULLIF(COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=0),0),1) AS w2, ROUND(100.0*COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=4)/NULLIF(COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=0),0),1) AS w4, ROUND(100.0*COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=8)/NULLIF(COUNT(DISTINCT external_identity_id) FILTER (WHERE week_n=0),0),1) AS w8 FROM pw WHERE cohort_week >= (date_trunc('week', now() AT TIME ZONE 'America/Sao_Paulo')::date - INTERVAL '12 weeks') GROUP BY 1 ORDER BY 1; |
|
|
|
-- [66] Taxa de 'one-and-done' por coorte (health) |
|
-- Definição: % de membros da coorte que ficaram ativos em exatamente 1 semana (a própria semana de origem) e nunca mais. Mede falha de ativação inicial. Coortes recentes são otimisticamente censuradas (parecem piores). |
|
-- Valor medido: Coortes maduras: 2026-03-23 63.4%, 2026-04-27 64.0%, 2026-05-04 56.6%, 2026-04-06 42.4% (melhor). Faixa típica 57-65%. |
|
-- ✔ Correção verificada: Reproduced exactly (2026-03-23=63.4, 2026-04-27=64.0, 2026-05-04=56.6, 2026-04-06=42.4) |
|
-- Viz: bar chart por coorte | Alvo: < 50% | Alerta: > 70% em coorte madura |
|
WITH activity AS (SELECT external_identity_id, sent_at AS ts FROM messages WHERE sent_at >= '2019-01-01' UNION ALL SELECT external_identity_id, occurred_at FROM voice_messages WHERE occurred_at >= '2019-01-01'), weekly AS (SELECT DISTINCT external_identity_id, date_trunc('week',(ts AT TIME ZONE 'America/Sao_Paulo'))::date AS act_week FROM activity), first_week AS (SELECT external_identity_id, MIN(act_week) AS cohort_week FROM weekly GROUP BY 1), spans AS (SELECT w.external_identity_id, fw.cohort_week, COUNT(*) AS active_weeks FROM weekly w JOIN first_week fw USING(external_identity_id) GROUP BY 1,2) SELECT cohort_week, COUNT(*) AS size, ROUND(100.0*COUNT(*) FILTER (WHERE active_weeks=1)/COUNT(*),1) AS pct_one_and_done, ROUND(AVG(active_weeks),2) AS avg_active_weeks FROM spans WHERE cohort_week >= (date_trunc('week', now() AT TIME ZONE 'America/Sao_Paulo')::date - INTERVAL '12 weeks') GROUP BY 1 ORDER BY 1; |
|
|
|
-- [67] Retenção W1 por canal de primeira atividade (text vs voice) (content) |
|
-- Definição: Compara retenção Week-1 entre membros cujo primeiro toque foi texto (messages) vs voz (voice_messages), nas coortes maduras das últimas ~12 semanas. Mostra qual porta de entrada gera vínculo mais durável. |
|
-- Valor medido: text-first: 18.9% (n=243); voice-first: 16.3% (n=698). Voz é canal de entrada dominante em volume, mas texto retém marginalmente mais. |
|
-- ✔ Correção verificada: Reproduced exactly: text 18.9% (n=243), voice 16.3% (n=698) |
|
-- Viz: grouped bar | Alvo: n/a (diagnóstico) | Alerta: gap > 15 p.p. |
|
WITH msg AS (SELECT external_identity_id, MIN(sent_at) AS first_msg FROM messages WHERE sent_at >= '2019-01-01' GROUP BY 1), voi AS (SELECT external_identity_id, MIN(occurred_at) AS first_voi FROM voice_messages WHERE occurred_at >= '2019-01-01' GROUP BY 1), ft AS (SELECT COALESCE(m.external_identity_id,v.external_identity_id) AS eid, LEAST(COALESCE(m.first_msg,'infinity'::timestamptz),COALESCE(v.first_voi,'infinity'::timestamptz)) AS first_ts, CASE WHEN m.first_msg IS NULL THEN 'voice' WHEN v.first_voi IS NULL THEN 'text' WHEN m.first_msg<=v.first_voi THEN 'text' ELSE 'voice' END AS channel FROM msg m FULL OUTER JOIN voi v USING(external_identity_id)), cohort AS (SELECT eid, channel, date_trunc('week', first_ts AT TIME ZONE 'America/Sao_Paulo')::date AS cohort_week FROM ft), activity AS (SELECT external_identity_id, sent_at AS ts FROM messages WHERE sent_at >= '2019-01-01' UNION ALL SELECT external_identity_id, occurred_at FROM voice_messages WHERE occurred_at >= '2019-01-01'), weekly AS (SELECT DISTINCT external_identity_id AS eid, date_trunc('week', ts AT TIME ZONE 'America/Sao_Paulo')::date AS act_week FROM activity), ret AS (SELECT c.channel, c.eid, MAX(CASE WHEN (w.act_week-c.cohort_week)/7=1 THEN 1 ELSE 0 END) AS r1 FROM cohort c JOIN weekly w ON w.eid=c.eid WHERE c.cohort_week BETWEEN (date_trunc('week', now() AT TIME ZONE 'America/Sao_Paulo')::date - INTERVAL '12 weeks') AND (date_trunc('week', now() AT TIME ZONE 'America/Sao_Paulo')::date - INTERVAL '2 weeks') GROUP BY 1,2) SELECT channel, COUNT(*) AS cohort_size, ROUND(100.0*AVG(r1),1) AS w1_retention FROM ret GROUP BY 1 ORDER BY 3 DESC; |
|
|
|
-- [68] Distribuição de canal de aquisição (first-touch) (input) |
|
-- Definição: Para todos os membros históricos com atividade, classifica a primeira atividade como text-only / voice-only / text-first / voice-first. Mostra de onde vêm os novos membros ativos. |
|
-- Valor medido: voice_only 10.732, voice_first 4.909, text_only 4.801, text_first 4.255 — ~70% entram por voz. |
|
-- ✔ Correção verificada: Reproduced exactly: voice_only 10,732; voice_first 4,909; text_only 4,801; text_first 4,255 |
|
-- Viz: donut / stacked bar | Alvo: n/a | Alerta: n/a |
|
WITH msg AS (SELECT external_identity_id, MIN(sent_at) AS first_msg FROM messages WHERE sent_at >= '2019-01-01' GROUP BY 1), voi AS (SELECT external_identity_id, MIN(occurred_at) AS first_voi FROM voice_messages WHERE occurred_at >= '2019-01-01' GROUP BY 1), combined AS (SELECT m.first_msg, v.first_voi FROM msg m FULL OUTER JOIN voi v USING(external_identity_id)) SELECT CASE WHEN first_msg IS NULL THEN 'voice_only' WHEN first_voi IS NULL THEN 'text_only' WHEN first_msg<=first_voi THEN 'text_first' ELSE 'voice_first' END AS first_touch, COUNT(*) AS members FROM combined GROUP BY 1 ORDER BY 2 DESC; |
|
|
|
-- [69] Tamanho de coorte semanal (novos ativos/semana) (input) |
|
-- Definição: Nº de membros distintos cuja PRIMEIRA atividade (messages∪voice) ocorreu naquela semana. É o denominador de todas as taxas de retenção e mede o fluxo de aquisição ativada. |
|
-- Valor medido: Últimas coortes: 2026-04-27=114, 2026-05-04=83, 2026-05-18=109, 2026-06-01=84, 2026-06-08=43, 2026-06-15=41 (PARCIAL). Faixa ~40-160. |
|
-- ✔ Correção verificada: Reproduced exactly (2026-04-27=114, 2026-05-04=83, 2026-05-18=109, 2026-06-01=84, 2026-06-08=43, 2026-06-15=41 partial) |
|
-- Viz: column chart, última barra hachurada (parcial) | Alvo: n/a | Alerta: queda > 40% vs média de 8 semanas (em semana completa) |
|
WITH activity AS (SELECT external_identity_id, sent_at AS ts FROM messages WHERE sent_at >= '2019-01-01' UNION ALL SELECT external_identity_id, occurred_at FROM voice_messages WHERE occurred_at >= '2019-01-01'), weekly AS (SELECT external_identity_id, date_trunc('week',(ts AT TIME ZONE 'America/Sao_Paulo'))::date AS act_week FROM activity), first_week AS (SELECT external_identity_id, MIN(act_week) AS cohort_week FROM weekly GROUP BY 1) SELECT cohort_week, COUNT(*) AS new_active_members FROM first_week WHERE cohort_week >= (date_trunc('week', now() AT TIME ZONE 'America/Sao_Paulo')::date - INTERVAL '12 weeks') GROUP BY 1 ORDER BY 1; |
|
|
|
-- [70] Vida média da coorte (avg semanas ativas) (health) |
|
-- Definição: Média de semanas distintas em que membros de uma coorte estiveram ativos (inclui a semana de origem). Proxy de lifetime/engajamento durável. Coortes recentes subavaliadas por censura. |
|
-- Valor medido: Coortes maduras ~1.7-1.9 semanas (ex.: 2026-04-06=1.92, 2026-05-04=1.77, 2026-03-23=1.78). Mediana = 1 semana em praticamente todas as coortes. |
|
-- ✔ Correção verificada: Reproduced exactly (2026-04-06=1.92, 2026-05-04=1.77, 2026-03-23=1.78; median=1 nearly everywhere) |
|
-- Viz: line por coorte | Alvo: >= 2.5 semanas | Alerta: < 1.4 em coorte madura |
|
WITH activity AS (SELECT external_identity_id, sent_at AS ts FROM messages WHERE sent_at >= '2019-01-01' UNION ALL SELECT external_identity_id, occurred_at FROM voice_messages WHERE occurred_at >= '2019-01-01'), weekly AS (SELECT DISTINCT external_identity_id, date_trunc('week',(ts AT TIME ZONE 'America/Sao_Paulo'))::date AS act_week FROM activity), first_week AS (SELECT external_identity_id, MIN(act_week) AS cohort_week FROM weekly GROUP BY 1), spans AS (SELECT w.external_identity_id, fw.cohort_week, COUNT(*) AS active_weeks FROM weekly w JOIN first_week fw USING(external_identity_id) GROUP BY 1,2) SELECT cohort_week, COUNT(*) AS size, ROUND(AVG(active_weeks),2) AS avg_active_weeks, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY active_weeks) AS median_active_weeks FROM spans WHERE cohort_week >= (date_trunc('week', now() AT TIME ZONE 'America/Sao_Paulo')::date - INTERVAL '12 weeks') GROUP BY 1 ORDER BY 1; |
|
|
|
-- [71] WAU (usuários ativos por semana) — âncora de contexto (health) |
|
-- Definição: Membros distintos ativos (messages∪voice) por semana, últimas 13 semanas. Contextualiza tamanhos de coorte e expõe spikes de evento. Borda esquerda e semana atual são parciais. |
|
-- Valor medido: Picos: 2026-03-23=558 (provável evento), 2026-05-18=430, 2026-04-27=417. Vale recente: 2026-06-08=190, 2026-06-15=186 (PARCIAL). |
|
-- ✔ Correção verificada: Reproduced exactly (2026-03-23=558 spike, 2026-05-18=430, 2026-04-27=417, 2026-06-08=190, 2026-06-15=186 partial) |
|
-- Viz: line chart | Alvo: n/a (tendência) | Alerta: queda sustentada > 30% em semanas completas |
|
WITH activity AS (SELECT external_identity_id, sent_at AS ts FROM messages WHERE sent_at >= '2019-01-01' UNION ALL SELECT external_identity_id, occurred_at FROM voice_messages WHERE occurred_at >= '2019-01-01') SELECT date_trunc('week', ts AT TIME ZONE 'America/Sao_Paulo')::date AS wk, COUNT(DISTINCT external_identity_id) AS wau FROM activity WHERE ts >= (now() - INTERVAL '13 weeks') GROUP BY 1 ORDER BY 1; |
|
|
|
-- [72] Novos membros Discord por semana (joined_at) — INPUT não-linkado (input) |
|
-- Definição: Novos membros por semana via discord_members.joined_at (is_bot=false). É o funil bruto de entrada no servidor. ATENÇÃO: não pode ser cruzado com retenção de atividade porque external_identity_id é 100% NULL em discord_members. |
|
-- Valor medido: 2026-04-27=155, 2026-05-18=219 (pico), 2026-06-08=142, 2026-06-15=122 (parcial). Faixa ~70-220/semana. |
|
-- ✔ Correção verificada: Reproduced exactly (2026-04-27=155, 2026-05-18=219 peak, 2026-06-08=142, 2026-06-15=122 partial) |
|
-- Viz: column chart | Alvo: n/a | Alerta: queda > 40% vs média 8 semanas |
|
SELECT date_trunc('week', joined_at AT TIME ZONE 'America/Sao_Paulo')::date AS join_week, COUNT(*) AS new_members FROM discord_members WHERE is_bot=false AND joined_at IS NOT NULL AND joined_at >= (now() - INTERVAL '13 weeks') GROUP BY 1 ORDER BY 1; |
|
|
|
-- ##################################################################### |
|
-- NICHO: Viralidade e Conteudo |
|
-- ##################################################################### |
|
|
|
-- [73] Avg Reactions per Reacted Message (engagement depth) (north_star) |
|
-- Definição: Mean reactions_total across only messages that received at least one reaction. Measures how strongly the community amplifies content that already resonated. Computed on the valid reaction window (history through 2023; degraded after). |
|
-- Valor medido: 3.869 reactions per reacted message (lifetime); overall avg across ALL messages = 0.0877. 72,131 messages ever reacted, 279,074 total reactions. |
|
-- ✔ Correção verificada: avg-when-reacted = 3.8690 (correct); true overall across all 2019+ messages = 0.0877 (needs separate query, not the duplicated alias) |
|
-- Viz: Big-number stat with sparkline (yearly, since reaction data is not reliable weekly) | Alvo: > 3.5 reactions per reacted message | Alerta: Alert if monthly avg-when-reacted drops below 2.5 (in a window with valid reaction ingestion) |
|
SELECT ROUND(AVG(reactions_total)::numeric,4) AS avg_reactions_when_reacted, ROUND(AVG(reactions_total)::numeric,4) AS overall FROM messages WHERE reactions_total > 0 AND COALESCE(sent_at,created_at) >= '2019-01-01'; |
|
|
|
-- [74] Reaction Rate (% of messages reacted) (input) |
|
-- Definição: Share of messages that received >=1 reaction. Breadth of virality. Must be read per-year because reaction ingestion degraded over time. |
|
-- Valor medido: 2019: 2.25% | 2020: 6.69% | 2021: 1.72% | 2022: 2.05% | 2023: 0.79% | 2024: 0.78% | 2025: 0.77% | 2026: 0.04%. Clear monotonic decay = reaction ingestion gap, NOT real engagement collapse. |
|
-- Viz: Yearly bar chart with an ingestion-gap annotation band over 2024-2026 | Alvo: Baseline ~5-7% (2020 peak); recent values invalid due to ingestion gap | Alerta: Once ingestion is fixed, alert if a full month < 1.5% |
|
SELECT date_trunc('year',(COALESCE(sent_at,created_at) AT TIME ZONE 'America/Sao_Paulo'))::date AS yr, COUNT(*) AS msgs, ROUND(100.0*COUNT(*) FILTER (WHERE reactions_total>0)/COUNT(*),3) AS pct_reacted FROM messages WHERE COALESCE(sent_at,created_at) >= '2019-01-01' GROUP BY 1 ORDER BY 1; |
|
|
|
-- [75] Viral Concentration (top 1% reaction share) (content) |
|
-- Definição: Percentage of all reactions captured by the top 1% most-reacted messages. High value => virality driven by a few breakout posts (announcements, anniversaries) rather than broad engagement. |
|
-- Valor medido: Top 1% of reacted messages (721 msgs) hold 24.30% of all 279,074 reactions (67,824 reactions). Heavy concentration. |
|
-- Viz: Lorenz/concentration curve or single gauge | Alvo: Monitor; 20-30% is typical for community announcements | Alerta: Alert if > 50% (over-reliance on a handful of pinned/announcement posts) |
|
SELECT ROUND(100.0 * SUM(reactions_total) FILTER (WHERE rnk <= GREATEST(1,(cnt/100))) / SUM(reactions_total),2) AS pct_held_by_top1pct FROM (SELECT reactions_total, ROW_NUMBER() OVER (ORDER BY reactions_total * -1) AS rnk, COUNT(*) OVER () AS cnt FROM messages WHERE reactions_total > 0) t; |
|
|
|
-- [76] Viral Content Distribution (reaction buckets) (content) |
|
-- Definição: Histogram of messages by reaction-intensity bucket. Shows the long tail of virality and how many true 'viral' (26+ reactions) posts exist. |
|
-- Valor medido: 0:3,111,480 | 1-2:55,673 | 3-5:8,750 | 6-10:2,850 | 11-25:2,598 | 26+ (viral):2,259. Only 2,259 lifetime 'viral' messages (0.07% of all). |
|
-- Viz: Horizontal bar histogram (log scale) | Alvo: n/a (distribution) | Alerta: Track count of 26+ posts/month once ingestion fixed |
|
SELECT CASE WHEN reactions_total=0 THEN '0' WHEN reactions_total BETWEEN 1 AND 2 THEN '1-2' WHEN reactions_total BETWEEN 3 AND 5 THEN '3-5' WHEN reactions_total BETWEEN 6 AND 10 THEN '6-10' WHEN reactions_total BETWEEN 11 AND 25 THEN '11-25' ELSE '26+' END AS bucket, COUNT(*) AS msgs FROM messages WHERE COALESCE(sent_at,created_at) >= '2019-01-01' GROUP BY 1 ORDER BY MIN(reactions_total); |
|
|
|
-- [77] Top Shared Domains (link virality) (content) |
|
-- Definição: Most-shared external domains from message_embeds.source_domain. Reveals what content the community circulates. Note: only 31,273 of 993,194 embeds carry a source_domain. |
|
-- Valor medido: youtube 19.88% (6,217) | github 11.79% (3,688) | twitter 8.31% (2,599) | tenor 4.99% | rythmbot 4.89% | spotify 4.85% | soundcloud 3.18% | coodesh 3.05% | twitch 1.93% | linkedin 1.21% | stackoverflow 1.02%. Top 3 = ~40% of all classified links. |
|
-- Viz: Horizontal bar / treemap of top 15 domains | Alvo: Track dev-domain share (github+stackoverflow+dev.to+MDN) as a 'learning content' proxy | Alerta: n/a |
|
SELECT source_domain, COUNT(*) AS shares, ROUND(100.0*COUNT(*)/SUM(COUNT(*)) OVER(),2) AS pct FROM message_embeds WHERE source_domain IS NOT NULL AND source_domain <> '' GROUP BY source_domain ORDER BY COUNT(*) * -1 LIMIT 20; |
|
|
|
-- [78] Link Share Rate (% messages with embed) (input) |
|
-- Definição: Share of messages carrying at least one embed (link unfurl). Must be read on the backfill-covered window (through ~Mar 2026); zero afterward is an ingestion artifact. |
|
-- Valor medido: Dec-2025: 20.6% | Jan-2026: 24.0% | Feb-2026: 23.8% | Mar-2026: 30.5% | Apr-2026: 0% | May-2026: 0% | Jun-2026: 0%. ~20-30% link-share is healthy; the 0% from Apr onward is the ETL backfill gap. |
|
-- Viz: Monthly line with ingestion-gap shading on Apr-Jun 2026 | Alvo: 20-30% of messages carry a link | Alerta: Alert if a full month = 0% (signals ETL stopped) once incremental ingestion exists |
|
SELECT date_trunc('month',(COALESCE(m.sent_at,m.created_at) AT TIME ZONE 'America/Sao_Paulo'))::date AS mo, ROUND(100.0*COUNT(DISTINCT e.message_id)/COUNT(*),3) AS pct_link_share FROM messages m LEFT JOIN message_embeds e ON e.message_id=m.id WHERE COALESCE(m.sent_at,m.created_at) >= '2025-12-01' AND COALESCE(m.sent_at,m.created_at) < '2026-06-21' GROUP BY 1 ORDER BY 1; |
|
|
|
-- [79] Media Share Mix (attachment content-type) (content) |
|
-- Definição: Distribution of attachments by top-level MIME class. Profiles what kind of media the community uploads. 70% being text/* signals pasted code/log snippets rather than images. |
|
-- Valor medido: text 70.19% (68,942, avg 0.007MB) | NULL 16.50% (16,208, avg 0.293MB) | image 12.90% (12,675, avg 0.296MB) | video 0.25% (245, avg 7.36MB) | application 0.14% (134) | audio 0.02% (17). text/plain dominates = code/log dumps. |
|
-- Viz: Donut chart of media classes + avg-size annotation | Alvo: n/a (profile) | Alerta: n/a |
|
SELECT split_part(content_type,'/',1) AS media_class, COUNT(*) AS attachments, ROUND(100.0*COUNT(*)/SUM(COUNT(*)) OVER(),2) AS pct, ROUND(AVG(size)/1024.0/1024.0,3) AS avg_mb FROM message_attachments GROUP BY 1 ORDER BY COUNT(*) * -1; |
|
|
|
-- [80] Reaction Rate by Message Kind (content) |
|
-- Definição: Which message types attract reactions. Compares default vs reply vs boost vs system messages. Behavior-changing: informs what content format to encourage. |
|
-- Valor medido: boost: 15.69% reacted (avg 0.62) | reply: 6.72% (avg 0.127) | thread_created: 2.52% | default: 3.04% (avg 0.122) | pin: 0.16%. Boosts and replies are reacted to 2-5x more than the baseline default message. |
|
-- Viz: Grouped bar: pct_reacted by kind | Alvo: n/a (comparative) | Alerta: n/a |
|
SELECT m.kind, COUNT(*) AS msgs, ROUND(100.0*COUNT(*) FILTER (WHERE m.reactions_total>0)/COUNT(*),3) AS pct_reacted, ROUND(AVG(m.reactions_total)::numeric,4) AS avg_react FROM messages m WHERE COALESCE(m.sent_at,m.created_at) >= '2019-01-01' GROUP BY m.kind ORDER BY COUNT(*) * -1 LIMIT 10; |
|
|
|
-- [81] Thread Creation & Archive Health (health) |
|
-- Definição: Number of threads spawned from messages and the share auto-archived. Thread creation is a strong signal of deep, branching conversation (high-quality content). |
|
-- Valor medido: 251 threads total, 248 archived (98.8%), 3 active, avg auto-archive 3,317 min (~2.3 days). Thread usage is extremely rare relative to 3.29M messages (~1 thread per 13,000 messages) and snapshot-only. |
|
-- Viz: Stat cards: total threads, % archived | Alvo: Grow thread creation; current usage is negligible | Alerta: n/a (volume too low to alert) |
|
SELECT COUNT(*) AS total_threads, COUNT(*) FILTER (WHERE archived) AS archived_threads, COUNT(*) FILTER (WHERE NOT archived) AS active_threads, ROUND(100.0*COUNT(*) FILTER (WHERE archived)/COUNT(*),2) AS pct_archived, ROUND(AVG(auto_archive_duration)) AS avg_auto_archive_min FROM message_threads; |
|
|
|
-- [82] Top Emojis (reaction vocabulary) (content) |
|
-- Definição: Most-used reaction emojis from the normalized activity_reactions table. Reveals community sentiment/culture (custom emojis vs unicode). |
|
-- Valor medido: pepeOK 26,638 | he4rt 25,438 | 💤 24,421 | PogChamp 23,167 | linkpepehype 21,613 | ✅ 13,229 | Topkek 7,735 | 🔥 6,655 | peepoLove 6,042 | 👍 5,285. Custom community emojis (pepeOK, he4rt, linkpepehype) outrank unicode — strong in-group culture. |
|
-- Viz: Emoji leaderboard / bar with emoji labels | Alvo: n/a (culture profile) | Alerta: n/a |
|
SELECT emoji_name, COUNT(*) AS rows, SUM(count) AS total_reactions FROM activity_reactions GROUP BY emoji_name ORDER BY SUM(count) * -1 LIMIT 15; |
|
|
|
-- [83] Top Viral Messages (leaderboard) (content) |
|
-- Definição: Highest reactions_total messages of all time. Drives a 'Hall of Fame' card and shows what content format goes viral (announcements, anniversaries, rules). |
|
-- Valor medido: #1: 3,089 reactions (2021-03-11, rules/help post) | #2: 3,062 (2021-03-11, Discord welcome) | #3: 1,258 (2020-06-10) | #4: 1,108 (2021-03-19) | anniversary posts (2022-09-27, 479) and 'bom dia' community posts also rank high. Top virality = pinned announcements + community-moment posts. |
|
-- Viz: Ranked table with message preview + date + reaction count | Alvo: n/a (leaderboard) | Alerta: n/a |
|
SELECT m.id, (m.sent_at AT TIME ZONE 'America/Sao_Paulo')::date AS day_brt, m.reactions_total, m.reactions_count AS distinct_emojis, LEFT(REGEXP_REPLACE(COALESCE(m.content,''),'\s+',' ','g'),50) AS preview FROM messages m WHERE m.reactions_total > 0 ORDER BY m.reactions_total * -1 LIMIT 10; |
|
|
|
-- ##################################################################### |
|
-- NICHO: Meetings e Eventos da Comunidade |
|
-- ##################################################################### |
|
|
|
-- [84] Scheduled events created (window) (north_star) |
|
-- Definição: Distinct Discord GUILD_SCHEDULED_EVENT_* events seen in the ~30-day window. Proxy for the originally-intended 'meetings por mês' KPI while the meetings table is empty. |
|
-- Valor medido: 3 distinct events in 2026-05-19..2026-06-20 (#4 Reunião Semanal, AULÃO: SYSTEM DESIGN, Reunião Delas #4) |
|
-- ✔ Correção verificada: 3 distinct events |
|
-- Viz: big number + sparkline | Alvo: >= 4 events / 30d (>=1 weekly meeting + occasional aulão) | Alerta: 0 events scheduled in a 14-day trailing window |
|
SELECT COUNT(DISTINCT COALESCE(payload #>> '{d,id}', payload #>> '{id}', payload #>> '{guild_scheduled_event_id}', payload #>> '{d,guild_scheduled_event_id}')) AS distinct_events FROM discord_event_logs WHERE event_type LIKE 'GUILD_SCHEDULED_EVENT_%'; |
|
|
|
-- [85] Total RSVP interest signals (input) |
|
-- Definição: Count of GUILD_SCHEDULED_EVENT_USER_ADD events = community members marking interest in attending a scheduled event. |
|
-- Valor medido: 40 RSVP adds |
|
-- ✔ Correção verificada: 40 RSVP adds |
|
-- Viz: big number | Alvo: growth vs prior 30d | Alerta: < 5 RSVPs over a 14-day trailing window |
|
SELECT COUNT(*) AS rsvp_add FROM discord_event_logs WHERE event_type='GUILD_SCHEDULED_EVENT_USER_ADD'; |
|
|
|
-- [86] Unique interested users (input) |
|
-- Definição: Distinct users who RSVP'd to at least one scheduled event. Proxy for 'participantes únicos'. |
|
-- Valor medido: 33 unique interested users |
|
-- ✔ Correção verificada: 33 unique users |
|
-- Viz: big number | Alvo: trend up MoM | Alerta: drop > 40% vs trailing 30d median (excluding partial week) |
|
SELECT COUNT(DISTINCT user_id) AS unique_interested_users FROM discord_event_logs WHERE event_type='GUILD_SCHEDULED_EVENT_USER_ADD' AND user_id IS NOT NULL; |
|
|
|
-- [87] Avg RSVPs per event (interest depth) (business) |
|
-- Definição: Mean number of RSVP adds per distinct scheduled event = how much interest each meeting attracts. Ratio metric, proxy for 'presença média'. |
|
-- Valor medido: 13.33 RSVPs/event (40 adds / 3 events); but bimodal: Reunião Semanal=18, AULÃO=19, Reunião Delas=3 |
|
-- ✔ Correção verificada: 13.33 RSVPs/event |
|
-- Viz: bar per event + avg line | Alvo: >= 15 RSVPs/event | Alerta: avg < 5 RSVPs/event |
|
SELECT ROUND(COUNT(*)::numeric / NULLIF(COUNT(DISTINCT COALESCE(payload #>> '{guild_scheduled_event_id}', payload #>> '{d,guild_scheduled_event_id}')),0),2) AS avg_rsvp_per_event FROM discord_event_logs WHERE event_type='GUILD_SCHEDULED_EVENT_USER_ADD'; |
|
|
|
-- [88] RSVP cancel rate (health) |
|
-- Definição: USER_REMOVE / USER_ADD = share of interest signals later withdrawn. Health/quality signal for event scheduling and reminders. |
|
-- Valor medido: 30.0% (12 removes / 40 adds) |
|
-- ✔ Correção verificada: 30.0% |
|
-- Viz: gauge | Alvo: < 20% | Alerta: > 35% |
|
SELECT ROUND(100.0 * COUNT(*) FILTER (WHERE event_type='GUILD_SCHEDULED_EVENT_USER_REMOVE') / NULLIF(COUNT(*) FILTER (WHERE event_type='GUILD_SCHEDULED_EVENT_USER_ADD'),0),1) AS cancel_rate_pct FROM discord_event_logs WHERE event_type IN ('GUILD_SCHEDULED_EVENT_USER_ADD','GUILD_SCHEDULED_EVENT_USER_REMOVE'); |
|
|
|
-- [89] Repeat RSVP rate (cross-event loyalty) (health) |
|
-- Definição: Share of unique RSVPers who RSVP'd to more than one distinct event. Proxy for 'presença repetida'. |
|
-- Valor medido: 12.1% (4 of 33 users RSVP'd to 2 events; 29 to a single event) |
|
-- ✔ Correção verificada: 12.1% (4 of 33) |
|
-- Viz: donut (1 event vs 2+ events) | Alvo: > 30% | Alerta: < 10% |
|
SELECT ROUND(100.0 * COUNT(*) FILTER (WHERE n_events >= 2) / NULLIF(COUNT(*),0),1) AS repeat_rate_pct FROM (SELECT user_id, COUNT(DISTINCT COALESCE(payload #>> '{guild_scheduled_event_id}', payload #>> '{d,guild_scheduled_event_id}')) AS n_events FROM discord_event_logs WHERE event_type='GUILD_SCHEDULED_EVENT_USER_ADD' AND user_id IS NOT NULL GROUP BY user_id) sub; |
|
|
|
-- [90] Weekly RSVP trend (input) |
|
-- Definição: RSVP adds, removes and unique users bucketed by ISO week in display tz. Trend metric; current week is PARTIAL. |
|
-- Valor medido: 2026-05-18: 8 add/1 rem/7u | 05-25: 9/6/9 | 06-01: 9/4/8 | 06-08: 5/0/4 | 06-15: 9/1/6 (PARTIAL, week not closed). Flat ~8-9 adds/week. |
|
-- ✔ Correção verificada: 2026-05-18:8/1/7 | 05-25:9/6/9 | 06-01:9/4/8 | 06-08:5/0/4 | 06-15:9/1/6 (PARTIAL) |
|
-- Viz: stacked/line chart by week | Alvo: non-declining trailing 4-week avg | Alerta: two consecutive closed weeks below 50% of trailing avg |
|
SELECT to_char(date_trunc('week', created_at AT TIME ZONE 'America/Sao_Paulo'), 'YYYY-MM-DD') AS week_start, COUNT(*) FILTER (WHERE event_type='GUILD_SCHEDULED_EVENT_USER_ADD') AS rsvp_add, COUNT(*) FILTER (WHERE event_type='GUILD_SCHEDULED_EVENT_USER_REMOVE') AS rsvp_remove, COUNT(DISTINCT user_id) FILTER (WHERE event_type='GUILD_SCHEDULED_EVENT_USER_ADD') AS unique_users FROM discord_event_logs WHERE event_type IN ('GUILD_SCHEDULED_EVENT_USER_ADD','GUILD_SCHEDULED_EVENT_USER_REMOVE') GROUP BY 1 ORDER BY 1; |
|
|
|
-- [91] RSVP by day-of-week (content) |
|
-- Definição: Distribution of RSVP adds across weekday in display tz. Proxy for 'presença por week_day' — when interest signals land, informs scheduling. |
|
-- Valor medido: Mon=18, Tue=2, Wed=9, Thu=5, Fri=4, Sat=1, Sun=1 — heavy Monday concentration (45% of RSVPs) |
|
-- ✔ Correção verificada: Mon=18, Tue=2, Wed=9, Thu=5, Fri=4, Sat=1, Sun=1 (Mon=45%) |
|
-- Viz: horizontal bar by weekday | Alvo: informational | Alerta: n/a |
|
SELECT to_char(created_at AT TIME ZONE 'America/Sao_Paulo','ID') AS iso_dow, to_char(created_at AT TIME ZONE 'America/Sao_Paulo','Day') AS day_name, COUNT(*) AS rsvp_add FROM discord_event_logs WHERE event_type='GUILD_SCHEDULED_EVENT_USER_ADD' GROUP BY 1,2 ORDER BY 1; |
|
|
|
-- [92] Per-event RSVP funnel (adds vs removes) (business) |
|
-- Definição: Adds and removes per scheduled event = which events retain committed attendees. Proxy for presença por meeting. |
|
-- Valor medido: AULÃO SYSTEM DESIGN(1499..): 19 add/4 rem (21% cancel) | Reunião Semanal #4(1394..): 18 add/8 rem (44% cancel!) | Reunião Delas #4(1464..): 3 add/0 rem |
|
-- ✔ Correção verificada: 1499..:19/4 | 1394..:18/8 | 1464..:3/0 |
|
-- Viz: grouped bar per event | Alvo: per-event cancel < 20% | Alerta: any event with cancel rate > 40% |
|
SELECT COALESCE(payload #>> '{guild_scheduled_event_id}', payload #>> '{d,guild_scheduled_event_id}') AS event_id, COUNT(*) FILTER (WHERE event_type='GUILD_SCHEDULED_EVENT_USER_ADD') AS adds, COUNT(*) FILTER (WHERE event_type='GUILD_SCHEDULED_EVENT_USER_REMOVE') AS removes FROM discord_event_logs WHERE event_type IN ('GUILD_SCHEDULED_EVENT_USER_ADD','GUILD_SCHEDULED_EVENT_USER_REMOVE') GROUP BY 1 ORDER BY adds DESC; |
|
|
|
-- [93] Legacy meetings table population (data-integrity guard) (health) |
|
-- Definição: Row counts of the canonical meetings tables. If zero, every legacy meeting/season/presença KPI silently returns 0 — this is a pipeline integrity alarm, not a real engagement reading. |
|
-- Valor medido: meetings=0, participants=0, meeting_types=0, season_meeting_count=0 — ALL EMPTY |
|
-- ✔ Correção verificada: meetings=0, participants=0, meeting_types=0, season_meeting_count=0 |
|
-- Viz: status tiles (red if 0) | Alvo: > 0 for all (meetings should accumulate over time) | Alerta: meetings=0 while scheduled-event RSVPs are flowing (current state — FIRING) |
|
SELECT (SELECT COUNT(*) FROM meetings) AS meetings, (SELECT COUNT(*) FROM meeting_participants) AS participants, (SELECT COUNT(*) FROM meeting_types) AS meeting_types, (SELECT COALESCE(SUM(meeting_count),0) FROM seasons) AS season_meeting_count; |
|
|
|
-- ##################################################################### |
|
-- NICHO: Saude de Moderacao (guarda-corpo) |
|
-- ##################################################################### |
|
|
|
-- [94] Acoes de auto-moderacao por dia (health) |
|
-- Definição: Media diaria de execucoes de auto-moderacao do Discord (AUTO_MODERATION_ACTION_EXECUTION) na janela de 30 dias disponivel. Mede a carga que o guarda-corpo automatizado esta absorvendo. |
|
-- Valor medido: 1.50 acoes/dia (45 acoes em 30 dias) |
|
-- ✔ Correção verificada: 1.50/dia se /30 (reproduzido); 1.55/dia se normalizado pelo span real de 29 dias (45/29). Diferenca pequena, escolha de denominador. |
|
-- Viz: big number + sparkline semanal | Alvo: >0 e estavel (sinal de que o automod esta ativo) | Alerta: 0 por >3 dias = automod possivelmente quebrado/desligado |
|
SELECT round(count(*)::numeric / 30, 2) automod_per_day FROM discord_event_logs WHERE event_type='AUTO_MODERATION_ACTION_EXECUTION' AND created_at >= '2026-05-19'; |
|
|
|
-- [95] Bans por dia (health) |
|
-- Definição: Media diaria de GUILD_BAN_ADD na janela de 30 dias. Indicador de pressao de enforcement severo. |
|
-- Valor medido: 1.97 bans/dia (59 bans em 30 dias; 59 usuarios distintos via payload->user->id) |
|
-- ✔ Correção verificada: 1.97/dia se /30 (reproduzido); 2.03/dia se /29 (span real). 59 bans, 59 alvos distintos. |
|
-- Viz: big number + barras por semana | Alvo: baseline historico baixo e estavel | Alerta: spike >3x a media de 7 dias = possivel raid/ataque |
|
SELECT round(count(*)::numeric / 30, 2) bans_per_day FROM discord_event_logs WHERE event_type='GUILD_BAN_ADD' AND created_at >= '2026-05-19'; |
|
|
|
-- [96] Concentracao do auto-mod (acoes por alvo) (health) |
|
-- Definição: Acoes de auto-mod divididas por usuarios-alvo distintos. Alto valor = poucos reincidentes consomem o automod; baixo = problema difuso. |
|
-- Valor medido: 5.63 acoes/alvo (45 acoes em 8 alvos distintos) |
|
-- ✔ Correção verificada: 5.63 acoes/alvo (45 acoes / 8 alvos distintos) — reproduzido exatamente. user_id da coluna esta preenchido aqui (0 NULLs) e bate com o payload. |
|
-- Viz: gauge + tabela top-ofensores | Alvo: proximo de 1.0 (acoes pulverizadas) | Alerta: >5 = reincidencia alta, considerar ban/escalonamento manual |
|
SELECT count(DISTINCT user_id) distinct_targets, count(*) actions, round(count(*)::numeric/NULLIF(count(DISTINCT user_id),0),2) actions_per_target FROM discord_event_logs WHERE event_type='AUTO_MODERATION_ACTION_EXECUTION' AND created_at >= '2026-05-19'; |
|
|
|
-- [97] Acoes de auto-mod por semana (tendencia) (input) |
|
-- Definição: Volume semanal de automod e bans no display tz. Semana atual e PARCIAL. |
|
-- Valor medido: 2026-05-18: automod=8,bans=2 | 05-25: 2,17 | 06-01: 1,9 | 06-08: 8,11 | 06-15(PARCIAL): 26,20 |
|
-- ✔ Correção verificada: 2026-05-18: automod=8,bans=2 | 05-25: 2,17 | 06-01: 1,9 | 06-08: 8,11 | 06-15(PARCIAL): 26,20 — reproduzido exatamente. |
|
-- Viz: linha dupla (automod vs bans), ultima barra hachurada (parcial) | Alvo: estavel; spikes investigados | Alerta: semana completa >3x mediana das 4 anteriores |
|
SELECT date_trunc('week', created_at AT TIME ZONE 'America/Sao_Paulo')::date wk, count(*) FILTER (WHERE event_type='AUTO_MODERATION_ACTION_EXECUTION') automod, count(*) FILTER (WHERE event_type='GUILD_BAN_ADD') bans FROM discord_event_logs WHERE event_type IN ('AUTO_MODERATION_ACTION_EXECUTION','GUILD_BAN_ADD') AND created_at >= '2026-05-19' GROUP BY 1 ORDER BY 1; |
|
|
|
-- [98] Taxa de reversao (unban/ban) (health) |
|
-- Definição: Proporcao de unbans sobre bans no historico de moderation_events. Proxy de falsos-positivos / arrependimento de enforcement. |
|
-- Valor medido: 2.22% (9 unbans / 406 bans) |
|
-- ✔ Correção verificada: 2.22% (9 unbans / 406 bans) — reproduzido exatamente. |
|
-- Viz: big number + meta | Alvo: <5% (poucos bans revertidos = decisoes corretas) | Alerta: >10% = enforcement impreciso / muitos falsos positivos |
|
SELECT count(*) FILTER (WHERE type='ban') bans, count(*) FILTER (WHERE type='unban') unbans, round(count(*) FILTER (WHERE type='unban')::numeric / NULLIF(count(*) FILTER (WHERE type='ban'),0) * 100, 2) reversal_pct FROM moderation_events WHERE occurred_at >= '2019-01-01'; |
|
|
|
-- [99] Cobertura de motivo de moderacao (health) |
|
-- Definição: % de eventos de moderacao que tem reason preenchido. Mede a qualidade do registro (auditabilidade do guarda-corpo). |
|
-- Valor medido: 37.18% (177 de 476 eventos com reason) |
|
-- ✔ Correção verificada: 37.18% (177/476) — reproduzido exatamente. |
|
-- Viz: gauge | Alvo: >90% (toda acao deve ter justificativa) | Alerta: <70% = lacuna de auditabilidade |
|
SELECT round(count(*) FILTER (WHERE reason IS NOT NULL)::numeric / count(*) * 100,2) reason_coverage_pct FROM moderation_events WHERE occurred_at >= '2019-01-01'; |
|
|
|
-- [100] Gatilhos de auto-mod por tipo de regra (content) |
|
-- Definição: Quais regras do Discord automod disparam mais (rule_trigger_type no payload: 3=keyword preset/spam, 1=keyword custom). |
|
-- Valor medido: rule_trigger_type=3: 34 acoes | rule_trigger_type=1: 11 acoes (total 45) |
|
-- ✔ Correção verificada: rule_trigger_type=3: 34 | rule_trigger_type=1: 11 (total 45) — reproduzido exatamente. |
|
-- Viz: barras por tipo de regra | Alvo: n/a (diagnostico) | Alerta: uma regra dominando pode indicar ataque coordenado |
|
SELECT payload->>'rule_trigger_type' rule_type, count(*) n FROM discord_event_logs WHERE event_type='AUTO_MODERATION_ACTION_EXECUTION' AND created_at >= '2026-05-19' GROUP BY 1 ORDER BY 2 DESC; |