# 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