Commit Graph

215 Commits

Author SHA1 Message Date
a7b916116d fix(escalations): fall back to account_id when team_id is null
Users without team_id (solo accounts, pro plans) couldn't see
escalations because the query filtered by team_id which was NULL.
Now falls back to account_id scoping for both the escalation queue
endpoint and the sidebar badge count.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 05:04:47 +00:00
cf23107735 fix(escalations): add sidebar badge count + show all team escalations
- Add escalation_count to sidebar stats (team-wide requesting_escalation)
- Show badge on Escalations nav item in sidebar
- Remove user_id filter from escalation queue — show all team escalations
  including your own (needed for solo users and visibility)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 04:41:27 +00:00
79358be90f fix(escalation): use User.name not display_name — attribute doesn't exist
User model has 'name', not 'display_name'. Fixed in flowpilot_engine
(escalate notify + pickup briefing) and psa_documentation_service
(engineer name in exported docs).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 04:09:54 +00:00
10cf5f45eb refactor: consolidate LLM JSON parsing into shared llm_utils module
Extracted duplicate _strip_markdown_fences / _parse_llm_json functions
from 7 files into app/services/llm_utils.py. Two shared functions:
- strip_markdown_fences(): fence stripping only
- parse_llm_json(): fence stripping + JSON parse + error logging

Files updated: flowpilot_engine, knowledge_flywheel, session_to_flow_service,
ai_tree_generator_service, ai_fix_service, ai_chat_service, kb_conversion_service

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 03:25:25 +00:00
0a77215fac fix(db): widen ai_sessions.status column from varchar(20) to varchar(30)
'requesting_escalation' is 23 characters, exceeding the varchar(20)
limit. This caused a StringDataRightTruncationError 500 on escalate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 01:23:33 +00:00
60334cde93 fix(db): add rollback on exception in get_db dependency
Prevents InFailedSQLTransaction cascade — when a request fails mid-
transaction, the connection is rolled back before being returned to
the pool, so subsequent requests on the same connection don't inherit
a poisoned transaction state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 01:10:07 +00:00
6122dda71d fix(flowpilot): extract _build_session_detail helper, fix link_ticket 500
The same model_validate bug existed in link_ticket endpoint (line 467).
Extracted the manual AISessionDetail construction into a shared helper
_build_session_detail() used by both get_session and link_ticket.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 06:28:11 +00:00
0118b80b63 fix(flowpilot): fix session detail 500 — build AISessionDetail manually
Root cause: AISessionDetail.model_validate(session) tried to validate the
ORM relationship 'steps' which has field 'id', but AISessionStepResponse
expects 'step_id'. This caused a Pydantic ValidationError on every session
detail load.

Fix: Construct AISessionDetail manually from ORM fields, passing the
already-built step_responses list directly instead of relying on
model_validate to serialize the ORM steps relationship.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 06:25:57 +00:00
5eeff0c83a debug: add detailed error reporting for session detail serialization
Temporary debug commit — surfaces the actual exception when GET /ai-sessions/{id}
fails with 500, instead of generic "Internal server error" from middleware.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 06:20:27 +00:00
7518fe643b fix(cors): return proper responses from middleware instead of re-raising
Root cause: Both RequestLoggingMiddleware and ErrorLoggingMiddleware used
BaseHTTPMiddleware and re-raised exceptions. When an exception (like a 401
from auth) was re-raised, the response never flowed back through
CORSMiddleware, so browsers received error responses without CORS headers.
This made 401 errors appear as CORS errors, breaking session resume and
other operations after token expiry.

Fix: Both middlewares now catch exceptions and return JSONResponse objects
(with correct status codes from HTTPException) instead of re-raising. This
ensures responses always flow through CORSMiddleware and receive proper
Access-Control-Allow-Origin headers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 06:05:20 +00:00
eed771cb27 fix: prevent InFailedSQLTransactionError in session creation
Root cause: embedding generation could break the DB transaction via a failed
SQL statement. The except block caught the Python error but left the transaction
in a failed state. Subsequent queries (_record_usage → subscription lookup)
then failed with InFailedSQLTransactionError.

Fixes:
- session_embedding_service: use begin_nested() savepoint so failures don't
  poison the parent transaction
- ai_sessions.py: add db.rollback() before _record_usage in all 3 error
  handlers (create, respond, pickup) to recover from broken transactions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 04:36:12 +00:00
2ed8a2af15 fix: 6 integration audit fixes — ticket filter, admin nav, FK scope, debounce, error messages
- Fix AISession.ticket_id → psa_ticket_id in list_sessions filter query
- Add Gallery nav item (LayoutGrid icon) to AdminSidebar navItems array
- Remove ForeignKey from FileUpload.session_id (Python model) + migration b8d2f4a6c091 to drop DB constraint, allowing column to reference either session type
- Add 400ms debounce on AI session search input in SessionHistoryPage (aiSearchInput state + useRef timeout pattern)
- Show friendly 503 error message in RichTextInput upload error handler (both initial upload and retry paths)
- Add overflow-x-auto to FlowPilotAnalyticsPage tab bar container

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 04:06:41 +00:00
e356103408 feat(search): add semantic similar session matching via Voyage AI embeddings
Adds vector-based similar session discovery using the existing Voyage AI
embedding infrastructure and pgvector cosine similarity search.

- New AISessionEmbedding model with vector(1024) column
- session_embedding_service: generate + upsert embeddings, find similar sessions
- Embeddings generated on session create (from problem_summary/domain) and
  updated on resolve (adds resolution_summary)
- GET /ai-sessions/{id}/similar endpoint returns top-N similar sessions
- Migration a7c9e3b1f402 creates ai_session_embeddings table

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 03:48:09 +00:00
ce68fa84ca feat(search): add PostgreSQL FTS on AI sessions with Command Palette integration
- Migration: add generated tsvector column + GIN index on ai_sessions (problem_summary, resolution_summary, escalation_reason, problem_domain)
- Backend: wire FTS into list_sessions q param; add GET /ai-sessions/search endpoint returning AISessionSearchResult (registered before /{session_id} to avoid UUID routing conflict)
- Frontend: add AISessionSearchResult type, aiSessionsApi.search() method, and Command Palette group "FlowPilot Sessions" using Zap icon navigating to /pilot/:id

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 03:42:01 +00:00
c3afc7a059 feat(search): add structured filters to AI session list endpoint and frontend
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 03:34:54 +00:00
241ea1e458 feat(evidence): add file upload/download API endpoints with tests
- POST /uploads: multipart upload with content-type/size validation, per-session limits, S3 storage
- GET /uploads/{id}/url: presigned download URL with account ownership check
- GET /uploads: list uploads for a session
- DELETE /uploads/{id}: delete with ownership enforcement (403 for non-owners)
- Returns 503 gracefully when STORAGE_ENDPOINT is not configured
- 15 integration tests covering auth, validation, 503 behavior, and ownership

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 03:22:52 +00:00
c7d602cfa5 feat(evidence): add S3 storage service and file_uploads model
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 03:15:37 +00:00
acf98d3a01 test(analytics): add PSA metrics endpoint tests — funnel, time entries, daily trend
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 01:06:30 +00:00
94fbb38f84 fix(analytics): fix 6 backend audit issues — domain matching, funnel counts, decimal casts, dead queries
- Issue 1: Normalize domain lookup to lowercase on both sides (flow category names and session problem_domain) to fix case-sensitive mismatch in coverage endpoint
- Issue 2: Count distinct ai_session_id (not PsaPostLog.id) in doc_pushed funnel step to avoid inflating counts on retried sessions
- Issue 3: Clamp recency_score to [0.0, 1.0] with min/max to handle negative days_since from future timestamps (clock skew/test data)
- Issue 4: Wrap func.sum(case(...)) results with int() in dashboard endpoint to handle Decimal returns from asyncpg
- Issue 5: Remove dead domain_flow_counts_result query (result fetched but never consumed) to eliminate unnecessary DB round-trip
- Issue 6: Replace select(Tree) with select(Tree.id, Tree.name, Tree.tree_type) in flow-quality endpoint to avoid loading large tree_structure JSONB column

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 00:36:30 +00:00
ae51e6e83c feat(analytics): wire flow usage tracking into session matching and resolution
- In `start_session`: increment `flow.usage_count` and set `flow.last_matched_at`
  when a flow is matched to a new session; errors are caught without blocking
- In `resolve_session`: recalculate `flow.success_rate` as (resolved / total)
  across all sessions ever matched to the flow after each resolution; errors
  are caught without blocking the session close

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 00:11:12 +00:00
a567d6d245 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>
2026-03-20 00:11:07 +00:00
7ec626f45a feat(analytics): add coverage heatmap and flow quality scoring endpoints
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 00:08:09 +00:00
779b29dbc4 feat(analytics): add flow tracking columns and psa_activity_logs table
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 00:00:34 +00:00
a404fb13ed feat(enterprise): add SSO/SAML groundwork — model columns and stub service
- Add sso_enabled, sso_provider, sso_config (JSONB) columns to Account model
  (migration included in branding commit 58e3f27f3e8f)
- Create sso_service.py stub with initiate_sso_login, process_sso_callback,
  validate_sso_config — all raise NotImplementedError (Phase 5)
- Add GET /accounts/me/sso endpoint returning enabled status and provider
- Add SSO section in AccountSettingsPage with Enterprise badge and Contact Us link

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:35:45 +00:00
21d6d09c05 feat(enterprise): add multi-PSA adapter stubs for Autotask and Halo PSA
- Create AutotaskProvider stub with all abstract methods raising NotImplementedError
- Create HaloPSAProvider stub with all abstract methods raising NotImplementedError
- Add PSA provider grid in IntegrationsPage showing ConnectWise (active),
  Autotask (Coming Soon), and Halo PSA (Coming Soon) with appropriate badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:35:39 +00:00
2f56327f81 feat(enterprise): add custom branding system — logo, accent color, company name
- Add branding_logo_url, branding_primary_color, branding_company_name columns to Account model
- Add Alembic migration (58e3f27f3e8f) for branding and SSO columns
- Add GET/PATCH /accounts/me/branding endpoints (owner-only for PATCH)
- Add BrandingSettingsPage with logo URL input, color picker, preview section
- Add /account/branding route (ProtectedRoute owner) in router.tsx
- Add Branding link card in AccountSettingsPage

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:35:35 +00:00
967a2b2c59 feat(export): add branding footer to all 5 export formats and PDF spinner
- Add "Generated with ResolutionFlow — https://resolutionflow.com" footer
  to markdown, text, HTML, PSA formats (both troubleshooting and procedural
  variants — 8 generators total)
- Fix PDF @page CSS: "Powered by ResolutionFlow" now appears on every PDF,
  not just for users with a custom logo (removed the has_custom_logo conditional)
- Add Loader2 spinner icon to PDF download button in ExportPreviewModal
  when pdfLoading is true, replacing the static Download icon

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:09:26 +00:00
12a373a2a2 feat(gallery): add admin gallery curation endpoints and management page (Task 6)
Add super-admin-only backend endpoints for toggling is_gallery_featured and
gallery_sort_order on flows and scripts, plus a frontend GalleryManagementPage
with toggle switches, editable sort order fields, and name/featured filters.
13 integration tests; all pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:04:40 +00:00
bacdb9d466 feat(public-gallery): add public templates gallery API (Tasks 2 & 3)
Implements a no-auth read-only API for the public templates gallery page:
- Schemas in schemas/public_templates.py (PublicFlowTemplate, PublicScriptTemplate, PublicGalleryResponse, PublicFlowDetail, PublicScriptDetail)
- Five endpoints under /api/v1/public/templates: listing, flow detail, script detail, categories with counts, full-text search
- Tree preview truncated to 3 levels max; script_body never exposed
- Rate limited at 30/minute; paginated with category/type/sort filters
- 25 passing integration tests covering feature flags, truncation, script body protection, search, categories, and 404 behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 19:12:34 +00:00
836a014a0f feat(gallery): add is_gallery_featured and gallery_sort_order columns to trees and script_templates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 19:08:06 +00:00
0f750e63e0 feat(notifications): add Phase 4 Slice 2 — multi-channel notification system
Full notification infrastructure with in-app, email, Slack, and Teams channels:

Backend:
- NotificationConfig, NotificationLog, Notification models + migration
- Notification service with event routing, channel delivery, retry logic
- 9 API endpoints (config CRUD + in-app notifications)
- APScheduler retry job with exponential backoff (30s, 2m, 10m)
- Wired into escalation, proposal approval, and knowledge flywheel
- Pydantic event key validation, cross-tenant protection on recipients

Frontend:
- TypeScript types + API client for all notification endpoints
- NotificationsPanel: bell icon with unread badge, dropdown, mark-read
- NotificationSettings: channel config, event toggles, test, delete confirm
- Notifications tab on IntegrationsPage
- ARIA attributes, Escape handler, settings link on panel

Review fixes (13 issues resolved):
- notify() no longer commits/rolls back caller's transaction (critical)
- retry_failed_notifications returns count instead of None (critical)
- NotificationSettings moved inside dedicated tab (critical)
- target_user_ids scoped by account_id (security)
- Email loop collects all failures before raising
- Slack webhook validates response body
- events_enabled rejects unknown event keys
- link column widened to String(500)
- Dead code removed from _auto_reinforce
- Delete confirmation, ARIA, Escape key support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:37:54 +00:00
9bad49d568 feat(knowledge-flywheel): add Phase 3 Knowledge Flywheel — AI analysis, review queue, analytics
Phase 3 implementation:
- AI session analysis service that generates flow proposals from resolved sessions
- APScheduler job for batch processing pending analyses (max_instances=1)
- Knowledge gap detection (weak options, high escalation signals)
- Flow proposals CRUD with team admin review workflow (approve/edit/dismiss/reject)
- FlowPilot analytics dashboard with confidence tiers, PSA metrics, knowledge gaps
- In-session script generator component
- Review queue page with filtering and proposal detail panel

Bug fixes from review (12 total):
- Fix "Edit & Publish" navigating to non-existent /editor/new route
- Hide Approve button for enhancement proposals (require Edit & Publish)
- Add max_instances=1 to scheduler to prevent TOCTOU race
- Fix eventual_success case() double-counting failed retries
- Add tree_structure validation before creating tree from proposal
- Simplify script generator rendering condition
- Add severity style fallback, toFixed on rates, Link instead of <a href>
- Add toast.warning on dismiss failure, fix dedup for domain-less sessions
- Cast Decimal to int in knowledge gap evidence dicts

Also updates CLAUDE.md with lessons 67-71 and Phase 3 project structure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 05:12:10 +00:00
ce118b51d8 fix(flowpilot): fix 4 Phase 2 escalation bugs + update Tailwind version in CLAUDE.md
- Fix escalation status mismatch: hook set 'escalated' but backend returns
  'requesting_escalation'
- Fix list_sessions to include sessions picked up by Engineer B via
  escalation_package->>'picked_up_by' JSONB query
- Fix sidebar escalation icon color: was Tailwind class 'text-amber-400'
  passed to style={{color}}, now hex '#fbbf24'
- Replace window.location.reload() after ticket linking with
  onReloadSession callback to preserve session state
- Update CLAUDE.md: Tailwind CSS v3 → v4 (@tailwindcss/vite, CSS-only config)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 03:10:11 +00:00
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
5494816b06 feat(ai-session): add FlowPilot AI-powered troubleshooting sessions
Implements Phase 1 of the FlowPilot-First pivot — the core AI session
experience where engineers describe a problem and FlowPilot guides them
through structured diagnosis with selectable options, free-text escape
hatches, and auto-generated documentation on resolution.

Backend: AISession + AISessionStep models, FlowPilot Engine (LLM
orchestration with structured JSON output), Flow Matching Engine v1
(semantic + keyword + recency scoring), 8 API endpoints with auth,
rate limiting, and AI quota enforcement.

Frontend: Intake screen, conversational session view with sidebar,
step cards with options/actions/resolution suggestions, resolve/escalate
modals, documentation view with rating, session history integration,
and /pilot route with sidebar navigation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 14:27:36 +00:00
2f18056fd1 feat: add security headers middleware with report-only CSP
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:38:42 +00:00
chihlasm
2234594363 fix: use correct package name for gdk-pixbuf in Debian Trixie
libgdk-pixbuf2.0-dev was renamed to libgdk-pixbuf-2.0-dev in Trixie
(python:3.12-slim base image).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 02:22:58 -04:00
chihlasm
2339787499 feat: add supporting data capture, PDF export, and branding settings UI
- API clients for supporting data CRUD and team branding
- AddSupportingDataModal with text snippet and screenshot tabs (paste + upload)
- SupportingDataPanel collapsible section integrated into both session runners
- ExportPreviewModal updated with PDF format and server-side download flow
- BrandingSettings component for company name and logo management
- Expose team_id in UserResponse schema for branding endpoint access

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 02:03:40 -04:00
chihlasm
f7271e22ae feat: include supporting data in all export formats
Query supporting data in the export endpoint and pass to markdown, text,
HTML, and PSA export generators. Each format renders text snippets and
screenshot placeholders in its native style.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 00:39:01 -04:00
chihlasm
312024e143 feat: add PDF export generation via WeasyPrint with branded template
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 00:28:22 -04:00
chihlasm
2c11917b5a feat: add supporting data CRUD endpoints with tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 00:22:40 -04:00
chihlasm
fdeb417131 feat: add team branding CRUD endpoints with tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 00:12:00 -04:00
chihlasm
75b32a4f5a feat: add onboarding status and dismiss endpoints with tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 00:05:28 -04:00
chihlasm
f16a686fb4 feat: add onboarding, branding, and supporting data models, migrations, and schemas
Add onboarding_dismissed and branding columns (logo_data, logo_content_type,
company_display_name) to users and teams models. Create SessionSupportingData
model for attaching text snippets and screenshots to sessions. Add Pydantic
schemas for onboarding status, branding responses, and supporting data CRUD.
Update SessionExport to accept pdf format.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:51:42 -04:00
chihlasm
8534dbfb5f feat: command palette, PSA ticket context, session-to-flow converter (#108)
* feat: add paletteIntent utility for command palette query classification

Detects query intent ('question' | 'keyword' | 'page' | 'empty') to drive
smart result ordering in the enhanced command palette.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add recentFlows localStorage utility for command palette empty state

Tracks recently visited flows (capped at 10) with deduplication by id,
surfaced in command palette when query is empty.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: rewrite CommandPalette with categorized results and smart ranking

- Adds FlowPilot AI result (always present when query is non-empty)
- Intent-aware ordering: question → FlowPilot prominent; page → pages first;
  keyword → FlowPilot at top with flows/sessions/tags below
- Pages section with admin-gated items (uses useAuthStore)
- Tags extracted from flow search results with ?tag= navigation
- Quick Actions for create/import/scripts
- Empty state shows recent flows + quick actions
- Grouped rendering with section labels per design system
- Keyboard nav flattened across groups

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add FlowPilot prefill handoff from command palette to AssistantChatPage

When navigated to /assistant with location.state.prefill, automatically
creates a new chat and sends the prefill message without user interaction.
Clears location state after handling to prevent re-trigger on back navigation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: track recently visited flows for command palette empty state

Calls addRecentFlow after tree data loads in both TreeNavigationPage and
ProceduralNavigationPage so the command palette can surface recent flows
when the query is empty.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: use useMemo instead of useCallback for groups builder in CommandPalette

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add PSA ticket context Pydantic schemas (Task 6)

Add TicketDetails, CompanyInfo, ContactInfo, ConfigItem, TicketNote,
RelatedTicket, and TicketContext models in schemas/psa_context.py for
structured ticket context enrichment used by AI prompt injection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add ticket context prompt formatter (Task 7)

format_ticket_context_for_prompt() in services/psa/ticket_context.py
serializes TicketContext into structured text for AI system prompts,
with 10-note limit, 200-char text previews, and human-readable timestamps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add get_ticket_context() to ConnectWise provider (Task 8)

Fetches ticket details, company, contact, configurations, notes, and
related open tickets in parallel via asyncio.gather with partial failure
tolerance. Results are cached with a 5-minute TTL per ticket/connection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add GET /integrations/psa/tickets/{id}/context endpoint (Task 9)

Returns rich TicketContext for a ticket ID. Handles PSA auth failures
(returns structured error), ticket-not-found (404), and general PSA
errors (502). Requires active PSA connection for the user's account.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: inject PSA ticket context into copilot system prompt (Task 10)

When a copilot conversation has an associated session with a linked PSA
ticket, fetch the ticket context and append it to the system prompt.
Failure is non-critical — errors are logged and the copilot proceeds
without context rather than failing the request.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add PSA context API client with TypeScript interfaces

Defines TicketDetails, CompanyInfo, ContactInfo, ConfigItemInfo,
TicketNote, RelatedTicket, and TicketContext interfaces matching backend
psa_context.py schemas. Exports psaContextApi with getTicketContext().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add useTicketContext hook for PSA ticket context fetching

Accepts psaTicketId and psaConnectionId, fetches context on mount
when both IDs are present, and exposes refresh() for manual re-fetch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add TicketContextPanel component with accordion sections

Glass-card panel showing ticket summary, status/priority/SLA, and
accordion sections for Client, Contact, Devices, Notes, and Related
tickets. Matches design system with font-label labels and ice-cyan accents.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: mount TicketContextPanel in session runners when ticket is linked

ProceduralNavigationPage renders panel in left sidebar below step checklist.
TreeNavigationPage renders panel above breadcrumb trail. Both use
useTicketContext hook and show panel only when psa_ticket_id is set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add fallback_steps to TypeScript types (Task 15)

Add optional fallback_steps field to ProceduralStep interface.
Add FallbackStepRecord interface and fallback_decisions field to Session.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add backend validation for fallback steps (Task 16)

Validate fallback_steps in procedural flow validation: required fields,
no nested fallback_steps, no duplicate IDs. Add FallbackStepRecord schema
and fallback_decisions field to SessionResponse.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: create FallbackSteps UI component (Task 17)

Collapsible component supporting edit and execute modes. Edit mode
provides title/description inputs with add/remove controls. Execute
mode shows "This worked" / "Didn't help" action buttons with emerald/
rose styling. Amber accent styling throughout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: integrate FallbackSteps into editor and session runner (Task 18)

Wire FallbackSteps edit mode into StepEditor for procedure_step type
with add/remove/update handlers using crypto.randomUUID(). Add execute
mode rendering in ProceduralNavigationPage with fallbackDecisions state
tracking per parent step.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add session-to-flow request/response schemas (Task 19)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add session-to-flow AI generation service (Task 20)

Converts completed troubleshooting sessions into reusable procedural flows
with fallback branches. Includes PSA ticket context integration and
AI-generated step validation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add POST /ai/session-to-flow endpoint (Task 21)

Converts a completed session into a reusable procedural flow using AI.
Includes quota checking, usage recording, and proper error handling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add Create Flow from Session button to session detail page (Task 22)

Adds sessionToFlow API client, exports from api/index.ts, and integrates
a prominent "Create Flow from Session" button on SessionDetailPage for
completed sessions. Generates a procedural flow via AI then navigates
to the procedural editor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: cast tree_type to TreeType in session-to-flow creation

Fixes build error where string was not assignable to TreeType.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update Playwright test selectors to match actual UI

- Use Control+k instead of Meta+k (Linux/CI compatibility)
- Use 'AI Assistant' group label instead of 'FlowPilot AI'
- Match actual FlowPilot chat page elements (Start a Conversation, New Chat, textarea)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update Playwright test selectors to match actual UI

- Use specific command palette placeholder to avoid ambiguous matches
- Fix 'Quick Actions' scoping (two elements with same text)
- Fix 'Resolved' exact match on session detail page
- Fix tree editor to use getByText instead of getByDisplayValue
- Fix 'Add Step' strict mode by using .first()
- Fix fallback description placeholder text
- Update playwright.config.ts to use port 5433 and resolutionflow DB
- Update FlowPilot chat selectors to match actual page layout

11/17 new tests now passing. Remaining 6 need procedural session
navigation investigation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: resolve all Playwright test failures — 16/16 passing

- Fix procedural session tests: sessions auto-start, no Start button
- Fix strict mode violations: use getByRole('heading') for step titles
- Fix FlowPilot chat: use button role selector for New Chat
- Fix command palette page nav: scope Analytics click to palette modal
- Fix fallback runner: remove non-existent Start button click
- Update playwright.config to port 5433 for local Docker

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:39:17 -04:00
chihlasm
357f8e2d08 feat: sidebar redesign — activity feed, grouped nav, AI split (#107)
* docs: add 5 sidebar icon color concepts for UX review

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(ui): add semantic icon colors and updated icons to sidebar nav

Swap generic icons for more descriptive alternatives (Network, Wrench,
FileOutput, Library, Code2, Lightbulb) and assign each nav item a unique
semantic color for instant visual landmarks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ui): default Sessions page to Active tab, reorder tabs

Active sessions are what engineers care about most. Tab order is now
Active, Prepared, Completed, All.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add sidebar grouping and AI naming concept mockups

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add sidebar redesign context and decision summary

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add sidebar redesign spec and implementation plan

Design spec covers: activity zone with daily stats + session feed,
nav grouping (Resolve/Build/Insights), AI split (FlowPilot + Flow Assist),
pinned flows removal. Implementation plan has 5 chunks, 12 tasks, 39 steps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add sidebar stats Pydantic schemas

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add failing tests for sidebar stats endpoint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add sidebar stats endpoint with daily stats and activity feed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add sidebar API client, stats bar, activity feed components

New components: SidebarStatsBar, SidebarActivityFeed, ActivityItem.
New API client for sidebar stats endpoint. Pulse-dot CSS animation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: restructure sidebar with stats bar, activity feed, and grouped nav

Dashboard-first layout with Resolve/Build/Insights groups.
AI split: FlowPilot (Resolve) + Flow Assist (Build).
Stats bar: Resolved/Active/In Session daily counters.
Activity feed: active sessions with CW ticket #, recent completions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: remove pinned flows frontend (PinnedFlowsSection, store, API, pin buttons)

Removed: PinnedFlowsSection component, pinnedFlowsStore, pinnedFlows API client.
Cleaned: pin buttons from TreeGridView, TreeListView, TreeTableView.
Cleaned: favorites section from QuickStartPage, pin props from TreeLibraryPage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add FlowAssistPage placeholder and /flow-assist route

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: real-time sidebar stats via session-changed events

Sidebar now refreshes stats when sessions are created or completed,
not just on page navigation. Uses window event bus pattern (same as
folder-changed events in codebase).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: live-ticking In Session timer using active session start times

SidebarStatsBar now computes active session elapsed time client-side
from started_at timestamps, ticking every 60s. Backend only returns
completed session minutes to avoid double-counting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: sidebar In Session timer ticks every second and shows seconds

Timer now uses 1s interval (not 60s) and displays seconds when under
a minute so it matches the session timer in the flow UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: trigger PR environment redeploy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* debug: add console.log to SidebarStatsBar for timer investigation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: parse sidebar timestamps as UTC (append Z suffix)

Backend returns naive UTC timestamps without timezone indicator.
JS Date() treats bare ISO strings as local time, causing the timer
to compute negative elapsed time (future timestamps). Appending 'Z'
forces UTC parsing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: rename 'In Session' to 'Total Time' for clarity

Makes it clear the timer is an aggregate of all sessions today,
not just the current one.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 01:35:16 -04:00
chihlasm
46865882c6 feat: ConnectWise PSA integration (#106)
PSA abstraction layer with provider pattern, ConnectWise integration (connection management, ticket linking, note posting, status updates, member mapping), Integrations page UI, Fernet credential encryption, in-memory TTL cache, 6 DB migrations, ConnectWise API reference docs.
2026-03-15 01:45:35 -04:00
chihlasm
d4dbf44781 feat: Script Generator Phase 1+2 — backend, engine, API, frontend, template editor, parameter detector
Complete Script Generator feature including:

Backend:
- ScriptCategory, ScriptTemplate, ScriptGeneration models
- ScriptTemplateEngine with substitution, filters, sanitization
- CRUD + share API endpoints with permission checks
- Integration tests for permissions and sharing
- Migration 057 with AD User Management seed templates

Frontend — Script Library:
- Browse templates with category tabs and search
- Configure pane with parameter form and script generation
- Script preview with live substitution and copy/download
- scriptGeneratorStore Zustand store

Frontend — Template Editor:
- Full CRUD form with metadata, script body (Monaco Editor), parameters
- ParameterSchemaBuilder with visual builder + JSON toggle
- ScriptManagePage with routing and nav link

Frontend — Parameter Detector:
- Client-side PowerShell parameter detection engine
- Detects script-level param() blocks and variable assignments
- Type inference from PS type annotations and value patterns
- ParameterDetectorStepper one-by-one review UI with accept/skip

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 20:18:59 -04:00
chihlasm
042a12b190 feat: add landing page with beta signup + raise KB node limit to 100
Landing page at /landing with full marketing content: hero, features,
pricing, testimonials, and beta email signup form. Beta signups email
beta@resolutionflow.com via new public endpoint. Unauthenticated users
redirect to landing instead of login. Also raises KB Accelerator node
limit from 50 to 100 to accommodate dense troubleshooting articles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 00:23:29 -04:00
chihlasm
458c2d9cab fix: prevent circular parent_node_id in KB troubleshooting import
AI-generated trees can have circular next_node_id references (e.g.,
node A → B → A). The parent mapping now checks for cycles before
assigning parent_node_id, preventing FK deadlocks during insert.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 23:46:49 -04:00