PreRelease v1
This commit is contained in:
386
NOTIFICATION_SYSTEM_SETUP.md
Normal file
386
NOTIFICATION_SYSTEM_SETUP.md
Normal file
@@ -0,0 +1,386 @@
|
||||
# 🔔 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
|
||||
Reference in New Issue
Block a user