10 KiB
🔔 Notification System Setup Guide
Overview
The notification system has been implemented to notify users about:
- ✅ Action Notifications: When users upload, analyze, or delete contracts
- 🕐 Deadline Notifications: When contracts are expiring (30, 15, 7 days)
- 📱 Toast Notifications: Immediate UI feedback for all actions
- 🔔 Notification Center: Persistent notification history accessible from the dashboard
Database Migration
Step 1: Update Your Database Schema
Run the following Prisma command to create the necessary database tables:
npx prisma migrate dev --name add_notifications
This will:
- Create the
Notificationtable - Create the
NotificationTypeenum - Add the
notificationsrelationship to theUsermodel - Add the
notificationsrelationship to theContractmodel
Step 2: Database Schema Overview
The migration adds:
-- Notification table with indexes
CREATE TABLE "Notification" (
id TEXT PRIMARY KEY,
userId TEXT NOT NULL,
contractId TEXT,
type "NotificationType" NOT NULL,
title VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
icon VARCHAR(100),
actionType VARCHAR(100),
actionData JSONB,
read BOOLEAN DEFAULT false,
createdAt TIMESTAMP DEFAULT now(),
expiresAt TIMESTAMP,
FOREIGN KEY (userId) REFERENCES "User"(id) ON DELETE CASCADE,
FOREIGN KEY (contractId) REFERENCES "Contract"(id) ON DELETE SET NULL
);
-- Notification Type Enum
CREATE TYPE "NotificationType" AS ENUM (
'SUCCESS',
'WARNING',
'ERROR',
'INFO',
'DEADLINE'
);
Architecture Overview
1. Notification Service (lib/services/notification.service.ts)
Core service handling all notification operations:
- Create notifications
- Fetch unread/all notifications
- Mark as read
- Delete notifications
- Check for upcoming deadlines
- Cleanup expired notifications
Key Methods:
create(input)- Create new notificationgetUnread(userId, limit)- Fetch unread notificationsgetUnreadCount(userId)- Get badge countcheckUpcomingDeadlines(userId)- Scan contracts and create deadline notificationscleanupExpired()- Remove expired notifications (run periodically)
2. Notification Actions (lib/actions/notification.action.ts)
Server actions for client-side notification management:
getNotifications()- Fetch unread notificationsgetAllNotifications()- Fetch notification historygetUnreadNotificationCount()- Get badge countmarkNotificationAsRead(id)- Mark single as readmarkAllNotificationsAsRead()- Mark all as readdeleteNotification(id)- Delete notificationcheckDeadlineNotifications()- Check and create deadline notifications
3. Notification Component (components/views/dashboard/notification-bar.tsx)
Beautiful notification UI dropdown with:
- Bell icon with unread count badge
- Notification list with type-specific icons and colors
- Action buttons (mark as read, delete)
- Time formatting (e.g., "2m ago")
- Empty state
- Auto-refresh every 30 seconds when open
- Daily deadline check
4. useNotifications Hook (hooks/useNotifications.ts)
Custom React hook wrapping Sonner toast + persistent notifications:
notifySuccess()- Green success toast + persistent notificationnotifyError()- Red error toast + persistent notificationnotifyWarning()- Yellow warning toast + persistent notificationnotifyInfo()- Blue info toast + persistent notificationnotifyDeadline()- Red deadline toast + persistent notification
Integration Points
1. Contract Actions (lib/actions/contract.action.ts)
Updated to create notifications on:
- ✅ Upload: "Contract uploaded successfully"
- ✅ Analysis: "Contract analyzed successfully" or error message
- ✅ Delete: "Contract deleted successfully"
- ✅ Ask Question: Error notification if Q&A fails
2. Dashboard (app/(dashboard)/dashboard/page.tsx)
- Calls
checkDeadlineNotifications()on page load - Checks for contracts expiring in 30, 15, 7 days
- Creates notifications automatically
3. Navigation (components/views/dashboard/navigation.tsx)
- Added
NotificationBarcomponent to sidebar - Positioned next to theme toggle in account section
- Accessible from all dashboard pages
Usage Examples
Creating a Notification in Server Actions
import { NotificationService } from "@/lib/services/notification.service";
// In a server action
const user = await ContractService.getUserByClerkId(clerkId);
await NotificationService.create({
userId: user.id,
type: "SUCCESS",
title: "Contract Uploaded",
message: 'Your file "insurance.pdf" is ready for analysis',
contractId: contractId,
actionType: "UPLOAD_SUCCESS",
icon: "FileCheck",
expiresIn: 7 * 24 * 60 * 60 * 1000, // 7 days
});
Using Toast Notifications in Client Components
import { useNotifications } from "@/hooks/useNotifications";
export function MyComponent() {
const { notifySuccess, notifyError, notifyDeadline } = useNotifications();
const handleUpload = async () => {
try {
await uploadFile();
notifySuccess("Upload Complete", "Your file has been uploaded");
} catch (error) {
notifyError("Upload Failed", error.message);
}
};
const handleDeadline = () => {
notifyDeadline({
title: "🔴 Contract Expiring Soon",
message: "Insurance Auto from ACME expires in 7 days",
contractId: "contract123",
actionType: "RENEWAL_URGENT",
});
};
return (
<>
<button onClick={handleUpload}>Upload</button>
<button onClick={handleDeadline}>Test Deadline</button>
</>
);
}
Notification Types
SUCCESS (Green - ✅)
Used for:
- Contract uploaded
- Analysis completed
- Contract deleted
- Settings saved
ERROR (Red - ❌)
Used for:
- Upload failed
- Analysis failed
- Network errors
- Invalid contract
WARNING (Yellow - ⚠️)
Used for:
- File analysis slow
- Low quality extraction
- Missing permissions
INFO (Blue - ℹ️)
Used for:
- Analysis started
- Processing updates
- General information
DEADLINE (Red - 🕐)
Used for:
- Contract expiring in 30 days (CRITICAL 🔴)
- Contract expiring in 15 days (WARNING 🟠)
- Contract expiring in 7 days (URGENT 🟡)
Scheduled Tasks
Daily Deadline Check
The system checks for upcoming deadlines:
- When: Daily at any time (triggered on dashboard load)
- What: Scans all user contracts with endDate
- Actions:
- Creates CRITICAL notification for 30-day threshold
- Creates WARNING notification for 15-day threshold
- Creates URGENT notification for 7-day threshold
- Avoids duplicate notifications (max 1 per threshold per day)
Running Deadline Checks Manually
import { checkDeadlineNotifications } from "@/lib/actions/notification.action";
// Client-side
const result = await checkDeadlineNotifications();
console.log(`Created ${result.data.count} deadline notifications`);
Cleanup Task (Recommended)
For production, set up a cron job to clean expired notifications:
import { NotificationService } from "@/lib/services/notification.service";
// Example: Vercel Cron (serverless function every day at midnight)
export async function GET(request: Request) {
const authHeader = request.headers.get("authorization");
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response("Unauthorized", { status: 401 });
}
const result = await NotificationService.cleanupExpired();
return Response.json(result);
}
// Route: api/cron/cleanup-notifications
// Set Cron Job: 0 0 * * * (daily at midnight)
Configurable Parameters
Default Notification Expiration
// In NotificationService.create()
const expiresAt = input.expiresIn
? new Date(Date.now() + input.expiresIn)
: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days default
Deadline Thresholds
Located in NotificationService.checkUpcomingDeadlines():
- 30 days: CRITICAL level
- 15 days: WARNING level
- 7 days: URGENT level
To modify, edit these lines in notification.service.ts:
if (daysUntilExpiration === 7) {
/* ... */
} else if (daysUntilExpiration === 15) {
/* ... */
} else if (daysUntilExpiration === 30) {
/* ... */
}
Notification Bar Polling
// In notification-bar.tsx
const pollInterval = setInterval(fetchNotifications, 30000); // 30 seconds
const dailyCheckInterval = setInterval(
() => {
checkDeadlineNotifications();
},
24 * 60 * 60 * 1000,
); // 24 hours
Security & Authorization
All notification operations include authorization checks:
- User Verification: Each action verifies the user owns the notification
- Contract Ownership: Deadline checks only process user's contracts
- Input Validation: Notification content isn't sanitized (all text)
- Server-Side Enforcement: All operations run server-side (no client-side manipulation)
Troubleshooting
Migrations Don't Apply
# Reset migrations (for development only)
npx prisma migrate reset
# Or manually apply pending migrations
npx prisma migrate deploy
Notifications Not Showing
- Check database connection
- Verify user exists in User table
- Check browser console for errors
- Verify
checkDeadlineNotificationswas called
Deadline Notifications Not Triggering
- Ensure contract has
endDateset - Verify contract status is "COMPLETED"
- Check date calculation (today at midnight)
- Run manual check:
await checkDeadlineNotifications()
Future Enhancements
Potential improvements:
- Email Notifications: Send deadline alerts via email
- Batch Operations: Bulk mark/delete notifications
- Notification Preferences: Let users disable certain types
- Snooze Feature: Temporarily hide notifications
- Advanced Filtering: Filter by type, date range, contract
- Export History: Download notification log as CSV
- Push Notifications: Web/mobile push for critical alerts
- Recurring Reminders: Repeat deadline notifications if ignored
Support
For issues or questions:
- Check the notification service comments for implementation details
- Review contracts-list.tsx for toast integration examples
- Check notification-bar.tsx for UI implementation
- See hooks/useNotifications.ts for hook usage