Files
LexiChain/NOTIFICATION_SYSTEM_SETUP.md
2026-03-25 13:52:45 +01:00

10 KiB
Raw Permalink Blame History

🔔 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:

  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:

-- 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

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`);

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:

  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

# 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