Notification System Strategy
Current State
The application already has a notification infrastructure:
- ✅ Firestore storage:
orgs/{orgId}/activityLogscollection - ✅ PWA notification support via service worker
- ✅ Real-time subscriptions via
usePWANotificationshook - ✅ Notification page at
/org/{orgId}/hr/notifications - ✅ Activity log types for contracts, messages, applications, members
Recommended Architecture
1. Firestore Structure
Organization-Level Notifications (Current)
Path: orgs/{orgId}/activityLogs/{logId}
Keep this for organization-scoped activities:
- Application approvals/rejections
- Contract signings
- Member invitations
- Messages within organization
- Application stage changes
User-Level Notifications (New)
Path: users/{userId}/notifications/{notificationId}
Add this for user-scoped notifications that may span multiple organizations:
- Cross-org messages
- Global system updates
- Personal reminders
- Application status across all orgs
2. Notification Types
Add Missing Types to OrgActivityLog:
typescript
type OrgActivityLogType =
| 'application_approved' // NEW: When candidate is approved
| 'application_rejected' // NEW: When candidate is rejected
| 'application_stage_changed' // EXISTS
| 'application_created' // EXISTS
| 'message_sent' // EXISTS
| 'contract_signed' // EXISTS
| 'member_invited' // EXISTS
| 'member_joined' // EXISTS
| 'member_removed' // EXISTS
// ... other existing typesUser Notification Type:
typescript
type UserNotificationType =
| 'application_approved' // From any org
| 'application_rejected' // From any org
| 'message_received' // Cross-org messages
| 'system_update' // Platform updates
| 'reminder' // Personal reminders3. Notification Interface
typescript
interface Notification {
id?: string;
type: string;
title: string;
body: string;
userId: string; // Target user
orgId?: string; // Optional: org context
read: boolean; // NEW: Read status
readAt?: Date | Timestamp; // NEW: When read
createdAt: Date | Timestamp;
actionUrl?: string; // URL to navigate on click
metadata?: Record<string, any>;
}4. Implementation Plan
Phase 1: Enhance Current System
- Add
readandreadAtfields toOrgActivityLog - Add
application_approvedandapplication_rejectedtypes - Update
NotificationServiceto log approvals/rejections - Update
NotificationsPageto show unread count and mark as read
Phase 2: Add User-Level Notifications
- Create
users/{userId}/notificationscollection - Create
UserNotificationServicefor user-scoped notifications - Update
usePWANotificationsto listen to both org and user notifications - Create global notifications page at
/notifications
Phase 3: Enhanced Features
- Notification preferences (what to receive)
- Notification grouping (e.g., "3 new messages")
- Notification actions (e.g., "Approve" button in notification)
- Badge count in UI
Implementation Details
1. Update NotificationService
Add functions for application approvals/rejections:
typescript
export const logApplicationApproved = async (
orgId: string,
applicationId: string,
candidateUserId: string,
candidateName: string,
approvedByUserId: string
): Promise<void> => {
await createActivityLog(orgId, {
type: 'application_approved',
userId: approvedByUserId,
targetUserId: candidateUserId,
action: `Your application has been approved!`,
metadata: {
applicationId,
candidateName,
},
});
};
export const logApplicationRejected = async (
orgId: string,
applicationId: string,
candidateUserId: string,
candidateName: string,
rejectedByUserId: string,
reason?: string
): Promise<void> => {
await createActivityLog(orgId, {
type: 'application_rejected',
userId: rejectedByUserId,
targetUserId: candidateUserId,
action: `Your application was not selected at this time.`,
metadata: {
applicationId,
candidateName,
reason,
},
});
};2. Update NotificationsPage
Add read/unread functionality:
typescript
// Mark notification as read
const markAsRead = async (logId: string) => {
await updateDoc(orgActivityLogsRef(orgId).doc(logId), {
read: true,
readAt: serverTimestamp(),
});
};
// Get unread count
const unreadCount = logs.filter(log => !log.read).length;3. Update usePWANotifications Hook
Enhance to handle all notification types:
typescript
// Add notification titles for new types
function getNotificationTitle(type: OrgActivityLog['type']): string {
switch (type) {
case 'application_approved':
return 'Application Approved! 🎉';
case 'application_rejected':
return 'Application Update';
case 'message_sent':
return 'New Message';
// ... existing cases
}
}4. PWA Notification Delivery
The current PWA setup already handles notifications via:
- Service worker (
public/sw.js) - receives push events usePWANotificationshook - subscribes to Firestore changesshowNotificationutility - displays browser notifications
No changes needed - it will automatically work for new notification types!
Benefits of This Approach
- Scalable: Separate org and user notifications
- Flexible: Can add new notification types easily
- User-Friendly: Read/unread status, unread counts
- Real-Time: Firestore subscriptions provide instant updates
- PWA-Ready: Already integrated with service worker
- Backward Compatible: Enhances existing system without breaking changes
Next Steps
- ✅ Review and approve this strategy
- Implement Phase 1 (enhance current system)
- Test notification delivery via PWA
- Implement Phase 2 (user-level notifications)
- Add notification preferences UI