feat: analytics dashboards & two-tier feedback system (#78)
* docs: add analytics & user feedback design document Covers team analytics, personal analytics, flow analytics, step-level thumbs up/down feedback, and flow CSAT ratings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add analytics & feedback implementation plan 12-task TDD plan covering session ratings, step feedback, team/personal/flow analytics endpoints, and frontend pages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add session_ratings table and analytics indexes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SessionRating model and analytics schemas Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add session CSAT rating endpoint with tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add step thumbs feedback and /ratings alias routes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add team, personal, and flow analytics endpoints Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add recharts, analytics types, and API client Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add inline step thumbs up/down feedback during sessions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add CSAT rating modal after session completion Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add Team Analytics page with charts and leaderboards Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add Flow Analytics panel with step dropoff and CSAT data Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add My Analytics page with personal stats and charts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit was merged in pull request #78.
This commit is contained in:
111
backend/app/schemas/analytics.py
Normal file
111
backend/app/schemas/analytics.py
Normal file
@@ -0,0 +1,111 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
# --- Session Rating Schemas ---
|
||||
|
||||
class SessionRatingCreate(BaseModel):
|
||||
rating: int = Field(..., ge=1, le=5)
|
||||
comment: Optional[str] = Field(None, max_length=500)
|
||||
|
||||
|
||||
class SessionRatingResponse(BaseModel):
|
||||
id: str
|
||||
session_id: str
|
||||
rating: int
|
||||
comment: Optional[str]
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class FlowRatingItem(BaseModel):
|
||||
"""Anonymous feedback item — no user_name for privacy."""
|
||||
rating: int
|
||||
comment: Optional[str]
|
||||
created_at: datetime
|
||||
|
||||
|
||||
# --- Step Feedback Schema ---
|
||||
|
||||
class StepFeedbackCreate(BaseModel):
|
||||
session_id: str
|
||||
was_helpful: bool
|
||||
|
||||
|
||||
# --- Analytics Response Schemas ---
|
||||
|
||||
class OutcomeBreakdown(BaseModel):
|
||||
resolved: int = 0
|
||||
escalated: int = 0
|
||||
workaround: int = 0
|
||||
unresolved: int = 0
|
||||
|
||||
|
||||
class AnalyticsSummary(BaseModel):
|
||||
total_sessions: int
|
||||
completed_sessions: int
|
||||
completion_rate: float
|
||||
median_duration_minutes: float
|
||||
active_engineers: int = 0
|
||||
outcome_breakdown: OutcomeBreakdown
|
||||
|
||||
|
||||
class TimeSeriesPoint(BaseModel):
|
||||
date: str
|
||||
sessions: int = 0
|
||||
resolved: int = 0
|
||||
escalated: int = 0
|
||||
workaround: int = 0
|
||||
unresolved: int = 0
|
||||
|
||||
|
||||
class TopFlow(BaseModel):
|
||||
tree_id: str
|
||||
name: str
|
||||
sessions: int
|
||||
completion_rate: float
|
||||
median_duration_minutes: float
|
||||
avg_csat: Optional[float] = None
|
||||
|
||||
|
||||
class TopEngineer(BaseModel):
|
||||
user_id: str
|
||||
name: str
|
||||
sessions: int
|
||||
completion_rate: float
|
||||
median_duration_minutes: float
|
||||
|
||||
|
||||
class TeamAnalyticsResponse(BaseModel):
|
||||
summary: AnalyticsSummary
|
||||
time_series: list[TimeSeriesPoint]
|
||||
top_flows: list[TopFlow]
|
||||
top_engineers: list[TopEngineer]
|
||||
|
||||
|
||||
class PersonalAnalyticsResponse(BaseModel):
|
||||
summary: AnalyticsSummary
|
||||
time_series: list[TimeSeriesPoint]
|
||||
top_flows: list[TopFlow]
|
||||
|
||||
|
||||
class StepFeedbackSummary(BaseModel):
|
||||
node_id: str
|
||||
node_title: str
|
||||
helpful_yes: int
|
||||
helpful_no: int
|
||||
helpful_rate: float
|
||||
visit_count: int = 0
|
||||
dropoff_count: int = 0
|
||||
dropoff_rate: float = 0.0
|
||||
|
||||
|
||||
class FlowAnalyticsResponse(BaseModel):
|
||||
summary: AnalyticsSummary
|
||||
avg_csat: Optional[float]
|
||||
total_ratings: int
|
||||
time_series: list[TimeSeriesPoint]
|
||||
step_feedback: list[StepFeedbackSummary]
|
||||
recent_comments: list[FlowRatingItem]
|
||||
Reference in New Issue
Block a user