Slice 2 (Notifications) fully complete. Slice 3 (Session Export) ~80% done, needs polish only. Remaining execution order: Slice 1 → 3 polish → 4 → 5. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
829 lines
38 KiB
Markdown
829 lines
38 KiB
Markdown
# FlowPilot-First Pivot — Phase 4: Growth, Polish & Enterprise Readiness
|
|
|
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
>
|
|
> **Status (2026-03-19):** Slice 2 (Notifications) COMPLETE. Slice 3 (Session Export) ~80% COMPLETE (needs polish only). Remaining: Slices 1, 4, 5. Execute in order: Slice 1 → Slice 3 polish → Slice 4 → Slice 5.
|
|
|
|
**Goal:** Prepare ResolutionFlow for market growth and enterprise customers. Build the public templates gallery for SEO/lead-gen, add notification integrations (Slack/Teams/email) for escalation alerts, polish the mobile/responsive experience, add session export capabilities, and lay the groundwork for enterprise features (SSO prep, custom branding, multi-PSA).
|
|
|
|
**Architecture:** This phase is less about new core architecture and more about extending what exists. Templates gallery is a public-facing read-only layer over the existing flow/script template system. Notifications add webhook/event infrastructure. Mobile polish is a responsive design pass. Enterprise features add configuration surfaces.
|
|
|
|
**Tech Stack:** FastAPI, SQLAlchemy 2.0 (async), React, TypeScript, Tailwind CSS v4 (@tailwindcss/vite), Recharts, Resend (email notifications), weasyprint (PDF export), slowapi (rate limiting)
|
|
|
|
**Prerequisites:**
|
|
- Phase 1 complete (AI session core)
|
|
- Phase 2 complete (PSA integration, escalation handoff)
|
|
- Phase 3 complete (Knowledge Flywheel, Review Queue, in-session Script Generator, analytics)
|
|
- Existing models: `Tree`, `ScriptTemplate`, `AISession`, `FlowProposal`, `PsaConnection`
|
|
- Existing services: All Phase 1-3 services
|
|
- Existing frontend: All Phase 1-3 pages and components
|
|
|
|
**Pivot architecture doc:** `docs/ResolutionFlow_Pivot_Architecture.docx`
|
|
**Product strategy doc:** `docs/ResolutionFlow_Product_Strategy_Review.docx`
|
|
|
|
---
|
|
|
|
## Context: What Phase 4 Adds
|
|
|
|
Phases 1-3 built a complete AI-powered resolution engine with PSA integration, knowledge learning, and analytics. Phase 4 is about growth and polish — making the product ready for broader adoption and enterprise buyers.
|
|
|
|
**Public Templates Gallery:** A public-facing page at `/templates` (no auth required) that showcases curated flow templates and script templates. This is the primary SEO and lead-gen surface identified in the Product Strategy Review. Engineers discover ResolutionFlow by searching for troubleshooting guides, see the value, and sign up.
|
|
|
|
**Notification Integrations:** When a session is escalated, the receiving engineer (and team leads) should be notified via Slack, Microsoft Teams, or email. Also notify on: high-priority ticket sessions, Knowledge Flywheel proposals pending review, and session completion for tracked tickets.
|
|
|
|
**Session Export & Sharing:** Export session documentation as PDF or formatted text for sharing outside ResolutionFlow. "Generated with ResolutionFlow" branding on exports for viral growth (per Product Strategy Review).
|
|
|
|
**Mobile/Responsive Polish:** The FlowPilot session experience must work on tablets and phones. MSP techs often troubleshoot on-site with a tablet. This is a responsive design pass, not a native app.
|
|
|
|
**Enterprise Readiness:** Custom branding (logo, colors), SAML/SSO groundwork, multi-PSA support (Autotask, Halo PSA adapter stubs), and admin controls for AI model selection.
|
|
|
|
---
|
|
|
|
## Slice 1: Public Templates Gallery
|
|
|
|
### Task 1: Build public templates API (no auth required)
|
|
|
|
**Files:**
|
|
- Create: `backend/app/api/endpoints/public_templates.py`
|
|
- Create: `backend/app/schemas/public_templates.py`
|
|
|
|
**Schemas:**
|
|
|
|
```python
|
|
class PublicFlowTemplate(BaseModel):
|
|
"""A flow template visible in the public gallery."""
|
|
id: UUID
|
|
name: str
|
|
description: str | None
|
|
category: str | None
|
|
problem_domain: str | None
|
|
tree_type: str
|
|
step_count: int
|
|
usage_count: int
|
|
success_rate: float | None
|
|
tags: list[str]
|
|
preview_structure: dict[str, Any] # Simplified tree for preview (first 2-3 levels only)
|
|
created_at: datetime
|
|
|
|
class PublicScriptTemplate(BaseModel):
|
|
"""A script template visible in the public gallery."""
|
|
id: UUID
|
|
name: str
|
|
description: str | None
|
|
use_case: str | None
|
|
category_name: str
|
|
category_icon: str | None
|
|
complexity: str
|
|
tags: list[str]
|
|
parameter_count: int
|
|
requires_elevation: bool
|
|
requires_modules: list[str]
|
|
usage_count: int
|
|
is_verified: bool
|
|
created_at: datetime
|
|
|
|
class PublicGalleryResponse(BaseModel):
|
|
"""Combined gallery response."""
|
|
flow_templates: list[PublicFlowTemplate]
|
|
script_templates: list[PublicScriptTemplate]
|
|
total_flows: int
|
|
total_scripts: int
|
|
categories: list[str]
|
|
domains: list[str]
|
|
```
|
|
|
|
**Endpoints (NO authentication required):**
|
|
|
|
```
|
|
GET /api/v1/public/templates — Gallery listing (paginated, filterable)
|
|
GET /api/v1/public/templates/flows/{id} — Flow template detail (preview only, no full structure)
|
|
GET /api/v1/public/templates/scripts/{id} — Script template detail (preview only, no script body)
|
|
GET /api/v1/public/templates/categories — List all categories with counts
|
|
GET /api/v1/public/templates/search — Full-text search across flows + scripts
|
|
```
|
|
|
|
**Key implementation details:**
|
|
|
|
- Only expose flows/scripts marked as `visibility = "public"` or a new `is_gallery_featured` boolean
|
|
- Add `is_gallery_featured` boolean column to both `trees` and `script_templates` tables (migration required)
|
|
- `preview_structure` should be a truncated version of `tree_structure` — first 2-3 levels only, no deep branches. Don't expose the full flow to unauthenticated users — they need to sign up for that.
|
|
- Script templates in the gallery show parameter names and description but NOT the `script_body` — that's the value behind the signup wall
|
|
- Rate limit public endpoints via `slowapi` (standard FastAPI rate limiter): 30/minute per IP. The existing `core/rate_limit.py` is auth-based (per-user); public endpoints need IP-based limiting. Add `slowapi` to requirements and configure a `Limiter` instance with `get_remote_address` as the key function. Apply `@limiter.limit("30/minute")` to each public endpoint.
|
|
- Add OpenGraph meta tags support for social sharing (title, description, image)
|
|
- Cache responses aggressively (5-minute TTL) since public content changes infrequently
|
|
|
|
**SEO consideration:** These endpoints power the public page at `resolutionflow.com/templates`. The response should include fields that map well to structured data (schema.org HowTo or SoftwareApplication).
|
|
|
|
**Note (deferred):** React SPAs serve empty HTML to social media scrapers (Facebook, Slack, LinkedIn), so OpenGraph meta tags won't render in link previews. Options for Phase 5: prerendering service (prerender.io), build-time static HTML generation for gallery pages, or backend-side meta tag injection. Google's crawler handles JS fine, but social sharing will be limited until addressed.
|
|
|
|
**Verification:** Hit the public templates endpoint without auth. Verify flows and scripts with `is_gallery_featured = true` appear. Verify full script bodies and deep flow structures are NOT exposed.
|
|
|
|
```
|
|
git commit -m "feat(public): add public templates gallery API"
|
|
```
|
|
|
|
### Task 2: Build public templates gallery frontend
|
|
|
|
**Files:**
|
|
- Create: `frontend/src/pages/PublicTemplatesPage.tsx`
|
|
- Create: `frontend/src/components/public/TemplateGalleryGrid.tsx`
|
|
- Create: `frontend/src/components/public/FlowTemplateCard.tsx`
|
|
- Create: `frontend/src/components/public/ScriptTemplateCard.tsx`
|
|
- Create: `frontend/src/components/public/TemplateDetailModal.tsx`
|
|
- Create: `frontend/src/components/public/GallerySearch.tsx`
|
|
- Create: `frontend/src/api/publicTemplates.ts`
|
|
- Create: `frontend/src/types/public-templates.ts`
|
|
- Edit: `frontend/src/router.tsx`
|
|
|
|
**Route:** `/templates` — public, no auth required. Add to the router OUTSIDE the `ProtectedRoute` wrapper, alongside `/landing`, `/login`, `/register`.
|
|
|
|
**Design:** This is the first page many potential users will see. It needs to be visually impressive and clearly communicate value.
|
|
|
|
**Layout:**
|
|
|
|
**Hero section:**
|
|
- Heading: "MSP Troubleshooting Templates" (Bricolage Grotesque, large)
|
|
- Subheading: "Battle-tested flows and scripts built by MSP engineers. Free to browse, powerful when connected to FlowPilot."
|
|
- Search bar (prominent, centered)
|
|
- CTA: "Sign Up Free" button
|
|
|
|
**Filter bar:**
|
|
- Category pills: "All", "Active Directory", "Networking", "Microsoft 365", "Security", etc.
|
|
- Type toggle: "Flows", "Scripts", "All"
|
|
- Sort: "Most Used", "Newest", "Highest Success Rate"
|
|
|
|
**Grid:**
|
|
- Responsive card grid: 3 columns desktop, 2 tablet, 1 mobile
|
|
- Flow cards: name, description, domain badge, step count, success rate, usage count, "Preview" button
|
|
- Script cards: name, description, complexity badge (color-coded), verified badge, module tags, "View Details" button
|
|
|
|
**Template detail modal:**
|
|
- For flows: show the first 2-3 levels of the tree as a simplified visual (not the full flow editor — just a clean tree diagram). "Sign up to use this flow with FlowPilot" CTA.
|
|
- For scripts: show parameter list, description, use case, modules required. "Sign up to generate this script" CTA. Do NOT show the script body.
|
|
|
|
**Footer on every card:** "Powered by ResolutionFlow" with subtle branding
|
|
|
|
**Verification:** Open `/templates` without being logged in. Browse the gallery. Search for "Active Directory". Filter by scripts. Click a card — see the preview modal with signup CTA. Verify no sensitive data (script bodies, deep flow structures) is exposed.
|
|
|
|
```
|
|
git commit -m "feat(public): add public templates gallery page"
|
|
```
|
|
|
|
### Task 3: Admin curation tools for gallery
|
|
|
|
**Files:**
|
|
- Edit: `frontend/src/pages/admin/` (add gallery management section)
|
|
- Edit: `backend/app/api/endpoints/admin.py` (or create `admin_gallery.py`)
|
|
|
|
**What to add:**
|
|
|
|
Admin interface to manage which flows and scripts appear in the public gallery:
|
|
|
|
- Toggle `is_gallery_featured` on/off for any flow or script template
|
|
- Reorder gallery items (add `gallery_sort_order` column)
|
|
- Set gallery category overrides (a flow might have a different display category in the gallery vs internally)
|
|
- Preview how a template will look in the public gallery
|
|
|
|
**Verification:** Log in as admin. Feature a flow in the gallery. Open `/templates` in an incognito window. Verify the flow appears.
|
|
|
|
```
|
|
git commit -m "feat(admin): add gallery curation tools"
|
|
```
|
|
|
|
---
|
|
|
|
## Slice 2: Notification Integrations — COMPLETE (2026-03-19)
|
|
|
|
> **Status:** Fully implemented in Phase 4 Slice 2 session. Models, service, API endpoints, in-app notifications, retry scheduler, frontend panel and settings all done. Skip to Slice 3.
|
|
|
|
### Task 4: Build notification event system
|
|
|
|
**Files:**
|
|
- Create: `backend/app/services/notification_service.py`
|
|
- Create: `backend/app/models/notification_config.py`
|
|
- Create: `backend/app/schemas/notification.py`
|
|
|
|
**Architecture:**
|
|
|
|
A lightweight event-driven notification system. Events are fired from various points in the codebase, and the notification service routes them to configured channels.
|
|
|
|
**Events:**
|
|
|
|
| Event | Trigger | Default Recipients |
|
|
|-------|---------|-------------------|
|
|
| `session.escalated` | Engineer escalates a session | Escalation target + team admins |
|
|
| `session.resolved` | Session resolved (if tracked) | Session owner |
|
|
| `proposal.pending` | Knowledge Flywheel creates proposal | Team admins |
|
|
| `proposal.approved` | Reviewer approves a proposal | Proposal source session engineer |
|
|
| `session.high_priority` | PSA ticket with high/critical priority starts a session | Team admins |
|
|
| `knowledge_gap.detected` | New high-severity knowledge gap identified | Team admins |
|
|
|
|
**Notification channels:**
|
|
|
|
- **Email** (via existing Resend integration — `settings.RESEND_API_KEY`)
|
|
- **Slack webhook** (simple `POST` to a webhook URL — no OAuth needed for v1)
|
|
- **Microsoft Teams webhook** (similar — Adaptive Card format)
|
|
|
|
**NotificationConfig model:**
|
|
|
|
```python
|
|
class NotificationConfig(Base):
|
|
__tablename__ = "notification_configs"
|
|
|
|
id: UUID (PK)
|
|
account_id: UUID (FK)
|
|
channel: str # "email" | "slack_webhook" | "teams_webhook"
|
|
webhook_url: str | None # For Slack/Teams
|
|
is_active: bool
|
|
events_enabled: JSONB # {"session.escalated": true, "proposal.pending": true, ...}
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
```
|
|
|
|
**Service pattern:**
|
|
|
|
```python
|
|
async def notify(event: str, account_id: UUID, payload: dict, db: AsyncSession):
|
|
"""Fire a notification event. Routes to all active channels for this account."""
|
|
configs = await _get_active_configs(account_id, event, db)
|
|
for config in configs:
|
|
if config.channel == "email":
|
|
await _send_email_notification(event, payload, config)
|
|
elif config.channel == "slack_webhook":
|
|
await _send_slack_notification(event, payload, config)
|
|
elif config.channel == "teams_webhook":
|
|
await _send_teams_notification(event, payload, config)
|
|
```
|
|
|
|
**Key details:**
|
|
- Run notifications async (don't block the response) via `asyncio.create_task()`
|
|
- Slack format: Rich message with fields (session summary, escalation reason, link to session)
|
|
- Teams format: Adaptive Card with similar fields
|
|
- Email format: Simple HTML email using Resend (reuse existing email infrastructure)
|
|
- On webhook failure: log to `notification_logs` table and schedule retry via APScheduler (exponential backoff: 30s, 2m, 10m — max 3 retries). Same pattern as PSA push retry from Phase 2.
|
|
|
|
**NotificationLog model:**
|
|
|
|
```python
|
|
class NotificationLog(Base):
|
|
__tablename__ = "notification_logs"
|
|
|
|
id: UUID (PK)
|
|
notification_config_id: UUID (FK → notification_configs.id)
|
|
event: str # "session.escalated", "proposal.pending", etc.
|
|
payload: JSONB # Event payload snapshot
|
|
status: str # "sent" | "failed" | "retrying" | "exhausted"
|
|
retry_count: int (default 0)
|
|
last_error: str | None
|
|
next_retry_at: datetime | None
|
|
created_at: datetime
|
|
delivered_at: datetime | None
|
|
```
|
|
|
|
**Verification:** Configure a Slack webhook. Escalate a session. Verify Slack message appears with session summary and link.
|
|
|
|
```
|
|
git commit -m "feat(notifications): add notification event system with email/Slack/Teams"
|
|
```
|
|
|
|
### Task 5: Wire notifications into session lifecycle
|
|
|
|
**Files:**
|
|
- Edit: `backend/app/services/flowpilot_engine.py`
|
|
- Edit: `backend/app/services/knowledge_flywheel.py`
|
|
- Edit: `backend/app/api/endpoints/flow_proposals.py`
|
|
|
|
**What to add:**
|
|
|
|
Add `notify()` calls at these points:
|
|
|
|
- `flowpilot_engine.escalate_session()` → fire `session.escalated`
|
|
- `flowpilot_engine.start_session()` → if PSA ticket has high/critical priority → fire `session.high_priority`
|
|
- `knowledge_flywheel.analyze_session()` → when creating a `pending` proposal → fire `proposal.pending`
|
|
- `flow_proposals.review_proposal()` → when approving → fire `proposal.approved`
|
|
|
|
All notification calls should use `asyncio.create_task()` to avoid blocking.
|
|
|
|
**Verification:** Configure email notifications. Escalate a session. Check email inbox. Configure Slack webhook. Create a high-priority ticket session. Verify Slack notification fires.
|
|
|
|
```
|
|
git commit -m "feat(notifications): wire notifications into session and proposal lifecycle"
|
|
```
|
|
|
|
### Task 6: Notification settings UI
|
|
|
|
**Files:**
|
|
- Create: `frontend/src/components/account/NotificationSettings.tsx`
|
|
- Edit: `frontend/src/pages/account/IntegrationsPage.tsx`
|
|
- Create: `frontend/src/api/notifications.ts`
|
|
- Create: `frontend/src/types/notification.ts`
|
|
|
|
**What to add:**
|
|
|
|
Under Account Settings → Integrations, add a "Notifications" section:
|
|
|
|
- **Email notifications:** Toggle per event type. Uses the account owner's email by default. Option to add additional email addresses.
|
|
- **Slack:** "Connect Slack" → paste webhook URL → test button → configure which events to send
|
|
- **Microsoft Teams:** Same pattern — paste webhook URL → test → configure events
|
|
|
|
Each channel shows a card with:
|
|
- Channel name + icon (Slack logo, Teams logo, email icon)
|
|
- Status indicator (active/inactive)
|
|
- Event toggles (checkboxes for each event type)
|
|
- Test button → sends a test notification to verify the webhook works
|
|
- Remove button
|
|
|
|
**Verification:** Open integrations page. Add a Slack webhook. Toggle escalation events on. Click test. Verify test message appears in Slack. Escalate a session. Verify real notification appears.
|
|
|
|
```
|
|
git commit -m "feat(notifications): add notification settings UI"
|
|
```
|
|
|
|
### Task 6.5: In-app notification center
|
|
|
|
**Files:**
|
|
- Edit: `frontend/src/components/layout/NotificationsPanel.tsx` (EXISTING — currently shows recent session activity only)
|
|
- Create: `backend/app/api/endpoints/notifications.py`
|
|
- Create: `backend/app/models/notification.py`
|
|
- Edit: `backend/app/api/router.py`
|
|
|
|
**Context:** An existing `NotificationsPanel` component already renders a bell icon with a dropdown in the top bar. It currently fetches recent sessions via `sessionsApi.list()` and shows them as an activity feed. This task extends it into a real notification center.
|
|
|
|
**Backend — Notification model:**
|
|
|
|
```python
|
|
class Notification(Base):
|
|
__tablename__ = "notifications"
|
|
|
|
id: UUID (PK)
|
|
account_id: UUID (FK)
|
|
user_id: UUID (FK → users.id) # Recipient
|
|
event: str # "session.escalated", "proposal.pending", etc.
|
|
title: str # "Session escalated by John"
|
|
body: str | None # Brief summary
|
|
link: str | None # In-app link, e.g. "/pilot/{session_id}"
|
|
is_read: bool (default False)
|
|
created_at: datetime
|
|
```
|
|
|
|
**Backend endpoints:**
|
|
|
|
```
|
|
GET /api/v1/notifications — List notifications (paginated, unread first)
|
|
GET /api/v1/notifications/unread-count — Unread count (for badge)
|
|
PATCH /api/v1/notifications/{id}/read — Mark as read
|
|
POST /api/v1/notifications/mark-all-read — Mark all as read
|
|
```
|
|
|
|
**Frontend changes to `NotificationsPanel.tsx`:**
|
|
|
|
- Replace `sessionsApi.list()` with notifications API
|
|
- Show unread count badge on the bell icon (red dot → count badge when > 0)
|
|
- Each notification item: icon (by event type), title, body, time ago, link
|
|
- Click a notification → mark as read + navigate to the link
|
|
- "Mark all as read" button in the dropdown header
|
|
- Keep existing glass-card dropdown styling
|
|
|
|
**Wire into notification service:** When `notify()` fires for email/Slack/Teams, also create a `Notification` row for each target user. In-app notifications are always created regardless of channel config.
|
|
|
|
**Verification:** Escalate a session. Check the bell icon shows a badge. Open dropdown — see the escalation notification. Click it — navigate to the session. Badge clears.
|
|
|
|
```
|
|
git commit -m "feat(notifications): add in-app notification center extending existing NotificationsPanel"
|
|
```
|
|
|
|
---
|
|
|
|
## Slice 3: Session Export & Sharing — MOSTLY COMPLETE (polish only)
|
|
|
|
> **Status:** `export_service.py` (1145 lines, 5 formats), frontend export UI on `SessionDetailPage` (format selection, preview, clipboard, download, redaction), and WeasyPrint are all implemented. Remaining: verify PDF template styling, add loading spinner for PDF generation, ensure "Generated with ResolutionFlow" branding on all formats, end-to-end test all formats.
|
|
|
|
### Task 7: Build session export service
|
|
|
|
**Files:**
|
|
- Create: `backend/app/services/session_export_service.py`
|
|
- Edit: `backend/app/api/endpoints/ai_sessions.py`
|
|
|
|
**Export formats:**
|
|
|
|
**1. PDF export:**
|
|
- Professional PDF with ResolutionFlow branding
|
|
- Sections: Problem Summary, Diagnostic Trail, Resolution/Escalation, Session Metadata
|
|
- Each step formatted cleanly with numbered steps, responses, outcomes
|
|
- "Generated with ResolutionFlow" footer + URL on every page
|
|
- Redact sensitive data (passwords) using existing `redaction_service.py`
|
|
|
|
**2. Markdown export:**
|
|
- Clean markdown version of the session documentation
|
|
- Suitable for pasting into wikis, Confluence, SharePoint, etc.
|
|
- Same structure as PDF but in markdown format
|
|
|
|
**3. Shareable link:**
|
|
- Generate a time-limited shareable link (24h default, configurable)
|
|
- Reuse the existing `SessionShare` model pattern from legacy sessions
|
|
- Public view shows the session in read-only mode with minimal UI
|
|
- "Generated with ResolutionFlow — Start your free trial" CTA at the bottom
|
|
|
|
**New endpoints:**
|
|
|
|
```
|
|
GET /api/v1/ai-sessions/{id}/export?format=pdf — Download PDF
|
|
GET /api/v1/ai-sessions/{id}/export?format=markdown — Download markdown
|
|
POST /api/v1/ai-sessions/{id}/share — Create shareable link
|
|
GET /api/v1/shared/ai-session/{token} — Public view (no auth)
|
|
```
|
|
|
|
**PDF generation:** Use `weasyprint` — it produces the best output for HTML→PDF conversion. Requires system-level dependencies in the Dockerfile:
|
|
|
|
```dockerfile
|
|
# Add to backend/Dockerfile before pip install
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 libffi-dev \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
```
|
|
|
|
Generate a styled HTML template (with ResolutionFlow branding, fonts, colors) and pass it to `weasyprint.HTML(string=html).write_pdf()`. Keep the HTML template in `backend/app/templates/session_export.html`.
|
|
|
|
**Key detail — growth mechanic:** Every export and shared link includes "Generated with ResolutionFlow" branding. This is the viral growth loop identified in the Product Strategy Review. Make the branding tasteful but visible — a small footer, not an intrusive watermark.
|
|
|
|
**Verification:** Resolve a session. Export as PDF — verify clean formatting with branding. Export as markdown — verify proper markdown. Create a share link — open in incognito — verify read-only view with CTA.
|
|
|
|
```
|
|
git commit -m "feat(export): add session export (PDF, markdown, shareable link)"
|
|
```
|
|
|
|
### Task 8: Export and share buttons in frontend
|
|
|
|
**Files:**
|
|
- Create: `frontend/src/components/flowpilot/SessionExportMenu.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/SessionDocView.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/FlowPilotSession.tsx`
|
|
|
|
**What to add:**
|
|
|
|
An export menu in the session documentation view and completed session view:
|
|
|
|
- "Export" dropdown button with options: "Download PDF", "Download Markdown", "Copy to Clipboard" (formatted text via `navigator.clipboard.writeText()` — most-used option for pasting into PSA ticket notes, wikis, or emails)
|
|
- "Share" button → generates shareable link → copies to clipboard with toast notification
|
|
- Share link shows expiration time and option to revoke
|
|
|
|
**Design:** Small dropdown menu, consistent with existing UI patterns. Export icon from Lucide (`Download` or `Share2`).
|
|
|
|
**Verification:** Complete a session. Click Export → Download PDF. Verify PDF downloads. Click Share → verify link is copied. Open link in incognito.
|
|
|
|
```
|
|
git commit -m "feat(export): add export and share UI"
|
|
```
|
|
|
|
---
|
|
|
|
## Slice 4: Mobile/Responsive Polish
|
|
|
|
### Task 9: Responsive design pass for FlowPilot session
|
|
|
|
**Files:**
|
|
- Edit: `frontend/src/components/flowpilot/FlowPilotIntake.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/FlowPilotSession.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/FlowPilotStepCard.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/FlowPilotOptions.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/FlowPilotActionBar.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/ConfidenceIndicator.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/SessionDocView.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/EscalateModal.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/EscalationQueue.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/SessionTicketCard.tsx`
|
|
- Edit: `frontend/src/components/flowpilot/InSessionScriptGenerator.tsx`
|
|
- Edit: `frontend/src/pages/ReviewQueuePage.tsx`
|
|
- Edit: `frontend/src/pages/FlowPilotAnalyticsPage.tsx`
|
|
- Edit: `frontend/src/pages/PublicTemplatesPage.tsx`
|
|
|
|
**This is NOT a rebuild. It's a responsive audit and fix pass.**
|
|
|
|
**Breakpoints (follow existing Tailwind v4 breakpoints):**
|
|
- Mobile: < 640px (`sm:`)
|
|
- Tablet: 640px - 1024px (`md:`)
|
|
- Desktop: > 1024px (`lg:`)
|
|
|
|
**Key responsive changes:**
|
|
|
|
**FlowPilot Session (most critical):**
|
|
- Desktop: Two-column layout (conversation 70% + sidebar 30%)
|
|
- Tablet: Sidebar collapses to a top bar with key info (problem summary, confidence, ticket #). Expandable on tap.
|
|
- Mobile: Single column. Sidebar info moves to a collapsible header. Action bar stays fixed at bottom.
|
|
|
|
**Options Grid:**
|
|
- Desktop: 2-column grid
|
|
- Tablet: 2-column grid (slightly narrower cards)
|
|
- Mobile: Single column stack
|
|
|
|
**Step Cards:**
|
|
- Desktop/Tablet: Full width with padding
|
|
- Mobile: Edge-to-edge cards with reduced padding
|
|
|
|
**Action Bar (Resolve/Escalate):**
|
|
- All sizes: Fixed to bottom of viewport. Buttons full-width on mobile.
|
|
|
|
**Intake Screen:**
|
|
- All sizes: Already mostly responsive (centered card). Ensure textarea and buttons are full-width on mobile.
|
|
|
|
**Modals (Resolve, Escalate, Ticket Picker):**
|
|
- Desktop: Centered modal with max-width
|
|
- Mobile: Full-screen slide-up panel built with Tailwind (`fixed inset-x-0 bottom-0 h-[90vh] rounded-t-2xl` with `translate-y` animation), or full-width modal matching existing modal patterns
|
|
|
|
**Script Generator (in-session):**
|
|
- Desktop: Inline with side-by-side form + preview
|
|
- Mobile: Stacked — form on top, preview below. Preview uses horizontal scroll for long script lines.
|
|
|
|
**Review Queue:**
|
|
- Desktop: Two-panel (list + detail)
|
|
- Mobile: List only, tap to navigate to detail page
|
|
|
|
**Analytics Dashboard:**
|
|
- Desktop: Multi-column chart grid
|
|
- Mobile: Single column, charts stack vertically. Charts resize to viewport width.
|
|
|
|
**Public Templates Gallery:**
|
|
- Desktop: 3-column card grid
|
|
- Tablet: 2-column
|
|
- Mobile: Single column
|
|
|
|
**Testing approach:**
|
|
- Use Chrome DevTools device emulation for iPhone 14 Pro (390px), iPad (810px), and desktop (1440px)
|
|
- Test every FlowPilot page at each breakpoint
|
|
- Ensure no horizontal overflow, no text truncation that hides critical info, all buttons are tappable (minimum 44px touch targets)
|
|
|
|
**Verification:** Open FlowPilot on Chrome DevTools mobile emulation. Start a session. Progress through steps. Resolve. Verify the entire flow is usable on a phone-sized screen. Repeat on tablet size.
|
|
|
|
```
|
|
git commit -m "feat(responsive): mobile/tablet responsive pass for all FlowPilot pages"
|
|
```
|
|
|
|
---
|
|
|
|
## Slice 5: Enterprise Readiness Foundations
|
|
|
|
### Task 10: Custom branding system
|
|
|
|
**Files:**
|
|
- Edit: `backend/app/models/account.py` (or use existing branding model if it exists)
|
|
- Edit: `backend/app/api/endpoints/branding.py` (existing endpoint)
|
|
- Edit: `frontend/src/components/layout/AppLayout.tsx`
|
|
- Edit: `frontend/src/styles/` (CSS variable overrides)
|
|
|
|
**What to add:**
|
|
|
|
Check if branding infrastructure already exists (there's a `branding.py` endpoint and the Product Strategy mentions custom branding for Enterprise). If it does, extend it. If not, build:
|
|
|
|
- Account-level branding settings: logo URL, primary color, sidebar color, company name
|
|
- CSS variable overrides applied at the layout level via inline `style` on the app shell root. Target the exact Tailwind v4 theme variables from `index.css`:
|
|
- `--color-primary` (oklch — main accent, currently cyan `oklch(0.65 0.13 195)`)
|
|
- `--color-primary-foreground` (text on primary backgrounds)
|
|
- `--glass-bg` (card/panel backgrounds)
|
|
- Convert the customer's hex color to oklch using a utility function before applying
|
|
- Logo appears in the sidebar header, replacing the ResolutionFlow logo
|
|
- Company name appears in session exports and shared links
|
|
- Branding settings page in Account Settings (owner-only)
|
|
|
|
**Keep it simple for v1:** Just logo + primary accent color + company name. Full theme customization can come later.
|
|
|
|
**Verification:** Upload a logo and set a custom primary color. Verify the sidebar shows the custom logo. Verify the accent color changes throughout the app. Export a session — verify company name appears.
|
|
|
|
```
|
|
git commit -m "feat(enterprise): add custom branding system"
|
|
```
|
|
|
|
### Task 11: Multi-PSA adapter stubs
|
|
|
|
**Files:**
|
|
- Create: `backend/app/services/psa/autotask/` directory with `__init__.py`, `provider.py`, `client.py`
|
|
- Create: `backend/app/services/psa/halopsa/` directory with `__init__.py`, `provider.py`, `client.py`
|
|
- Edit: `backend/app/services/psa/registry.py`
|
|
|
|
**What to add:**
|
|
|
|
Create stub implementations for Autotask and Halo PSA that extend the existing `PSAProvider` abstract base class. These stubs should:
|
|
|
|
- Implement all abstract methods
|
|
- Raise `NotImplementedError("Autotask integration coming soon")` for each method
|
|
- Include docstrings noting the expected API endpoints and authentication patterns
|
|
- Register in the PSA registry so the provider selection dropdown shows them as "Coming Soon"
|
|
|
|
**Why stubs now:** This establishes the multi-PSA architecture so when it's time to fully implement Autotask or Halo, the structure is ready. It also signals to enterprise prospects that multi-PSA is on the roadmap.
|
|
|
|
**Frontend change:** In the PSA connection setup UI, show Autotask and Halo PSA as options with a "Coming Soon" badge. They should be visible but not selectable.
|
|
|
|
**Verification:** Open the integrations page. See ConnectWise (active), Autotask (Coming Soon badge), Halo PSA (Coming Soon badge).
|
|
|
|
```
|
|
git commit -m "feat(enterprise): add multi-PSA adapter stubs for Autotask and Halo"
|
|
```
|
|
|
|
### Task 12: SSO/SAML groundwork
|
|
|
|
**Files:**
|
|
- Create: `backend/app/services/sso_service.py` (stub)
|
|
- Edit: `backend/app/models/account.py`
|
|
|
|
**What to add:**
|
|
|
|
This is groundwork only — NOT a full SSO implementation. Add:
|
|
|
|
- `sso_enabled` boolean on the Account model (default false)
|
|
- `sso_provider` string on Account (nullable — "saml" | "oidc" | null)
|
|
- `sso_config` JSONB on Account (nullable — will hold IdP metadata URL, entity ID, etc.)
|
|
- A stub `sso_service.py` with the expected interface:
|
|
```python
|
|
async def initiate_sso_login(account_slug: str) -> str: ... # Returns redirect URL
|
|
async def process_sso_callback(saml_response: str) -> User: ... # Returns authenticated user
|
|
async def validate_sso_config(config: dict) -> bool: ... # Tests IdP connectivity
|
|
```
|
|
- Migration for the new columns
|
|
|
|
**Do NOT implement the actual SAML/OIDC flow.** This just establishes the model and service interface so when an enterprise customer needs it, the architecture is ready and the feature flag can be checked.
|
|
|
|
**Frontend:** In Account Settings, show an "SSO / Single Sign-On" section with a "Contact us to enable SSO for your organization" message. This acts as a lead capture for enterprise sales conversations.
|
|
|
|
**Verification:** Check the account model has SSO fields. Verify the settings page shows the SSO section with the contact message.
|
|
|
|
```
|
|
git commit -m "feat(enterprise): add SSO/SAML groundwork (model + stub service)"
|
|
```
|
|
|
|
---
|
|
|
|
## Summary of All New/Modified Files
|
|
|
|
### Backend — New
|
|
```
|
|
app/api/endpoints/public_templates.py # Public gallery API
|
|
app/schemas/public_templates.py # Public gallery schemas
|
|
app/services/notification_service.py # Event-driven notifications (with retry via APScheduler)
|
|
app/models/notification_config.py # Notification channel configs
|
|
app/models/notification_log.py # Notification delivery log (retry tracking)
|
|
app/models/notification.py # In-app notification model
|
|
app/api/endpoints/notifications.py # In-app notification endpoints
|
|
app/schemas/notification.py # Notification schemas
|
|
app/templates/session_export.html # Styled HTML template for PDF export
|
|
app/services/session_export_service.py # PDF/markdown/share export
|
|
app/services/psa/autotask/__init__.py # Autotask stub
|
|
app/services/psa/autotask/provider.py # Autotask provider stub
|
|
app/services/psa/autotask/client.py # Autotask client stub
|
|
app/services/psa/halopsa/__init__.py # Halo PSA stub
|
|
app/services/psa/halopsa/provider.py # Halo PSA provider stub
|
|
app/services/psa/halopsa/client.py # Halo PSA client stub
|
|
app/services/sso_service.py # SSO stub service
|
|
alembic/versions/xxx_phase4_growth.py # Migration
|
|
```
|
|
|
|
### Backend — Modified
|
|
```
|
|
app/api/router.py # Register new routers
|
|
app/api/endpoints/ai_sessions.py # Export + share endpoints
|
|
app/api/endpoints/branding.py # Custom branding extensions
|
|
app/services/flowpilot_engine.py # Notification calls on escalation/high-priority
|
|
app/services/knowledge_flywheel.py # Notification calls on proposal creation
|
|
app/api/endpoints/flow_proposals.py # Notification calls on approval
|
|
app/services/psa/registry.py # Register Autotask + Halo stubs
|
|
app/models/account.py # SSO fields
|
|
app/models/tree.py # is_gallery_featured, gallery_sort_order
|
|
app/models/script_template.py # is_gallery_featured, gallery_sort_order
|
|
```
|
|
|
|
### Frontend — New
|
|
```
|
|
src/pages/PublicTemplatesPage.tsx # Public gallery page
|
|
src/components/public/TemplateGalleryGrid.tsx # Gallery grid layout
|
|
src/components/public/FlowTemplateCard.tsx # Flow card
|
|
src/components/public/ScriptTemplateCard.tsx # Script card
|
|
src/components/public/TemplateDetailModal.tsx # Preview modal with signup CTA
|
|
src/components/public/GallerySearch.tsx # Search component
|
|
src/components/flowpilot/SessionExportMenu.tsx # Export dropdown
|
|
src/components/account/NotificationSettings.tsx # Notification channel config
|
|
src/api/publicTemplates.ts # Public gallery API client
|
|
src/api/notifications.ts # Notifications API client
|
|
src/types/public-templates.ts # Public gallery types
|
|
src/types/notification.ts # Notification types
|
|
```
|
|
|
|
### Frontend — Modified (responsive pass)
|
|
```
|
|
src/components/flowpilot/FlowPilotIntake.tsx
|
|
src/components/flowpilot/FlowPilotSession.tsx
|
|
src/components/flowpilot/FlowPilotStepCard.tsx
|
|
src/components/flowpilot/FlowPilotOptions.tsx
|
|
src/components/flowpilot/FlowPilotActionBar.tsx
|
|
src/components/flowpilot/ConfidenceIndicator.tsx
|
|
src/components/flowpilot/SessionDocView.tsx
|
|
src/components/flowpilot/EscalateModal.tsx
|
|
src/components/flowpilot/EscalationQueue.tsx
|
|
src/components/flowpilot/SessionTicketCard.tsx
|
|
src/components/flowpilot/InSessionScriptGenerator.tsx
|
|
src/pages/ReviewQueuePage.tsx
|
|
src/pages/FlowPilotAnalyticsPage.tsx
|
|
src/pages/PublicTemplatesPage.tsx
|
|
src/router.tsx # Public gallery route + any new routes
|
|
src/components/sidebar/ # Updated with any new nav entries
|
|
src/components/layout/AppLayout.tsx # Custom branding support
|
|
src/pages/account/IntegrationsPage.tsx # Notification settings + PSA stubs
|
|
```
|
|
|
|
---
|
|
|
|
## Database Changes
|
|
|
|
**Migration:** Single migration with multiple changes:
|
|
|
|
```python
|
|
# 1. Gallery featuring columns
|
|
op.add_column('trees', sa.Column('is_gallery_featured', sa.Boolean(), nullable=True, server_default='false'))
|
|
op.add_column('trees', sa.Column('gallery_sort_order', sa.Integer(), nullable=True, server_default='0'))
|
|
op.add_column('script_templates', sa.Column('is_gallery_featured', sa.Boolean(), nullable=True, server_default='false'))
|
|
op.add_column('script_templates', sa.Column('gallery_sort_order', sa.Integer(), nullable=True, server_default='0'))
|
|
|
|
# 2. Notification configs table
|
|
op.create_table('notification_configs', ...)
|
|
|
|
# 3. Notification logs table (retry tracking)
|
|
op.create_table('notification_logs', ...)
|
|
|
|
# 4. In-app notifications table
|
|
op.create_table('notifications', ...)
|
|
|
|
# 5. SSO groundwork on accounts
|
|
op.add_column('accounts', sa.Column('sso_enabled', sa.Boolean(), nullable=True, server_default='false'))
|
|
op.add_column('accounts', sa.Column('sso_provider', sa.String(20), nullable=True))
|
|
op.add_column('accounts', sa.Column('sso_config', sa.dialects.postgresql.JSONB(), nullable=True))
|
|
```
|
|
|
|
**Run migration:**
|
|
```bash
|
|
cd /projects/patherly/backend
|
|
DATABASE_URL=postgresql://postgres:postgres@resolutionflow_postgres:5432/resolutionflow \
|
|
venv/bin/alembic upgrade head
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Strategy
|
|
|
|
### Backend Tests
|
|
|
|
**Files:** `backend/tests/test_public_templates.py`
|
|
- Test gallery endpoint returns only featured templates
|
|
- Test no script bodies exposed
|
|
- Test no deep flow structures exposed
|
|
- Test search functionality
|
|
- Test unauthenticated access works
|
|
|
|
**Files:** `backend/tests/test_notification_service.py`
|
|
- Test event routing to correct channels
|
|
- Test Slack webhook format
|
|
- Test Teams webhook format
|
|
- Test email notification
|
|
- Test disabled events are not sent
|
|
|
|
**Files:** `backend/tests/test_session_export.py`
|
|
- Test PDF generation
|
|
- Test markdown generation
|
|
- Test shareable link creation and expiry
|
|
- Test branding in exports
|
|
|
|
### Frontend Manual Testing
|
|
|
|
1. Open `/templates` without login — browse gallery, search, filter
|
|
2. Click a template — see preview modal with signup CTA
|
|
3. Configure Slack notifications — escalate a session — verify Slack message
|
|
4. Export a session as PDF — verify clean formatting + branding
|
|
5. Share a session — open link in incognito — verify read-only view
|
|
6. Test all FlowPilot pages on mobile viewport (390px)
|
|
7. Test all FlowPilot pages on tablet viewport (810px)
|
|
8. Upload custom branding — verify it appears throughout the app
|
|
9. Check integrations page — verify Autotask and Halo show as "Coming Soon"
|
|
10. Escalate a session — verify bell icon badge appears — click notification — navigates to session
|
|
|
|
---
|
|
|
|
## Low Priority: Gallery Analytics Tracking
|
|
|
|
PostHog is already integrated. When building the public gallery (Slice 1), add these events using `analytics.ts` helpers:
|
|
|
|
- `gallery_viewed` — page load with active filters/category
|
|
- `template_clicked` — which template, flow vs script, position in grid
|
|
- `template_search` — search terms (valuable for understanding MSP needs)
|
|
- `signup_cta_clicked` — from gallery detail modal (conversion tracking)
|
|
|
|
This data reveals which templates drive signups and what topics to create more content around. Implement alongside Tasks 1-2, not as a separate task.
|
|
|
|
---
|
|
|
|
## What Comes Next (Phase 5+ — Future)
|
|
|
|
- **Full Autotask implementation:** Complete the PSA provider for Autotask PSA
|
|
- **Full Halo PSA implementation:** Complete the PSA provider for Halo PSA
|
|
- **Full SSO/SAML implementation:** Complete SAML + OIDC authentication flows
|
|
- **Native mobile app:** React Native or PWA for on-site troubleshooting
|
|
- **AI model selection per account:** Allow enterprise customers to choose model tier (haiku/sonnet/opus)
|
|
- **Webhook API:** Public webhooks for third-party integrations
|
|
- **ConnectWise Marketplace listing:** Package and submit to CW marketplace
|
|
- **White-label option:** Full branding removal for enterprise resellers
|