Files
resolutionflow/backend/alembic/versions/bb2101378a61_phase2_psa_flowpilot_integration.py
chihlasm bbe590bfec feat(ai-session): add Phase 2 PSA integration, escalation handoff, and session management
Phase 2 of the FlowPilot-First Pivot connecting AI sessions to ConnectWise PSA:

Slice 1 — PSA Ticket Intake:
- FlowPilotEngine accepts psa_ticket intake with graceful CW API fallback
- Ticket picker on intake screen (refactored TicketPickerModal for dual-mode)
- Ticket context card in session sidebar

Slice 2 — Auto Documentation Push:
- PSA documentation service with resolution/escalation note formatting
- Time entry creation via new ConnectWise provider method
- Automatic retry scheduler (APScheduler, 5min interval, 3 retries)
- PSA push status indicators in frontend with manual retry button
- Member mapping warning when CW member not mapped

Slice 3 — Session Pause/Resume & Escalation Handoff:
- Pause/resume endpoints for same-engineer session bookmarking
- Escalation flow: requesting_escalation status, self-escalation blocked
- Enhanced escalation package with LLM-generated hypotheses/suggestions
- Pickup endpoint with continue/fresh resume modes and briefing step
- Escalation queue (sidebar nav + dedicated page)
- SessionBriefing component with continue/fresh choice UI
- EscalateModal with PSA-aware button text

Slice 4 — Mid-Session Ticket Linking:
- Link ticket retroactively with context injection into system prompt
- Link Ticket button in session sidebar

Slice 5 — FlowPilot PSA Settings:
- Settings tab on IntegrationsPage with 7 configurable options
- Stored as flowpilot_settings JSONB on PsaConnection

Database: 2 migrations (flowpilot_settings, psa_post_log changes, status constraint)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 01:30:05 +00:00

79 lines
2.5 KiB
Python

"""phase2 psa flowpilot integration
Revision ID: bb2101378a61
Revises: f1a2b3c4d5e6
Create Date: 2026-03-18 23:05:01.099910
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision: str = 'bb2101378a61'
down_revision: Union[str, None] = 'f1a2b3c4d5e6'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# 1. Add flowpilot_settings JSONB to psa_connections
op.add_column('psa_connections', sa.Column(
'flowpilot_settings',
postgresql.JSONB(astext_type=sa.Text()),
nullable=True,
server_default='{}',
comment='FlowPilot-specific settings: auto_push, time_rounding, note_visibility, etc.',
))
# 2. Add ai_session_id FK to psa_post_log
op.add_column('psa_post_log', sa.Column(
'ai_session_id',
sa.Uuid(),
nullable=True,
comment='FK to AI sessions (Phase 2). Original session_id FK remains for legacy sessions.',
))
op.create_index(
op.f('ix_psa_post_log_ai_session_id'),
'psa_post_log',
['ai_session_id'],
)
op.create_foreign_key(
'fk_psa_post_log_ai_session_id',
'psa_post_log',
'ai_sessions',
['ai_session_id'],
['id'],
ondelete='CASCADE',
)
# 3. Make original session_id nullable (was NOT NULL — legacy sessions only)
op.alter_column('psa_post_log', 'session_id', nullable=True)
# 4. Add retry_count and next_retry_at for automatic retries
op.add_column('psa_post_log', sa.Column(
'retry_count',
sa.Integer(),
nullable=False,
server_default='0',
comment='Number of retry attempts for failed PSA pushes',
))
op.add_column('psa_post_log', sa.Column(
'next_retry_at',
sa.DateTime(timezone=True),
nullable=True,
comment='When to attempt the next retry',
))
def downgrade() -> None:
op.drop_column('psa_post_log', 'next_retry_at')
op.drop_column('psa_post_log', 'retry_count')
op.alter_column('psa_post_log', 'session_id', nullable=False)
op.drop_constraint('fk_psa_post_log_ai_session_id', 'psa_post_log', type_='foreignkey')
op.drop_index(op.f('ix_psa_post_log_ai_session_id'), table_name='psa_post_log')
op.drop_column('psa_post_log', 'ai_session_id')
op.drop_column('psa_connections', 'flowpilot_settings')