diff --git a/services/frontend/src/app/(dashboard)/dashboard/view.tsx b/services/frontend/src/app/(dashboard)/dashboard/view.tsx
index 7e98c8b7..fe3f4a82 100644
--- a/services/frontend/src/app/(dashboard)/dashboard/view.tsx
+++ b/services/frontend/src/app/(dashboard)/dashboard/view.tsx
@@ -258,6 +258,54 @@ export function DashboardView({
+ {/* Hourly Flow — last-24h message volume by hour */}
+ {activity?.hourly && activity.hourly.length > 0 && (
+
+
+ {activity.hourly.reduce((a, h) => a + h.messages, 0)} MSGS ·{" "}
+ {activity.hourly.reduce((a, h) => a + h.flagged, 0)} FLAGGED
+
+ }
+ />
+
+ {activity.hourly.map((h) => {
+ const max = Math.max(
+ ...activity.hourly.map((x) => x.messages),
+ 1,
+ );
+ const pct = Math.max(4, (h.messages / max) * 100);
+ return (
+
+
+
+ {String(h.hour).padStart(2, "0")}
+
+
+ );
+ })}
+
+
+ 00:00
+ 06:00
+ 12:00
+ 18:00
+ 23:00
+
+
+ )}
+
{/* Top Channels + Engagement Row */}
{/* Top Channels Ranking */}
diff --git a/services/frontend/src/app/(dashboard)/recordings/view.tsx b/services/frontend/src/app/(dashboard)/recordings/view.tsx
index 7cf7c7cd..85d4a5b1 100644
--- a/services/frontend/src/app/(dashboard)/recordings/view.tsx
+++ b/services/frontend/src/app/(dashboard)/recordings/view.tsx
@@ -799,6 +799,9 @@ function Leaderboard({
{s.transcribed > 0 ? `${s.words} words` : "no transcript"}
+
+ {s.last_at ? `active ${formatRelativeTime(s.last_at)}` : "—"}
+
))}
diff --git a/services/frontend/src/app/(dashboard)/voice/view.tsx b/services/frontend/src/app/(dashboard)/voice/view.tsx
index 12319033..a7889b2c 100644
--- a/services/frontend/src/app/(dashboard)/voice/view.tsx
+++ b/services/frontend/src/app/(dashboard)/voice/view.tsx
@@ -1,6 +1,7 @@
"use client";
import {
+ Cable,
Mic,
PhoneOff,
Radio,
@@ -231,6 +232,99 @@ export function VoiceView({
+ {/* Connected Bridges — multi-guild voice bridge roster */}
+
+
+ {status?.connections?.length ?? (connected ? 1 : 0)} ACTIVE
+
+ }
+ />
+
+ {status?.connections && status.connections.length > 0 ? (
+
+ {status.connections.map((conn) => {
+ const isActive =
+ conn.guildId === status.activeGuildId &&
+ conn.channelId === status.activeChannelId;
+ return (
+
+
+
+
+
+
+ {conn.channelName || "#" + conn.channelId.slice(0, 8)}
+
+
+
+ G:{conn.guildId.slice(0, 8)} · C:
+ {conn.channelId.slice(0, 8)}
+
+ {isActive && (
+
+ ACTIVE
+
+ )}
+
+
+
+ {new Date(conn.connectedAt).toLocaleTimeString([], {
+ hour: "2-digit",
+ minute: "2-digit",
+ })}
+
+
+ );
+ })}
+
+ ) : connected ? (
+
+
+
+
+
+
+ {status?.activeChannelName || "Voice channel"}
+
+
+ Active bridge · G:
+ {(status?.activeGuildId ?? guildId ?? "").slice(0, 8)}
+
+
+
+ ACTIVE
+
+
+ ) : (
+
+
+ No active voice bridges
+
+
+ )}
+
+
+
{/* Voice Stage Grid */}