Skip to main content

Overview

The Notification Center provides a comprehensive system for delivering real-time alerts to users about ticket updates, assignments, status changes, and system events. It supports both in-app notifications and web push notifications.
The notification system consists of three layers: event generation, delivery management, and presentation (in-app and push).

Notification Categories

Notifications are organized into five categories:

Assignments

New ticket assignments and unassignments. Alerts when you’re assigned to a work order.

Comments

New comments added to tickets you’re involved with.

Status Changes

Ticket status updates, priority changes, and finalizations.

Deadlines

Deadline reminders, due soon alerts, and overdue notices.

Admin/System

System announcements and administrative notifications.

Notification Center

Access the Notification Center at /notificaciones to view and manage all notifications:

Feed View

Features:
  • Chronological list of notifications
  • Visual distinction between read/unread
  • Search by title, message, or category
  • Quick mark as read/unread
  • Click to navigate to related entity
  • Real-time updates
Filtering:
Shows all notifications regardless of read status or category.

Settings Panel

Configuration Options:
  1. Push Notifications
    • Enable/disable push on current device
    • Platform-specific instructions
    • Permission status indicator
    • Test notification sender
  2. Category Preferences
    • Toggle each category on/off
    • Affects both in-app and push
    • Saved per user
  3. Admin Tools (if permitted)
    • Send test notifications to any user
    • Search users by name/email
    • View push subscription status
    • Test both in-app and push delivery

Notification States

Each notification has three state timestamps:

Delivered At

When: Notification created and delivered to recipient Meaning: Notification exists in user’s feed Database: notification_deliveries.delivered_at

Seen At

When: User views the notification in the feed Meaning: User has seen the notification (but not necessarily read it) Database: notification_deliveries.seen_at Auto-marked: When notification appears in viewport

Read At

When: User explicitly marks as read or clicks the notification Meaning: User has acknowledged and read the notification Database: notification_deliveries.read_at Affects: Unread count badge

Web Push Notifications

Enabling Push

1

Navigate to Notification Center

Go to /notificaciones in the app.
2

Enable push on device

Click “Push en este dispositivo” button in the settings panel.
3

Grant browser permission

When prompted by the browser, click “Allow” to enable notifications.
4

Test push delivery

Click “Enviar prueba a este dispositivo” to verify push is working.
iOS Requirements:
  • Must use installed PWA (not Safari browser)
  • Requires iOS 16.4 or later
  • Must be on HTTPS domain
  • Permission prompt appears on first PWA launch

Platform-Specific Instructions

iOS (iPhone/iPad):
  • Install app to home screen first
  • Open installed PWA
  • Allow notifications when prompted
  • Check Settings > [App Name] > Notifications
Android:
  • Browser or PWA supported
  • Allow notifications when prompted
  • Check Settings > Apps > [Browser/App] > Notifications
Windows:
  • Browser permission prompt
  • Check Settings > System > Notifications
  • Verify browser notifications enabled
macOS:
  • Browser permission prompt
  • Check System Preferences > Notifications
  • Verify browser notifications enabled

Push Architecture

Components:
  1. Subscription - Device registers with push service
    • Table: web_push_subscriptions
    • Stores endpoint, keys, user_agent
    • One per device per user
  2. Outbox - Queue for pending push messages
    • Table: web_push_outbox
    • Created by triggers on notification events
    • Processed by Edge Function
  3. Edge Function - Sends push messages
    • Function: send-push-from-outbox
    • Triggered by cron (every minute)
    • Uses Web Push protocol
    • Marks delivered or failed
  4. Client - Receives and displays push
    • Service worker intercepts
    • Shows browser notification
    • Handles click to open app
Flow:
Event → Trigger → Outbox Entry → Edge Function → Push Service → Device

Event System

Notification Events

Stored in notification_events table:
interface NotificationEvent {
  id: string; // UUID
  event_type: string; // e.g., 'ticket.assigned'
  actor_user_id: string | null; // Who triggered the event
  entity_type: string; // e.g., 'ticket'
  entity_id: string; // e.g., ticket ID
  payload: Record<string, unknown>; // Custom data
  created_at: string;
}

Common Event Types

Ticket Events:
  • ticket.created
  • ticket.assigned
  • ticket.unassigned
  • ticket.status_changed
  • ticket.accepted
  • ticket.finalized
  • ticket.comment_added
  • ticket.priority_changed
  • ticket.urgent_changed
  • ticket.deadline_set
  • ticket.deadline_changed
  • ticket.due_soon
  • ticket.overdue

Delivery Records

Each event creates one or more deliveries:
interface NotificationDelivery {
  id: string; // UUID
  event_id: string; // References notification_events
  recipient_user_id: string;
  channel_mask: number; // Bitmask: 1=in-app, 2=push, 4=email
  read_at: string | null;
  seen_at: string | null;
  delivered_at: string | null;
  created_at: string;
}

Service Integration

Listing Notifications

import { listNotifications } from '@/services/notificationCenterService';

const { items, total } = await listNotifications({
  scope: 'unread', // 'all' | 'unread' | 'tickets' | 'admin'
  offset: 0,
  limit: 20,
});

items.forEach((item) => {
  console.log(item.title, item.message, item.category);
});
See ~/workspace/source/src/services/notificationCenterService.ts:290 for implementation.

Marking as Read

import { markNotificationRead, markAllNotificationsRead } from '@/services/notificationCenterService';

// Mark single notification
await markNotificationRead(deliveryId);

// Mark all notifications
await markAllNotificationsRead();
See ~/workspace/source/src/services/notificationCenterService.ts:365 and :395.

Unread Count

import { getUnreadNotificationsCount } from '@/services/notificationCenterService';

const count = await getUnreadNotificationsCount();
console.log(`${count} unread notifications`);
See ~/workspace/source/src/services/notificationCenterService.ts:349.

Preferences

import { 
  getMyNotificationPreferences, 
  saveMyNotificationPreferences 
} from '@/services/notificationCenterService';

// Load preferences
const prefs = await getMyNotificationPreferences();

// Update preferences
const updated = await saveMyNotificationPreferences({
  push_enabled: true,
  categories: {
    assignments: true,
    comments: true,
    status_changes: true,
    deadlines: true,
    admin_system: false,
  },
});
See ~/workspace/source/src/services/notificationCenterService.ts:428 and :448.

Real-time Subscription

import { subscribeToMyNotificationDeliveries } from '@/services/notificationCenterService';

const unsubscribe = subscribeToMyNotificationDeliveries(
  userId,
  () => {
    // Callback when new notification arrives
    refreshNotifications();
  }
);

// Clean up on unmount
return () => unsubscribe();
See ~/workspace/source/src/services/notificationCenterService.ts:565.

Data Model

NotificationItem

Frontend representation:
type NotificationItem = {
  deliveryId: string;
  eventId: string;
  eventType: string; // e.g., 'ticket.assigned'
  actorUserId: string | null;
  entityType: string; // e.g., 'ticket'
  entityId: string;
  category: NotificationCategory;
  channelMask: number;
  title: string;
  message: string;
  url: string; // Navigation target
  createdAt: string;
  readAt: string | null;
  seenAt: string | null;
  deliveredAt: string | null;
  payload: Record<string, unknown>;
};

NotificationPreferences

User configuration:
type NotificationPreferences = {
  push_enabled: boolean;
  categories: Record<NotificationCategory, boolean>;
  quiet_hours?: {
    from?: string; // e.g., '22:00'
    to?: string;   // e.g., '08:00'
  };
};

NotificationCategory

Category enum:
type NotificationCategory =
  | 'assignments'
  | 'comments'
  | 'status_changes'
  | 'deadlines'
  | 'admin_system';

UI Components

NotificationCenterPage

Main page at ~/workspace/source/src/pages/NotificationCenterPage.tsx:102 Features:
  • Feed with filtering and search
  • Settings panel with preferences
  • Push onboarding guide
  • Admin test tools
  • Responsive mobile/desktop layout

SwipeableNotificationCard

Interactive card at ~/workspace/source/src/components/notifications/SwipeableNotificationCard.tsx Gestures:
  • Tap to open
  • Swipe right for quick actions
  • Long press for context menu

Badge Components

Unread count badge in app header:
import { useUnreadNotificationsCount } from '@/hooks/useUnreadNotificationsCount';

const count = useUnreadNotificationsCount();

{count > 0 && (
  <span className="badge">{count}</span>
)}

Permissions

View Notifications

All authenticated users can:
  • View their own notifications
  • Mark notifications as read/unread
  • Configure preferences
  • Enable/disable push

Send Test Notifications

Requires one of:
  • users:full_access
  • rbac:manage_permissions
Allows:
  • Search all users
  • Send test notifications to any user
  • View push subscription status

Performance

Pagination

  • Default page size: 20 notifications
  • Client-side pagination controls
  • Server-side filtering and counting
  • Efficient range(offset, limit) queries

Caching

  • Unread count cached in memory
  • Refreshed on notification events
  • Invalidated on mark as read/unread

Real-time Efficiency

  • Uses Supabase Realtime channels
  • Filters by recipient_user_id
  • Only subscribes to own notifications
  • Automatic reconnection on disconnect

Troubleshooting

Push not working

Symptoms: “Permission blocked” messageSolution:
  1. Check browser notification settings
  2. Reset site permissions
  3. Re-enable push in app
  4. Test with self-test button

Notifications not appearing

  • Check category preferences (might be disabled)
  • Verify RLS policies allow access
  • Confirm event was created
  • Check delivery records in database
  • Review browser console for errors

Unread count wrong

  • Refresh the page
  • Mark all as read and verify
  • Check read_at in database
  • Clear browser cache

Best Practices

For Users

  1. Enable Push - Stay informed of urgent updates
  2. Review Daily - Check notification center regularly
  3. Mark as Read - Keep unread count manageable
  4. Configure Categories - Disable categories you don’t need
  5. Test Regularly - Verify push works after device changes

For Developers

  1. Use Correct Event Types - Follow naming convention
  2. Populate Payload - Include useful context data
  3. Set Meaningful Titles - Make notifications actionable
  4. Test on All Platforms - iOS, Android, desktop
  5. Handle Errors Gracefully - Push may fail, show in-app

For Admins

  1. Monitor Outbox - Check for stuck messages
  2. Review Edge Function Logs - Identify delivery issues
  3. Validate VAPID Keys - Ensure configured correctly
  4. Test User Notifications - Use admin test tool
  5. Clean Old Notifications - Archive old deliveries