Files
resolutionflow/docs/archive/2026-02-07-notification-system-design.md
chihlasm 350c977eda feat: add procedural flows with intake forms, navigation, and seed templates
Adds a new "procedural" tree type for linear step-by-step project workflows
(domain controller setup, M365 onboarding, VPN config, etc). Includes intake
form builder, two-panel step navigation, variable resolution, procedural
exports, 3 seed templates, and UI rename from "Trees" to "Flows".

Also archives 19 implemented plan docs and creates deferred features backlog.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 04:13:52 -05:00

16 KiB

Tier 1 UX Enhancement: Consistent Notification System

Context

ResolutionFlow (Patherly) currently lacks a consistent feedback system for user actions. MSP engineers switching between multiple contexts need immediate confirmation that actions succeeded to reduce cognitive load and prevent errors. Research shows that 200-300ms feedback timing dramatically improves perceived reliability and user confidence.

Current State Problems

  • No success notifications: Users don't get confirmation when trees/folders/sessions are saved or deleted
  • Inconsistent patterns: Mix of button state changes, modal errors, and page-level banners
  • Silent operations: "Add to Folder" silently succeeds with no feedback
  • No dismissible errors: Error messages persist until page reload or modal close
  • No notification history: Users can't review recent actions

User Impact

Engineers experience cognitive overload troubleshooting client issues. Without clear feedback:

  • They second-guess themselves and repeat actions
  • They abandon tasks when uncertain if changes saved
  • They miss critical errors that appear briefly
  • They waste time verifying actions succeeded

Why This Feature First

  1. Foundational infrastructure: Toast system benefits all future features
  2. Immediate wins: Every save/delete/export action gets better UX
  3. Low risk: Additive feature, doesn't break existing flows
  4. Quick implementation: 1-2 days to full deployment
  5. High perceived value: Users notice and appreciate immediate feedback

Design Overview

We'll integrate sonner (by shadcn creator) - a modern, accessible toast notification library that:

  • Works perfectly with Tailwind CSS and our dark mode
  • Provides beautiful default styling matching our design system
  • Supports promise tracking (show loading → success/error automatically)
  • Handles stacking, positioning, and auto-dismiss elegantly
  • Only ~10KB gzipped
  • Fully accessible (ARIA attributes, keyboard navigation)

Architecture: Toast as Global Service

frontend/src/
  ├── main.tsx
  │   └── Wrap <App> with <Toaster /> provider
  │
  ├── lib/
  │   └── toast.ts (re-export sonner's toast with custom defaults)
  │
  ├── components/
  │   ├── library/TreeLibraryPage.tsx (add toast.success on delete)
  │   ├── library/FolderEditModal.tsx (add toast.success on save)
  │   ├── tree-editor/TreeEditorPage.tsx (replace error banner with toast)
  │   ├── session/SessionDetailPage.tsx (add toast on export)
  │   └── ...other components using toast
  │
  └── api/
      └── client.ts (optional: global error toast interceptor)

Key Design Decisions:

  1. Single import point: import { toast } from '@/lib/toast' everywhere
  2. Custom defaults: Pre-configured duration, position, dark mode sync
  3. Promise pattern: Use toast.promise() for async operations
  4. Consistent vocabulary: "Saved", "Deleted", "Exported" (not "Success!")
  5. Error details: Show action + reason ("Failed to delete tree: Network error")

Implementation Plan

Phase 1: Install and Configure Sonner

1.1 Install dependencies

cd patherly/frontend
npm install sonner

1.2 Create toast utility wrapper (frontend/src/lib/toast.ts):

import { toast as sonnerToast } from 'sonner';

// Re-export with custom defaults
export const toast = {
  success: (message: string, options?: any) =>
    sonnerToast.success(message, { duration: 4000, ...options }),

  error: (message: string, options?: any) =>
    sonnerToast.error(message, { duration: 6000, ...options }),

  info: (message: string, options?: any) =>
    sonnerToast.info(message, { duration: 4000, ...options }),

  loading: (message: string, options?: any) =>
    sonnerToast.loading(message, { ...options }),

  promise: sonnerToast.promise,
  dismiss: sonnerToast.dismiss
};

1.3 Add Toaster provider to frontend/src/main.tsx:

import { Toaster } from 'sonner';

// Inside root render, wrap App:
<React.StrictMode>
  <Toaster
    position="top-right"
    richColors
    closeButton
    theme={themeStore.theme === 'dark' ? 'dark' : 'light'}
  />
  <App />
</React.StrictMode>

1.4 Sync theme with Toaster: Update themeStore.ts to re-render Toaster on theme change


Phase 2: Add Notifications to Core Actions

Success notifications to add:

Component Action Toast Message Type
TreeLibraryPage Delete tree "Tree deleted" success
FolderEditModal Save folder "Folder saved" success
FolderSidebar Delete folder "Folder deleted" success
AddToFolderMenu Add tree to folder "Added to {folderName}" success
AddToFolderMenu Remove from folder "Removed from {folderName}" success
TreeEditorPage Save tree "Tree saved" success
TreeEditorPage Publish tree "Tree published" success
SessionDetailPage Export session "Session exported" success
SettingsPage Save preferences "Settings saved" success
AccountSettingsPage Update account "Account updated" success

2.1 Tree Library Actions (TreeLibraryPage.tsx):

  • Remove confirmation dialog result logging
  • Add toast.success('Tree deleted') after successful delete
  • Replace inline error state with toast.error(error)

2.2 Folder Management (FolderEditModal.tsx, FolderSidebar.tsx):

  • Add success toast on folder create/update/delete
  • Remove inline error messages (use toast.error instead)
  • Keep loading state but add toast feedback on completion

2.3 Tree Editor (TreeEditorPage.tsx):

  • Replace current error banner with toast notifications
  • Add toast.promise() for autosave operations:
    toast.promise(saveTree(), {
      loading: 'Saving tree...',
      success: 'Tree saved',
      error: 'Failed to save tree'
    });
    
  • Remove saveError state and error banner div

2.4 Session Export (SessionDetailPage.tsx):

  • Add toast on successful export: toast.success('Session exported')
  • Add toast on copy to clipboard: toast.success('Copied to clipboard')
  • Replace current inline copy feedback with toast

2.5 Settings Pages:

  • Add success toasts on settings save
  • Remove inline success messages if any exist

Phase 3: Standardize Error Handling

3.1 Global API Error Interceptor (client.ts):

apiClient.interceptors.response.use(
  response => response,
  error => {
    // Show toast for non-form errors (4xx/5xx)
    const message = error.response?.data?.detail || 'An error occurred';

    // Don't toast validation errors (handled inline)
    if (error.response?.status !== 422) {
      toast.error(message);
    }

    return Promise.reject(error);
  }
);

3.2 Remove redundant error handling:

  • Keep form validation errors inline (modal errors)
  • Use toast for unexpected/network errors
  • Remove page-level error banner states where replaced by toast

Phase 4: Add Copy Feedback Consistency

4.1 Standardize clipboard operations: All "Copy to Clipboard" buttons should:

  1. Use navigator.clipboard.writeText()
  2. Show toast on success: toast.success('Copied to clipboard')
  3. Show toast on error: toast.error('Failed to copy')
  4. Remove button state toggle (icon + text change)

Components to update:


Critical Files to Modify

File Path Changes
patherly/frontend/package.json Add sonner dependency
patherly/frontend/src/main.tsx Add <Toaster> provider component
patherly/frontend/src/lib/toast.ts NEW FILE - Toast utility wrapper
patherly/frontend/src/store/themeStore.ts Sync theme changes to Toaster
patherly/frontend/src/api/client.ts Add global error interceptor
patherly/frontend/src/pages/TreeLibraryPage.tsx Add success/error toasts for delete
patherly/frontend/src/pages/TreeEditorPage.tsx Replace error banner with toast.promise()
patherly/frontend/src/pages/SessionDetailPage.tsx Add export/copy success toasts
patherly/frontend/src/pages/SettingsPage.tsx Add settings save toast
patherly/frontend/src/pages/AccountSettingsPage.tsx Add account update toast
patherly/frontend/src/components/library/FolderEditModal.tsx Add folder save toast, remove inline errors
patherly/frontend/src/components/library/FolderSidebar.tsx Add delete folder toast
patherly/frontend/src/components/library/AddToFolderMenu.tsx Add add/remove from folder toasts
patherly/frontend/src/components/session/ExportPreviewModal.tsx Standardize copy feedback

Design Patterns and Best Practices

When to Use Each Toast Type

Success (green, 4s duration):

  • Action completed successfully
  • Examples: "Tree saved", "Folder deleted", "Exported"
  • Only show for user-initiated actions, not automatic operations

Error (red, 6s duration):

  • Action failed unexpectedly
  • Examples: "Failed to save tree: Network error", "Could not delete folder"
  • Include reason when available from API response

Info (blue, 4s duration):

  • Neutral information
  • Examples: "Session resumed", "Autosave enabled"
  • Use sparingly - don't spam user with info toasts

Loading (infinite duration until dismissed):

  • Long-running operations (>500ms expected)
  • Examples: "Saving tree...", "Exporting session..."
  • Use toast.promise() to automatically transition to success/error

Promise Pattern Best Practice

For async operations with loading states:

// DON'T do this (manual dismiss logic):
const toastId = toast.loading('Saving...');
try {
  await saveTree();
  toast.success('Saved', { id: toastId });
} catch (error) {
  toast.error('Failed', { id: toastId });
}

// DO this (automatic state transitions):
toast.promise(saveTree(), {
  loading: 'Saving tree...',
  success: 'Tree saved',
  error: (err) => `Failed to save: ${err.message}`
});

Error Message Format

Always provide context:

  • "Error" (too vague)
  • "Failed" (what failed?)
  • "Failed to delete tree: Permission denied"
  • "Could not load folders: Network error"

When NOT to Use Toasts

Keep inline error messages for:

  1. Form validation errors: Show next to invalid field
  2. Modal-contained errors: Errors within a modal workflow
  3. Real-time feedback: Input validation as user types
  4. Critical blocking errors: Full-page error states

Verification Plan

Manual Testing Checklist

Tree Operations:

  • Create new tree → "Tree saved" toast appears
  • Edit existing tree → "Tree saved" toast appears
  • Delete tree → Confirm dialog → "Tree deleted" toast appears
  • Delete fails (network off) → "Failed to delete tree" toast with reason
  • Autosave triggers → "Tree saved" toast (via promise pattern)

Folder Operations:

  • Create folder → "Folder saved" toast appears
  • Edit folder name → "Folder saved" toast appears
  • Delete folder → "Folder deleted" toast appears
  • Add tree to folder → "Added to [folder name]" toast appears
  • Remove tree from folder → "Removed from [folder name]" toast appears

Session Operations:

  • Export session (any format) → "Session exported" toast appears
  • Copy to clipboard → "Copied to clipboard" toast appears
  • Copy fails (permissions) → "Failed to copy" toast appears
  • Download session → "Session exported" toast appears

Settings:

  • Save user preferences → "Settings saved" toast appears
  • Update account details → "Account updated" toast appears

Error Scenarios:

  • Network offline → API errors show toast with meaningful message
  • Permission denied → Toast shows "Permission denied" reason
  • 500 server error → Toast shows generic "Server error" message
  • 422 validation error → NO toast (inline validation only)

Dark Mode:

  • Switch to dark mode → Toast background is dark themed
  • Switch to light mode → Toast background is light themed
  • Toast colors match theme (success green, error red, etc.)

Accessibility:

  • Screen reader announces toast messages (ARIA live region)
  • Toasts can be dismissed with keyboard (close button focusable)
  • Toast position doesn't obscure critical UI (top-right safe zone)
  • Color contrast meets WCAG AA standards

Stacking Behavior:

  • Multiple toasts stack vertically without overlap
  • Oldest toasts auto-dismiss while newer ones remain
  • Maximum 3-4 toasts visible at once (sonner default)

Rollout Strategy

Phase 1: Core Infrastructure (Day 1, Morning)

  1. Install sonner package
  2. Create toast utility wrapper (lib/toast.ts)
  3. Add Toaster provider to main.tsx
  4. Sync with theme store
  5. Test basic toast functionality in dev

Phase 2: High-Impact Actions (Day 1, Afternoon)

  1. Tree save/delete operations
  2. Folder CRUD operations
  3. Session export/copy
  4. Remove old error banners

Phase 3: Error Standardization (Day 2, Morning)

  1. Add global API error interceptor
  2. Clean up redundant error handling
  3. Test error scenarios (network offline, permissions, etc.)

Phase 4: Refinement (Day 2, Afternoon)

  1. Verify all toast messages use consistent vocabulary
  2. Check dark mode appearance
  3. Test accessibility with screen reader
  4. Performance check (ensure no memory leaks from unmounted toasts)
  5. Update user documentation if needed

Future Enhancements (Out of Scope)

These can be added later if needed:

  • Undo actions: Toast with "Undo" button for reversible operations
  • Progress toasts: Show percentage for uploads/exports
  • Grouped toasts: Collapse multiple similar actions ("3 trees deleted")
  • Persistent notifications: Critical alerts that don't auto-dismiss
  • Sound effects: Subtle audio feedback (accessibility feature)
  • Action buttons in toasts: "View details" or "Retry" buttons

Risks and Mitigation

Risk Impact Mitigation
Toast spam Users annoyed by too many notifications Only toast user-initiated actions, not automatic events
Theme sync issues Toast theme doesn't match app theme Subscribe to themeStore changes, update Toaster theme prop
Mobile viewport Toasts obscure content on small screens Use top-right position (least obtrusive), verify on mobile
Bundle size increase +10KB to frontend bundle Acceptable for significant UX improvement; sonner is already optimized
Breaking existing error handling Some errors go unnoticed Keep inline validation errors; only replace page-level banners

Success Metrics

Qualitative:

  • Users report feeling more confident about action completion
  • Support tickets decrease for "Did my changes save?" questions
  • User feedback mentions improved responsiveness

Quantitative:

  • 0 console errors related to toast implementation
  • Toast render time <50ms (measured in React DevTools)
  • No accessibility violations in Lighthouse audit
  • Frontend bundle size increase <15KB gzipped

References