Insights — UI Screens
Status: [To Build]
App: apps/dashboard
Auth: Tenant-scoped
Navigation Change
Add to the persistent left sidebar in apps/dashboard/src/app/(dashboard)/layout.tsx:
| Route | Label | Icon | Position |
|---|---|---|---|
/insights | Insights | Sparkles (lucide-react) | After /channels |
Screen I1 — Insights List
Route: /insights
Purpose: Overview of all generated insights across all connected channels for the tenant.
Page Header
- Title: “Insights”
- Subtitle: “AI-powered analysis of your connected channel data”
- Right side: “Last refreshed: {relative time}” + Refresh All button (triggers generation for all connected channels)
Channel Filter Strip
Horizontally scrollable pill buttons:
[ All ] [ GSC ] [ Google Analytics ] [ Google Ads ] [ Meta Ads ] [ Facebook ] [ Instagram ] [ LinkedIn ] [ GBP ]Selecting a pill filters the card grid below.
Insights Card Grid
Responsive grid — 2 columns desktop, 1 column mobile. One card per connected channel, showing the most recent insight.
Insight Card (normal state)
┌──────────────────────────────────────────────────┐
│ [Channel icon] Google Search Console │
│ Last generated: 3 days ago │
│ │
│ ✓ 3 Strengths ✗ 2 Weaknesses │
│ ◆ 4 Opportunities → 5 Recommendations │
│ │
│ [View Insights] [Regenerate] │
└──────────────────────────────────────────────────┘Insight Card (generating state)
┌──────────────────────────────────────────────────┐
│ [Channel icon] Google Analytics │
│ ⟳ Generating insights... │
│ │
│ [────────────] [──────────────] │ ← skeleton bars
│ [─────────────────────────────] │
└──────────────────────────────────────────────────┘Insight Card (failed state)
┌──────────────────────────────────────────────────┐
│ [Channel icon] Google Ads │
│ ⚠ Generation failed │
│ │
│ Could not fetch data from Google Ads. │
│ │
│ [Retry] │
└──────────────────────────────────────────────────┘Insight Card (no insight yet)
┌──────────────────────────────────────────────────┐
│ [Channel icon] LinkedIn │
│ No insights yet │
│ │
│ Generate your first insight to see │
│ AI-powered analysis of this channel. │
│ │
│ [Generate Insights] │
└──────────────────────────────────────────────────┘Empty State (no channels connected)
┌────────────────────────────────────────────────────────┐
│ [Sparkles icon — large] │
│ No channels connected │
│ │
│ Connect a channel to start generating insights │
│ from your marketing data. │
│ │
│ [Connect a Channel →] │
└────────────────────────────────────────────────────────┘The button links to /channels.
Screen I2 — Insight Detail
Route: /insights/[insightId]
Purpose: Full insight report for a single channel and period.
Header
Insights › Google Search Console
[GSC icon] Google Search Console
Period: Last 6 months · Generated: Apr 13, 2026
[Regenerate]Period Selector
Segmented control (top right of content area):
[ 3 months ] [ 6 months ✓ ] [ 12 months ]Changing the period triggers POST /tenant/v1/insights/generate with the new period value. The detail view transitions to the generating skeleton while the new insight is processed.
Insight Sections
Four stacked card groups, each expandable. All items are expanded by default.
Strengths (green accent)
┌── ✓ Strong branded keyword performance ─────────────────────────────┐
│ "acme plumbing" and "acme services" hold positions 1.2 and 1.4 │
│ with CTRs of 18% and 15% — well above the 3% average for │
│ branded terms. │
└──────────────────────────────────────────────────────────────────────┘
┌── ✓ Organic impressions up 22% period-over-period ──────────────────┐
│ ... │
└──────────────────────────────────────────────────────────────────────┘Weaknesses (amber accent)
┌── ✗ High-impression queries with poor CTR ──────────────────────────┐
│ "emergency plumber sydney" receives 4,200 impressions/month │
│ but only a 0.8% CTR from position 7. A meta title update │
│ could double click volume. │
└──────────────────────────────────────────────────────────────────────┘Opportunities (blue accent)
┌── ◆ 12 keywords sitting in positions 4–10 ──────────────────────────┐
│ These are within 1–2 optimisation cycles of page 1. Combined │
│ they represent ~800 additional clicks/month if moved up. │
└──────────────────────────────────────────────────────────────────────┘Recommendations (purple accent, with priority badge)
┌── [HIGH] Update meta title on /services/emergency ─────────────────┐
│ Improve CTR from 0.8% toward the 3% benchmark on │
│ "emergency plumber sydney" (4,200 impressions/month, pos. 7). │
└──────────────────────────────────────────────────────────────────────┘
┌── [MED] Add FAQ schema to top 5 ranking pages ────────────────────┐
│ ... │
└──────────────────────────────────────────────────────────────────────┘
┌── [LOW] Publish a dedicated page for "plumber north sydney" ──────┐
│ ... │
└──────────────────────────────────────────────────────────────────────┘Priority badge colours: HIGH = red, MED = amber, LOW = grey.
Summary Section
Full-width card with a subtle background, rendered as markdown.
┌─ Analyst Summary ────────────────────────────────────────────────────┐
│ │
│ Your Google Search Console performance over the past 6 months │
│ shows strong branded visibility but a clear opportunity in │
│ non-branded local terms... │
│ │
│ [2–4 paragraphs of markdown narrative] │
│ │
└───────────────────────────────────────────────────────────────────────┘Screen I3 — Channel Detail: Insights Tab
Route: /channels/[id] → Insights tab
Purpose: Embeds the latest insight for this specific channel directly within the channel detail view.
Tab Strip Addition
Add “Insights” to the existing tab strip on the channel detail page:
Overview | Analytics | Insights | SettingsTab States
No insight yet:
┌─────────────────────────────────────────────────────────────┐
│ [Sparkles icon] │
│ No insights generated yet │
│ │
│ Get AI-powered analysis of your last 6 months of data. │
│ │
│ [Generate Insights] │
└─────────────────────────────────────────────────────────────┘Generating:
⟳ Generating insights, this may take up to a minute...
[skeleton card rows]Done: Renders the same 4-section card layout as Screen I2 (strengths / weaknesses / opportunities / recommendations + summary), with:
- Period selector (3 / 6 / 12 months) in the top right
- “View full report” link →
/insights/[insightId]
Failed:
⚠ Failed to generate insights
[errorMessage text]
[Retry]Real-Time Updates
When the agent worker emits insight:completed via publishAgentEvent():
- The generating skeleton on Screen I1 and Screen I3 replaces itself with the populated insight cards — no page refresh
- The
generatedAttimestamp on the I1 card updates - Uses the existing Socket.io connection in the dashboard’s
SocketProvider
Event payload delivered to the client:
{
event: "insight:completed",
insightId: string;
connectedChannelId: string;
channelType: string;
status: "done" | "failed";
}The dashboard fetches the full insight by insightId on receipt of this event.