Files
resolutionflow/docs/plans/archive/2026-03-20-search-recall-evidence-design.md
Michael Chihlas cbb4b25671
All checks were successful
Mirror to GitHub / mirror (push) Successful in 5s
CI / frontend (pull_request) Successful in 6m42s
CI / e2e (pull_request) Successful in 10m11s
CI / backend (pull_request) Successful in 10m43s
fix(ui): drop setState-in-effect in useAuthSessionExpiry
CI surfaced react-hooks/set-state-in-effect on the synchronous
setState(computeState(token)) inside the useEffect body. The earlier
shape mirrored token -> state via an effect, which is exactly the
"you might not need an effect" pattern React 19's eslint rule now
flags.

Switch to derived state: compute during render, use a useReducer
tick to force re-render on the 30s cadence (so relative timestamps
stay current even when token props don't change). Same observable
behavior, no cascading renders.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 20:15:11 -04:00

5.8 KiB

Search & Recall + Evidence-Rich Sessions — Design Document

Date: 2026-03-20 Status: Approved Source: Stack priorities plan items #1 (Search and recall improvements) and #2 (Evidence-rich sessions)


Overview

Two complementary features that make ResolutionFlow a team memory system, not just a flow runner. Engineers can capture proof (screenshots, logs, command output) during troubleshooting via clipboard paste, and search across all past sessions by content, domain, ticket, or semantic similarity.


Feature 1: Evidence-Rich Sessions

Storage

  • Railway Object Storage — S3-compatible bucket provisioned via Railway dashboard/CLI
  • Backend uses boto3 with S3-compatible endpoint configured via env vars:
    • STORAGE_ENDPOINT — Railway bucket endpoint
    • STORAGE_ACCESS_KEY — bucket access key
    • STORAGE_SECRET_KEY — bucket secret key
    • STORAGE_BUCKET_NAME — bucket name
    • STORAGE_REGION — region (default: us-east-1)

Data Model

New file_uploads table:

Column Type Notes
id UUID PK
account_id UUID FK → accounts Tenant scope
uploaded_by UUID FK → users Who uploaded
session_id UUID FK → ai_sessions (nullable) Linked session
filename String(255) Original filename
content_type String(100) MIME type
size_bytes Integer File size
storage_key String(500) S3 object key
created_at DateTime(tz)

API

POST   /uploads                    — Multipart file upload, returns upload record with presigned URL
GET    /uploads/{id}/url           — Presigned download URL (time-limited, 1 hour)
GET    /uploads?session_id={id}    — List uploads for a session
DELETE /uploads/{id}               — Delete upload + S3 object

Limits

  • Image types: PNG, JPEG, GIF, WebP — max 5MB each
  • Text types: .txt, .log, .csv — max 1MB each
  • Per-session: 20 files, 50MB total
  • Rate limit: 10 uploads/minute per user

Clipboard Paste UX

A RichTextInput component that wraps textareas with clipboard paste support:

  • Listens for paste event on the textarea
  • Detects image blobs in clipboardData.items
  • On image paste: uploads in background via POST /uploads, shows inline thumbnail with progress
  • Thumbnail states: uploading (spinner overlay) → success (image preview) → error (retry button)
  • Text content and image references stored together in JSONB
  • Images rendered as small thumbnails below the textarea, removable with X button

Where it's used:

  • FlowPilot intake textarea
  • Free-text response input (escape hatch)
  • Escalation reason textarea
  • Session scratchpad

Evidence in Exports

Extend the existing export service:

  • Markdown: images as ![filename](presigned_url) links
  • HTML/PDF: images embedded as <img> with presigned URLs
  • PSA: image URLs listed as references (ConnectWise notes don't support inline images)

Feature 2: Search & Recall

Layer 1: Structured Filters

Extend GET /ai-sessions with query parameters:

Param Type Filter
problem_domain string Exact match on domain
matched_flow_id UUID Sessions that matched a specific flow
confidence_tier string guided / exploring / discovery
ticket_id string PSA ticket ID
date_from datetime Sessions created after
date_to datetime Sessions created before
q string Full-text search (Layer 2)

Frontend: add filter bar to AI Sessions tab on SessionHistoryPage — domain dropdown, confidence pills, date range, search input. Match the existing Flow Sessions filter pattern.

Layer 2: Content Search (PostgreSQL FTS)

Add generated tsvector column to ai_sessions:

ALTER TABLE ai_sessions ADD COLUMN search_vector tsvector
  GENERATED ALWAYS AS (
    to_tsvector('english',
      coalesce(intake_summary, '') || ' ' ||
      coalesce(resolution_summary, '') || ' ' ||
      coalesce(escalation_reason, '') || ' ' ||
      coalesce(problem_domain, ''))
  ) STORED;

CREATE INDEX idx_ai_sessions_search ON ai_sessions USING gin(search_vector);

The q parameter uses plainto_tsquery('english', q) against this vector. Same pattern as existing tree FTS search.

Extend Command Palette to search AI sessions alongside flows.

Layer 3: Similar Session Matching

New endpoint: GET /ai-sessions/{id}/similar?limit=5

  • Generates embedding for the session's intake_summary using existing Voyage AI integration
  • New ai_session_embeddings table (same pattern as tree_embeddings): session_id, embedding (pgvector)
  • Embeddings generated on session creation (after intake) and updated on resolution
  • Cosine similarity query against all session embeddings for the account
  • Returns top N matches with similarity score and session summary

Where similar sessions appear:

  • FlowPilot session sidebar: "Similar Past Sessions" section (3-5 matches)
  • Session detail page: "Related Sessions" at bottom
  • Both show: session name/summary, resolution status, date, similarity %

Implementation Order

  1. File upload infrastructure — S3 service, file_uploads model, upload/download endpoints
  2. RichTextInput component — clipboard paste handler, thumbnail rendering, upload integration
  3. Wire into FlowPilot — intake, free-text, escalation, scratchpad
  4. Evidence in exports — extend export service with image references
  5. Structured filters — extend AI session list endpoint + frontend filter bar
  6. Content search (FTS) — migration for tsvector + GIN index, wire into list endpoint
  7. Command palette session search — extend CommandPalette with AI session results
  8. Similar session matching — embeddings table, generation service, similar endpoint
  9. Similar sessions UI — sidebar section + session detail section