Skip to content

Commit be5d6d0

Browse files
committed
refactor: Improve code comments and log messages for professionalism
- Enhanced API route documentation with detailed descriptions - Improved log messages to be more descriptive and actionable - Added context to error logs (companyId, conversationId, agentId) - Standardized log message format across services - Improved inline comments to explain 'why' not just 'what' - Made comments more professional and comprehensive - Updated analytics API routes with better documentation - Enhanced agent service public routes with detailed comments - Improved OpenAI service logging with better error context
1 parent 0687e93 commit be5d6d0

8 files changed

Lines changed: 359 additions & 141 deletions

File tree

frontend/app/api/analytics/agents/route.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
/**
22
* Analytics Agents API
3-
* Returns agent performance metrics
3+
*
4+
* Provides agent performance metrics including:
5+
* - Conversation count per agent
6+
* - Average response time
7+
* - User satisfaction score
8+
*
9+
* Results are sorted by conversation count (top performers first).
10+
*
11+
* @route GET /api/analytics/agents
412
*/
513

614
import { NextRequest, NextResponse } from 'next/server'
@@ -30,7 +38,10 @@ export async function GET(request: NextRequest) {
3038
.eq('enabled', true)
3139

3240
if (agentsError) {
33-
logger.warn('Failed to fetch agents', { error: agentsError })
41+
logger.warn('Failed to retrieve agent list for analytics', {
42+
error: agentsError.message,
43+
companyId: ctx.companyId,
44+
})
3445
}
3546

3647
if (!agents || agents.length === 0) {
@@ -95,12 +106,14 @@ export async function GET(request: NextRequest) {
95106
? (await messagesResponse.json()).messages || []
96107
: []
97108

98-
// Calculate metrics per agent
109+
// Calculate performance metrics for each agent
99110
const agentMetrics = agents.map((agent) => {
111+
// Filter conversations assigned to this agent
100112
const agentConversations = conversations.filter(
101113
(c: { agent_id: string }) => c.agent_id === agent.id
102114
)
103115

116+
// Filter messages from this agent's conversations
104117
const agentMessages = messages.filter(
105118
(m: { conversation_id: string; sender_type: string; ai_metadata?: { response_time_ms?: number }; metadata?: { sentiment?: { sentiment: string } } }) => {
106119
const conv = conversations.find((c: { _id: string; agent_id: string }) =>
@@ -110,7 +123,7 @@ export async function GET(request: NextRequest) {
110123
}
111124
)
112125

113-
// Calculate average response time
126+
// Calculate average response time from messages with timing metadata
114127
const messagesWithResponseTime = agentMessages.filter(
115128
(m: { ai_metadata?: { response_time_ms?: number } }) => m.ai_metadata?.response_time_ms
116129
)
@@ -125,7 +138,7 @@ export async function GET(request: NextRequest) {
125138
)
126139
: 0
127140

128-
// Calculate satisfaction
141+
// Calculate satisfaction score from sentiment analysis
129142
const messagesWithSentiment = agentMessages.filter(
130143
(m: { metadata?: { sentiment?: { sentiment: string } } }) =>
131144
m.metadata?.sentiment?.sentiment
@@ -151,12 +164,15 @@ export async function GET(request: NextRequest) {
151164
}
152165
})
153166

154-
// Sort by conversation count (top performers first)
167+
// Sort agents by conversation count (descending) to highlight top performers
155168
agentMetrics.sort((a, b) => b.conversationCount - a.conversationCount)
156169

157170
return NextResponse.json({ agents: agentMetrics })
158171
} catch (error) {
159-
logger.error('Analytics agents error', { error })
172+
logger.error('Failed to fetch agent performance analytics', {
173+
error: error instanceof Error ? error.message : String(error),
174+
companyId: ctx.companyId,
175+
})
160176
return NextResponse.json(
161177
{ error: 'Failed to fetch agent analytics' },
162178
{ status: 500 }

frontend/app/api/analytics/conversations/route.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
/**
22
* Analytics Conversations API
3-
* Returns conversation analytics (timeline, by channel, avg duration)
3+
*
4+
* Provides conversation analytics including:
5+
* - Timeline distribution (grouped by day/week/month)
6+
* - Channel distribution (chat, voice, video)
7+
* - Average conversation duration
8+
*
9+
* @route GET /api/analytics/conversations
410
*/
511

612
import { NextRequest, NextResponse } from 'next/server'
@@ -63,52 +69,55 @@ export async function GET(request: NextRequest) {
6369
})
6470
}
6571

66-
// Group conversations by date
72+
// Aggregate conversation metrics
6773
const timelineMap = new Map<string, number>()
6874
const channelMap = new Map<string, number>()
6975
let totalDuration = 0
7076
let conversationsWithDuration = 0
7177

7278
conversations.forEach((conv: { started_at: string; ended_at?: string; channel: string }) => {
73-
// Timeline grouping
79+
// Group conversations by date based on requested granularity
7480
const date = new Date(conv.started_at)
7581
let dateKey: string
7682

7783
if (groupBy === 'week') {
84+
// Calculate week start (Sunday)
7885
const weekStart = new Date(date)
7986
weekStart.setDate(date.getDate() - date.getDay())
8087
dateKey = weekStart.toISOString().split('T')[0]
8188
} else if (groupBy === 'month') {
89+
// Format as YYYY-MM
8290
dateKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`
8391
} else {
92+
// Default: daily grouping
8493
dateKey = date.toISOString().split('T')[0]
8594
}
8695

8796
timelineMap.set(dateKey, (timelineMap.get(dateKey) || 0) + 1)
8897

89-
// Channel grouping
98+
// Aggregate by communication channel
9099
channelMap.set(conv.channel, (channelMap.get(conv.channel) || 0) + 1)
91100

92-
// Calculate duration
101+
// Calculate conversation duration for completed conversations
93102
if (conv.ended_at) {
94103
const duration = new Date(conv.ended_at).getTime() - new Date(conv.started_at).getTime()
95104
totalDuration += duration
96105
conversationsWithDuration++
97106
}
98107
})
99108

100-
// Convert timeline map to array
109+
// Transform timeline map to sorted array for chart rendering
101110
const timeline = Array.from(timelineMap.entries())
102111
.map(([date, count]) => ({ date, count }))
103112
.sort((a, b) => a.date.localeCompare(b.date))
104113

105-
// Convert channel map to array
114+
// Transform channel map to array format
106115
const byChannel = Array.from(channelMap.entries()).map(([channel, count]) => ({
107116
channel,
108117
count,
109118
}))
110119

111-
// Calculate average duration in seconds
120+
// Calculate average conversation duration in seconds
112121
const avgDuration = conversationsWithDuration > 0
113122
? Math.round(totalDuration / conversationsWithDuration / 1000)
114123
: 0
@@ -119,7 +128,10 @@ export async function GET(request: NextRequest) {
119128
avgDuration,
120129
})
121130
} catch (error) {
122-
logger.error('Analytics conversations error', { error })
131+
logger.error('Failed to fetch conversation analytics', {
132+
error: error instanceof Error ? error.message : String(error),
133+
companyId: ctx.companyId,
134+
})
123135
return NextResponse.json(
124136
{ error: 'Failed to fetch conversation analytics' },
125137
{ status: 500 }

frontend/app/api/analytics/costs/route.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
/**
22
* Analytics Costs API
3-
* Returns cost and efficiency metrics
3+
*
4+
* Calculates token usage and estimated costs based on:
5+
* - Total tokens consumed across all messages
6+
* - Model-specific pricing (per 1M tokens)
7+
* - Estimated input/output token distribution (80/20 split)
8+
*
9+
* @route GET /api/analytics/costs
410
*/
511

612
import { NextRequest, NextResponse } from 'next/server'
@@ -9,17 +15,29 @@ import { logger } from '@/lib/utils/logger'
915

1016
const CHAT_SERVICE_URL = process.env.CHAT_SERVICE_URL || 'http://localhost:4004'
1117

12-
// Model pricing (per 1M tokens)
18+
/**
19+
* OpenAI model pricing per 1 million tokens (USD)
20+
* Prices are current as of implementation date and may need periodic updates
21+
*/
1322
const MODEL_PRICING: Record<string, { input: number; output: number }> = {
1423
'gpt-4o-mini': { input: 0.15, output: 0.6 },
1524
'gpt-4-turbo': { input: 10, output: 30 },
1625
'gpt-4': { input: 30, output: 60 },
1726
'gpt-3.5-turbo': { input: 0.5, output: 1.5 },
1827
}
1928

29+
/**
30+
* Calculate estimated cost for token usage
31+
*
32+
* Uses a standard 80/20 input/output token distribution as an approximation
33+
* since individual message token breakdowns are not always available.
34+
*
35+
* @param tokensUsed - Total tokens consumed
36+
* @param model - OpenAI model identifier
37+
* @returns Estimated cost in USD
38+
*/
2039
function calculateCost(tokensUsed: number, model: string): number {
2140
const pricing = MODEL_PRICING[model] || MODEL_PRICING['gpt-4o-mini']
22-
// Assume 80% input, 20% output tokens (rough estimate)
2341
const inputTokens = tokensUsed * 0.8
2442
const outputTokens = tokensUsed * 0.2
2543
return (inputTokens / 1_000_000) * pricing.input + (outputTokens / 1_000_000) * pricing.output
@@ -76,10 +94,13 @@ export async function GET(request: NextRequest) {
7694

7795
return NextResponse.json({
7896
totalTokens,
79-
estimatedCost: Math.round(totalCost * 100) / 100, // Round to 2 decimal places
97+
estimatedCost: Math.round(totalCost * 100) / 100, // Round to 2 decimal places for currency display
8098
})
8199
} catch (error) {
82-
logger.error('Analytics costs error', { error })
100+
logger.error('Failed to calculate cost analytics', {
101+
error: error instanceof Error ? error.message : String(error),
102+
companyId: ctx.companyId,
103+
})
83104
return NextResponse.json(
84105
{ error: 'Failed to fetch cost analytics' },
85106
{ status: 500 }

frontend/app/api/analytics/crm/route.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
/**
22
* Analytics CRM API
3-
* Returns CRM-related analytics
3+
*
4+
* Provides CRM performance metrics including:
5+
* - Contact-to-deal conversion rate
6+
* - Deal pipeline distribution by stage
7+
* - Total deal value by stage
8+
*
9+
* @route GET /api/analytics/crm
410
*/
511

612
import { NextRequest, NextResponse } from 'next/server'
@@ -20,7 +26,7 @@ export async function GET(request: NextRequest) {
2026
const startDate = searchParams.get('startDate')
2127
const endDate = searchParams.get('endDate')
2228

23-
// Build date filter
29+
// Build date-filtered queries for contacts and deals
2430
let contactsQuery = supabase
2531
.from('contacts')
2632
.select('id', { count: 'exact' })
@@ -40,21 +46,28 @@ export async function GET(request: NextRequest) {
4046
dealsQuery = dealsQuery.lte('created_at', endDate)
4147
}
4248

43-
// Get contacts count
49+
// Retrieve contact count
4450
const { count: totalContacts, error: contactsError } = await contactsQuery
4551

4652
if (contactsError) {
47-
logger.warn('Failed to fetch contacts', { error: contactsError })
53+
logger.warn('Failed to retrieve contact count for CRM analytics', {
54+
error: contactsError.message,
55+
companyId: ctx.companyId,
56+
})
4857
}
4958

50-
// Get deals
59+
// Retrieve deal data with stage and value information
5160
const { data: deals, count: totalDeals, error: dealsError } = await dealsQuery
5261

5362
if (dealsError) {
54-
logger.warn('Failed to fetch deals', { error: dealsError })
63+
logger.warn('Failed to retrieve deal data for CRM analytics', {
64+
error: dealsError.message,
65+
companyId: ctx.companyId,
66+
})
5567
}
5668

57-
// Calculate contact-to-deal conversion
69+
// Calculate contact-to-deal conversion rate
70+
// Count unique contacts that have associated deals
5871
const uniqueContactIds = new Set(
5972
(deals || []).map((d: { contact_id?: string }) => d.contact_id).filter(Boolean)
6073
)
@@ -63,7 +76,7 @@ export async function GET(request: NextRequest) {
6376
? Math.round((uniqueContactIds.size / totalContacts) * 100)
6477
: 0
6578

66-
// Calculate deals by stage
79+
// Aggregate deals by stage (count and total value)
6780
const dealsByStageMap = new Map<string, { count: number; value: number }>()
6881
;(deals || []).forEach((deal: { stage: string; value?: number }) => {
6982
const stage = deal.stage || 'lead'
@@ -85,7 +98,10 @@ export async function GET(request: NextRequest) {
8598
dealsByStage,
8699
})
87100
} catch (error) {
88-
logger.error('Analytics CRM error', { error })
101+
logger.error('Failed to fetch CRM analytics', {
102+
error: error instanceof Error ? error.message : String(error),
103+
companyId: ctx.companyId,
104+
})
89105
return NextResponse.json(
90106
{ error: 'Failed to fetch CRM analytics' },
91107
{ status: 500 }

frontend/app/api/analytics/overview/route.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
/**
22
* Analytics Overview API
3-
* Returns key performance indicators
3+
*
4+
* Provides key performance indicators (KPIs) including:
5+
* - Total and active conversation counts
6+
* - Active agent count
7+
* - Average response time
8+
* - User satisfaction score
9+
*
10+
* @route GET /api/analytics/overview
411
*/
512

613
import { NextRequest, NextResponse } from 'next/server'
@@ -52,24 +59,29 @@ export async function GET(request: NextRequest) {
5259
const conversationsData = await conversationsResponse.json()
5360
const conversations = conversationsData.conversations || []
5461

55-
// Calculate metrics
62+
// Calculate conversation metrics
5663
const totalConversations = conversations.length
57-
const activeConversations = conversations.filter((c: { status: string }) => c.status === 'active').length
64+
const activeConversations = conversations.filter(
65+
(c: { status: string }) => c.status === 'active'
66+
).length
5867

59-
// Get active agents from Supabase
68+
// Retrieve active agent count from Supabase
6069
const { data: agents, error: agentsError } = await supabase
6170
.from('agent_configs')
6271
.select('id')
6372
.eq('company_id', ctx.companyId)
6473
.eq('enabled', true)
6574

6675
if (agentsError) {
67-
logger.warn('Failed to fetch agents', { error: agentsError })
76+
logger.warn('Failed to retrieve agent count for analytics', {
77+
error: agentsError.message,
78+
companyId: ctx.companyId,
79+
})
6880
}
6981

7082
const activeAgents = agents?.length || 0
7183

72-
// Fetch messages to calculate response time and satisfaction
84+
// Fetch message data to calculate performance metrics
7385
const messagesResponse = await fetch(
7486
`${CHAT_SERVICE_URL}/api/internal/messages/list`,
7587
{
@@ -94,7 +106,7 @@ export async function GET(request: NextRequest) {
94106
const messagesData = await messagesResponse.json()
95107
const messages = messagesData.messages || []
96108

97-
// Calculate average response time from agent messages
109+
// Calculate average response time from agent messages with timing metadata
98110
const agentMessages = messages.filter(
99111
(m: { sender_type: string; ai_metadata?: { response_time_ms?: number } }) =>
100112
m.sender_type === 'agent' && m.ai_metadata?.response_time_ms
@@ -109,7 +121,7 @@ export async function GET(request: NextRequest) {
109121
avgResponseTime = Math.round(totalResponseTime / agentMessages.length)
110122
}
111123

112-
// Calculate user satisfaction from sentiment
124+
// Calculate user satisfaction percentage from sentiment analysis
113125
const messagesWithSentiment = messages.filter(
114126
(m: { metadata?: { sentiment?: { sentiment: string } } }) =>
115127
m.metadata?.sentiment?.sentiment
@@ -132,7 +144,10 @@ export async function GET(request: NextRequest) {
132144
userSatisfaction,
133145
})
134146
} catch (error) {
135-
logger.error('Analytics overview error', { error })
147+
logger.error('Failed to fetch analytics overview metrics', {
148+
error: error instanceof Error ? error.message : String(error),
149+
companyId: ctx.companyId,
150+
})
136151
return NextResponse.json(
137152
{ error: 'Failed to fetch analytics overview' },
138153
{ status: 500 }

0 commit comments

Comments
 (0)