Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Quick Reference: Top 5 actionable improvements that can be implemented immediately

1. 🔴 Fix Push Notification Security Issue (30 min)

Critical: Multi-tenancy vulnerability in push subscriptions. Fix:
-- Migration: Fix endpoint uniqueness constraint
ALTER TABLE pf_push_subscriptions 
DROP CONSTRAINT IF EXISTS pf_push_subscriptions_endpoint_key;

ALTER TABLE pf_push_subscriptions
ADD CONSTRAINT pf_push_subscriptions_user_endpoint_unique 
UNIQUE (user_id, endpoint);

-- Add UPDATE RLS policy
CREATE POLICY "pf_push_subscriptions_update" ON pf_push_subscriptions
  FOR UPDATE USING (user_id = auth.uid());
Update edge function:
// supabase/functions/save-push-subscription/index.ts
.upsert({...}, {
  onConflict: 'user_id,endpoint', // Composite key
})

2. 🔴 Complete Push Notification Implementation (4-6 hours)

Current: TODO in send-push-notification function. Add to edge function:
import { webpush } from 'https://deno.land/x/webpush@v1.0.0/mod.ts';

// Replace TODO section with:
const subscription = {
  endpoint: sub.endpoint,
  keys: { p256dh: sub.p256dh_key, auth: sub.auth_key },
};

await webpush.sendNotification(subscription, payload, {
  vapidDetails: {
    subject: VAPID_SUBJECT,
    publicKey: VAPID_PUBLIC_KEY,
    privateKey: VAPID_PRIVATE_KEY,
  },
});
Add service worker handler:
// In VitePWA service worker or public/sw.js
self.addEventListener('push', (event) => {
  const data = event.data?.json() || {};
  event.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: data.icon || '/icons/icon-192x192.png',
      badge: '/icons/badge-72x72.png',
      data: { url: data.action_url || '/' },
    })
  );
});

self.addEventListener('notificationclick', (event) => {
  event.notification.close();
  event.waitUntil(
    clients.openWindow(event.notification.data?.url || '/')
  );
});

3. 🟠 Add Notification Quick Actions (2-3 hours)

Enhancement: Allow users to approve/reject directly from notification. Implementation:
// src/platform/notifications/utils/notificationActions.ts
export const getNotificationActions = (type: notification_type) => {
  const actions: Record<notification_type, Action[]> = {
    approval_request: [
      { label: 'Approve', action: 'approve', icon: CheckCircle },
      { label: 'Reject', action: 'reject', variant: 'destructive' },
    ],
    // ... other types
  };
  return actions[type] || [];
};
Add to NotificationItem:
{actions.length > 0 && (
  <div className="flex gap-2 mt-2">
    {actions.map((action) => (
      <Button
        key={action.action}
        size="sm"
        variant={action.variant}
        onClick={() => handleAction(action.action)}
      >
        {action.label}
      </Button>
    ))}
  </div>
)}

4. 🟠 Add Notification Grouping (3-4 hours)

Enhancement: Group related notifications (e.g., 5 form submissions in 5 minutes). Implementation:
// src/platform/notifications/utils/notificationGrouping.ts
export const groupNotifications = (
  notifications: Notification[],
  timeWindowMinutes = 5
): NotificationGroup[] => {
  const groups = new Map<string, Notification[]>();
  
  notifications.forEach((notif) => {
    const key = `${notif.type}-${notif.data?.entity_id || 'none'}`;
    const existing = groups.get(key) || [];
    
    if (existing.length > 0) {
      const latest = new Date(existing[0].created_at);
      const current = new Date(notif.created_at);
      const diffMinutes = (current.getTime() - latest.getTime()) / 60000;
      
      if (diffMinutes > timeWindowMinutes) {
        groups.set(`${key}-${notif.id}`, [notif]);
        return;
      }
    }
    
    existing.unshift(notif);
    groups.set(key, existing);
  });
  
  return Array.from(groups.entries()).map(([key, group]) => ({
    id: group[0].id,
    type: group[0].type,
    title: group[0].title,
    count: group.length,
    notifications: group,
  }));
};

5. 🟡 Add App Badge Updates (1 hour)

Enhancement: Show unread count on app icon. Implementation:
// src/platform/notifications/useNotifications.ts
useEffect(() => {
  if ('setAppBadge' in navigator && unreadCount !== undefined) {
    if (unreadCount > 0) {
      navigator.setAppBadge(unreadCount);
    } else {
      navigator.clearAppBadge();
    }
  }
}, [unreadCount]);

Priority Order

  1. Security Fix (P0) - Do immediately
  2. Complete Push (P0) - Critical for production
  3. Quick Actions (P1) - High user value
  4. Grouping (P1) - Reduces inbox clutter
  5. App Badge (P2) - Nice UX enhancement
Total Estimated Time: 1-2 days for all 5 items
See full recommendations for complete details.