387 lines
10 KiB
Markdown
387 lines
10 KiB
Markdown
# 🔔 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:
|
||
|
||
```bash
|
||
npx prisma migrate dev --name add_notifications
|
||
```
|
||
|
||
This will:
|
||
|
||
1. Create the `Notification` table
|
||
2. Create the `NotificationType` enum
|
||
3. Add the `notifications` relationship to the `User` model
|
||
4. Add the `notifications` relationship to the `Contract` model
|
||
|
||
### Step 2: Database Schema Overview
|
||
|
||
The migration adds:
|
||
|
||
```sql
|
||
-- 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 notification
|
||
- `getUnread(userId, limit)` - Fetch unread notifications
|
||
- `getUnreadCount(userId)` - Get badge count
|
||
- `checkUpcomingDeadlines(userId)` - Scan contracts and create deadline notifications
|
||
- `cleanupExpired()` - Remove expired notifications (run periodically)
|
||
|
||
### 2. **Notification Actions** (`lib/actions/notification.action.ts`)
|
||
|
||
Server actions for client-side notification management:
|
||
|
||
- `getNotifications()` - Fetch unread notifications
|
||
- `getAllNotifications()` - Fetch notification history
|
||
- `getUnreadNotificationCount()` - Get badge count
|
||
- `markNotificationAsRead(id)` - Mark single as read
|
||
- `markAllNotificationsAsRead()` - Mark all as read
|
||
- `deleteNotification(id)` - Delete notification
|
||
- `checkDeadlineNotifications()` - 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 notification
|
||
- `notifyError()` - Red error toast + persistent notification
|
||
- `notifyWarning()` - Yellow warning toast + persistent notification
|
||
- `notifyInfo()` - Blue info toast + persistent notification
|
||
- `notifyDeadline()` - 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 `NotificationBar` component to sidebar
|
||
- Positioned next to theme toggle in account section
|
||
- Accessible from all dashboard pages
|
||
|
||
## Usage Examples
|
||
|
||
### Creating a Notification in Server Actions
|
||
|
||
```typescript
|
||
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
|
||
|
||
```typescript
|
||
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
|
||
|
||
```typescript
|
||
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:
|
||
|
||
```typescript
|
||
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
|
||
|
||
```typescript
|
||
// 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`:
|
||
|
||
```typescript
|
||
if (daysUntilExpiration === 7) {
|
||
/* ... */
|
||
} else if (daysUntilExpiration === 15) {
|
||
/* ... */
|
||
} else if (daysUntilExpiration === 30) {
|
||
/* ... */
|
||
}
|
||
```
|
||
|
||
### Notification Bar Polling
|
||
|
||
```typescript
|
||
// 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:
|
||
|
||
1. **User Verification**: Each action verifies the user owns the notification
|
||
2. **Contract Ownership**: Deadline checks only process user's contracts
|
||
3. **Input Validation**: Notification content isn't sanitized (all text)
|
||
4. **Server-Side Enforcement**: All operations run server-side (no client-side manipulation)
|
||
|
||
## Troubleshooting
|
||
|
||
### Migrations Don't Apply
|
||
|
||
```bash
|
||
# Reset migrations (for development only)
|
||
npx prisma migrate reset
|
||
|
||
# Or manually apply pending migrations
|
||
npx prisma migrate deploy
|
||
```
|
||
|
||
### Notifications Not Showing
|
||
|
||
1. Check database connection
|
||
2. Verify user exists in User table
|
||
3. Check browser console for errors
|
||
4. Verify `checkDeadlineNotifications` was called
|
||
|
||
### Deadline Notifications Not Triggering
|
||
|
||
1. Ensure contract has `endDate` set
|
||
2. Verify contract status is "COMPLETED"
|
||
3. Check date calculation (today at midnight)
|
||
4. Run manual check: `await checkDeadlineNotifications()`
|
||
|
||
## Future Enhancements
|
||
|
||
Potential improvements:
|
||
|
||
1. **Email Notifications**: Send deadline alerts via email
|
||
2. **Batch Operations**: Bulk mark/delete notifications
|
||
3. **Notification Preferences**: Let users disable certain types
|
||
4. **Snooze Feature**: Temporarily hide notifications
|
||
5. **Advanced Filtering**: Filter by type, date range, contract
|
||
6. **Export History**: Download notification log as CSV
|
||
7. **Push Notifications**: Web/mobile push for critical alerts
|
||
8. **Recurring Reminders**: Repeat deadline notifications if ignored
|
||
|
||
## Support
|
||
|
||
For issues or questions:
|
||
|
||
1. Check the notification service comments for implementation details
|
||
2. Review contracts-list.tsx for toast integration examples
|
||
3. Check notification-bar.tsx for UI implementation
|
||
4. See hooks/useNotifications.ts for hook usage
|