feat(analytics): add PSA activity logging and enhanced PSA metrics endpoint

- Log `note_posted` and `time_entry_posted` activities to `psa_activity_logs`
  after each successful PSA push in `psa_documentation_service.py`; errors
  are caught and logged without blocking the main push flow
- Add `PsaFunnel`, `PsaDailyTrend`, and `EnhancedPsaMetrics` Pydantic schemas
- Add `GET /analytics/flowpilot/psa-metrics?period=30d` endpoint (team_admin,
  rate-limited 15/min) returning time entry totals, push funnel
  (sessions → linked → doc pushed → time entry logged), and daily trend

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-20 00:11:07 +00:00
parent 7ec626f45a
commit a567d6d245
3 changed files with 173 additions and 0 deletions

View File

@@ -14,6 +14,7 @@ from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.ai_session import AISession
from app.models.psa_activity_log import PsaActivityLog
from app.models.psa_connection import PsaConnection
from app.models.psa_member_mapping import PsaMemberMapping
from app.models.psa_post_log import PsaPostLog
@@ -303,6 +304,7 @@ async def push_documentation(
)
# Create time entry if member mapping exists
time_entry_hours: Optional[float] = None
if member_mapping and session.resolved_at and session.created_at:
try:
delta = session.resolved_at - session.created_at
@@ -316,10 +318,38 @@ async def push_documentation(
hours=rounded_hours,
notes=f"FlowPilot session: {session.problem_summary or 'Troubleshooting'}",
)
time_entry_hours = rounded_hours
except Exception as e:
logger.warning("Failed to create time entry for session %s: %s", session.id, e)
# Don't fail the note push just because time entry failed
# Log PSA activity — note posted
try:
note_activity = PsaActivityLog(
account_id=session.account_id,
session_id=session.id,
activity_type="note_posted",
hours_logged=None,
psa_ticket_id=session.psa_ticket_id,
)
db.add(note_activity)
except Exception as e:
logger.warning("Failed to log PSA note activity for session %s: %s", session.id, e)
# Log time entry activity if one was created
if time_entry_hours is not None:
try:
time_activity = PsaActivityLog(
account_id=session.account_id,
session_id=session.id,
activity_type="time_entry_posted",
hours_logged=time_entry_hours,
psa_ticket_id=session.psa_ticket_id,
)
db.add(time_activity)
except Exception as e:
logger.warning("Failed to log PSA time entry activity for session %s: %s", session.id, e)
# Log success
log_entry = PsaPostLog(
id=uuid.uuid4(),