# 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
