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:
chihlasm
2026-02-16 15:23:14 -05:00
committed by GitHub
parent 293ceaa9e9
commit bd12ced5ee
29 changed files with 4856 additions and 5 deletions

View File

@@ -0,0 +1,45 @@
"""Add session_ratings table and analytics indexes
Revision ID: 039
Revises: 038
Create Date: 2026-02-16
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import UUID
revision = '039'
down_revision = '038'
def upgrade():
# New session_ratings table for flow CSAT ratings
op.create_table(
'session_ratings',
sa.Column('id', UUID(as_uuid=True), server_default=sa.text('gen_random_uuid()'), primary_key=True),
sa.Column('session_id', UUID(as_uuid=True), sa.ForeignKey('sessions.id', ondelete='CASCADE'), nullable=False),
sa.Column('user_id', UUID(as_uuid=True), sa.ForeignKey('users.id', ondelete='CASCADE'), nullable=False),
sa.Column('tree_id', UUID(as_uuid=True), sa.ForeignKey('trees.id', ondelete='CASCADE'), nullable=False),
sa.Column('account_id', UUID(as_uuid=True), sa.ForeignKey('accounts.id', ondelete='CASCADE'), nullable=False),
sa.Column('rating', sa.Integer, nullable=False),
sa.Column('comment', sa.String(500), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('NOW()'), nullable=False),
sa.CheckConstraint('rating >= 1 AND rating <= 5', name='ck_session_ratings_rating_range'),
sa.UniqueConstraint('session_id', name='uq_session_ratings_session_id'),
)
# Analytics indexes
op.create_index('ix_session_ratings_tree_created', 'session_ratings', ['tree_id', 'created_at'])
op.create_index('ix_session_ratings_account_created', 'session_ratings', ['account_id', 'created_at'])
op.create_index('ix_sessions_completed', 'sessions', ['completed_at'])
op.create_index('ix_step_ratings_step_helpful', 'step_ratings', ['step_id', 'was_helpful'])
# Make step_ratings.rating column nullable (thumbs-only mode)
op.alter_column('step_ratings', 'rating', nullable=True)
def downgrade():
op.alter_column('step_ratings', 'rating', nullable=False)
op.drop_index('ix_step_ratings_step_helpful', 'step_ratings')
op.drop_index('ix_sessions_completed', 'sessions')
op.drop_index('ix_session_ratings_account_created', 'session_ratings')
op.drop_index('ix_session_ratings_tree_created', 'session_ratings')
op.drop_table('session_ratings')