feat: AI chat conclusion + survey completion & management (#95)

* fix: increase assistant chat input height from 1 to 3 rows

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add Anthropic prompt caching to assistant chat

Cache the static system prompt and conversation history prefix across
turns, reducing input token costs by ~80% on multi-turn conversations.
RAG context is intentionally uncached since it changes per query.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add Microsoft Learn MCP integration + refine assistant system prompt

- Integrate Microsoft Learn MCP server via Anthropic's MCP connector
  for real-time documentation lookups (docs search, fetch, code samples)
- Refine system prompt: clear persona, structured answer guidelines,
  when to use RAG flows vs Microsoft Learn, guardrails against fabrication
- Add ENABLE_MCP_MICROSOFT_LEARN config toggle (default: True)
- Fix bugs from prior edit: wrong MCP URL, broken indentation, undefined
  usage/token variables, NOT_GIVEN for disabled MCP params
- Log MCP tool usage and cache performance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: AI chat session conclusion + survey completion & management

AI Assistant - Conclude Session:
- 3-step modal: select outcome (resolved/escalated/paused), add notes, AI-generated summary
- AI generates structured ticket notes from conversation transcript (PSA-ready format)
- Copy to clipboard for pasting into ticketing systems
- "Resume in New Chat" for paused sessions (pre-loads context into new chat)
- Backend: POST /chats/{id}/conclude endpoint, conclusion_summary/outcome/concluded_at fields
- Migration 048: add conclusion fields to assistant_chats

Survey Completion Flow:
- Email-to-self option after submission (branded HTML email with formatted responses)
- Finish button navigates to /survey/thank-you page
- Thank you page with close-window message and feedback email callout
- Already-submitted state updated with same messaging
- Backend: POST /survey/email-copy public endpoint

Survey Admin Management:
- Read/unread indicators (cyan dot, bold name, auto-mark on expand)
- Unread count stat card
- Per-row context menu: mark read/unread, archive/unarchive, delete
- Bulk actions bar: select all, mark read/unread, archive, delete
- Show Archived toggle to filter archived responses
- Backend: 7 new admin endpoints (read, unread, archive, unarchive, delete, bulk)
- Migration 049: add is_read, archived_at to survey_responses

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: initialize VerifyEmailPage state from token to avoid setState in effect

Moves the no-token error case from useEffect into initial state to satisfy
the react-hooks/set-state-in-effect ESLint rule.

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 #95.
This commit is contained in:
chihlasm
2026-03-05 22:43:02 -05:00
committed by GitHub
parent b46f41e7bb
commit 0fb1ef33a0
21 changed files with 1630 additions and 70 deletions

View File

@@ -0,0 +1,76 @@
import { BrandLogo } from '@/components/common/BrandLogo'
export default function SurveyThankYouPage() {
return (
<div className="min-h-screen bg-background text-foreground">
{/* Atmosphere orbs */}
<div className="pointer-events-none fixed inset-0 z-0 overflow-hidden" aria-hidden="true">
<div
className="absolute"
style={{ top: '-200px', left: '-100px', width: '600px', height: '600px', borderRadius: '50%', background: 'radial-gradient(circle, rgba(6, 182, 212, 0.12) 0%, rgba(6, 182, 212, 0.03) 40%, transparent 70%)', filter: 'blur(80px)' }}
/>
<div
className="absolute"
style={{ bottom: '-150px', right: '-100px', width: '500px', height: '500px', borderRadius: '50%', background: 'radial-gradient(circle, rgba(52, 211, 153, 0.08) 0%, rgba(52, 211, 153, 0.02) 40%, transparent 70%)', filter: 'blur(80px)' }}
/>
</div>
{/* Top bar */}
<div className="sticky top-0 z-50" style={{ backdropFilter: 'blur(20px)', WebkitBackdropFilter: 'blur(20px)', background: 'rgba(16, 17, 20, 0.85)', borderBottom: '1px solid var(--glass-border)' }}>
<div className="mx-auto flex max-w-[680px] items-center justify-between gap-3 px-5 py-3.5">
<a href="https://resolutionflow.com" target="_blank" rel="noreferrer" className="flex items-center gap-2.5 text-sm font-heading font-bold text-muted-foreground no-underline">
<BrandLogo size="sm" />
<span>Resolution<span className="text-gradient-brand">Flow</span></span>
</a>
</div>
</div>
<div className="relative z-10 mx-auto max-w-[680px] px-5">
<div className="text-center pt-[120px] animate-fade-in-up">
{/* Success icon */}
<div className="w-20 h-20 mx-auto mb-6 rounded-full flex items-center justify-center" style={{ background: 'rgba(52, 211, 153, 0.1)', border: '1px solid rgba(52, 211, 153, 0.15)' }}>
<svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#34d399" strokeWidth="2">
<path d="M20 6L9 17l-5-5"/>
</svg>
</div>
<h1 className="font-heading text-[clamp(24px,4vw,32px)] font-extrabold leading-tight mb-3">
Thank You!
</h1>
<p className="text-[15px] text-muted-foreground max-w-[460px] mx-auto leading-relaxed mb-3">
Your response has been recorded. Your expertise will directly shape how FlowPilot thinks about troubleshooting.
</p>
<p className="text-sm text-muted-foreground/70 max-w-[400px] mx-auto leading-relaxed mb-10">
You can safely close this browser window now.
</p>
{/* Divider */}
<div className="mx-auto w-12 h-px mb-10" style={{ background: 'var(--glass-border)' }} />
{/* Feedback callout */}
<div
className="glass-card-static p-6 text-center max-w-[480px] mx-auto"
>
<div className="flex items-center justify-center gap-2 mb-3">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#06b6d4" strokeWidth="2">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg>
<span className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-primary font-semibold">
Have Feedback?
</span>
</div>
<p className="text-sm text-muted-foreground leading-relaxed">
If you have any feedback unrelated to the survey, we'd love to hear from you at{' '}
<a
href="mailto:feedback@resolutionflow.com"
className="text-primary hover:underline font-medium"
>
feedback@resolutionflow.com
</a>
</p>
</div>
</div>
</div>
</div>
)
}