diff --git a/.changeset/brave-emus-invite.md b/.changeset/brave-emus-invite.md
new file mode 100644
index 0000000000..a845151cc8
--- /dev/null
+++ b/.changeset/brave-emus-invite.md
@@ -0,0 +1,2 @@
+---
+---
diff --git a/server/public/admin-outreach.html b/server/public/admin-outreach.html
index 81c1fb6281..b0ee31d8be 100644
--- a/server/public/admin-outreach.html
+++ b/server/public/admin-outreach.html
@@ -411,6 +411,7 @@
+
+
+
Performance Over Time
+
+
+
Today
+
—
+
0 responded
+
+
+
This Week
+
—
+
0 responded
+
+
+
This Month
+
—
+
0 responded
+
+
+
All Time
+
—
+
0% response rate
+
+
+
+
+
+
+
Response Rates by Goal
+
Loading goal statistics...
+
No outreach data yet.
+
+
+
+ | Goal |
+ Sent |
+ Responded |
+ Response Rate |
+ Insights |
+ Sentiment Breakdown |
+
+
+
+
+
+
+
';
+ context.outreach_history.forEach(outreach => {
+ const date = new Date(outreach.sent_at).toLocaleDateString();
+ const goalName = outreach.goal_name || 'General';
+ const hasResponse = outreach.user_responded;
+ const sentiment = outreach.response_sentiment;
+ const intent = outreach.response_intent;
+
+ // Sentiment badge colors
+ let sentimentBadge = '';
+ if (sentiment) {
+ const colors = {
+ positive: 'background: var(--color-success-100); color: var(--color-success-700);',
+ neutral: 'background: var(--color-gray-100); color: var(--color-gray-700);',
+ negative: 'background: var(--color-warning-100); color: var(--color-warning-700);',
+ refusal: 'background: var(--color-error-100); color: var(--color-error-700);'
+ };
+ sentimentBadge = `
${sentiment}`;
+ }
+
+ // Thread link if available
+ const threadLink = outreach.thread_id
+ ? `
View Thread (${outreach.thread_message_count || 0} msgs)`
+ : '';
+
+ html += `
+
+ ${escapeHtml(goalName)}
+ ${date}
+
+
+ ${hasResponse ? '✓ Responded' : '○ No response'} ${sentimentBadge}
+
+ ${outreach.response_text ? `
"${escapeHtml(outreach.response_text.substring(0, 100))}${outreach.response_text.length > 100 ? '...' : ''}"
` : ''}
+ ${threadLink}
+
`;
+ });
+ html += '
';
+ }
+
+ html += '';
}
// Impersonation Link (if WorkOS user exists)
diff --git a/server/src/db/insights-db.ts b/server/src/db/insights-db.ts
index a35c0022b0..91d75f3956 100644
--- a/server/src/db/insights-db.ts
+++ b/server/src/db/insights-db.ts
@@ -286,6 +286,43 @@ export interface OutreachStats {
insights_gathered: number;
}
+export interface OutreachGoalStats {
+ goal_id: number;
+ goal_name: string;
+ goal_question: string;
+ goal_type: GoalType;
+ is_enabled: boolean;
+ total_sent: number;
+ total_responded: number;
+ total_insights: number;
+ response_rate_pct: number | null;
+ insight_conversion_rate_pct: number | null;
+ positive_responses: number;
+ neutral_responses: number;
+ negative_responses: number;
+ refusal_responses: number;
+ converted_count: number;
+ interested_count: number;
+ deferred_count: number;
+ question_count: number;
+ objection_count: number;
+ first_outreach_at: Date | null;
+ last_outreach_at: Date | null;
+}
+
+export interface OutreachTimeStats {
+ sent_today: number;
+ responded_today: number;
+ sent_this_week: number;
+ responded_this_week: number;
+ sent_this_month: number;
+ responded_this_month: number;
+ total_sent: number;
+ total_responded: number;
+ total_insights: number;
+ overall_response_rate_pct: number | null;
+}
+
// =====================================================
// DATABASE CLASS
// =====================================================
@@ -1155,6 +1192,106 @@ export class InsightsDatabase {
};
}
+ /**
+ * Get outreach response rates broken down by goal
+ */
+ async getOutreachGoalStats(): Promise