549 lines
16 KiB
Markdown
549 lines
16 KiB
Markdown
# Notification and Widget Update System - Complete File & Route Analysis
|
|
|
|
## 📋 Table of Contents
|
|
1. [Notification System](#notification-system)
|
|
2. [Widget Update System](#widget-update-system)
|
|
3. [API Routes](#api-routes)
|
|
4. [Components](#components)
|
|
5. [Services & Libraries](#services--libraries)
|
|
6. [Hooks](#hooks)
|
|
7. [Types](#types)
|
|
|
|
---
|
|
|
|
## 🔔 Notification System
|
|
|
|
### API Routes
|
|
|
|
#### 1. **GET `/api/notifications`**
|
|
- **File**: `app/api/notifications/route.ts`
|
|
- **Purpose**: Fetch paginated notifications for authenticated user
|
|
- **Query Parameters**:
|
|
- `page` (default: 1)
|
|
- `limit` (default: 20, max: 100)
|
|
- **Response**:
|
|
```json
|
|
{
|
|
"notifications": Notification[],
|
|
"page": number,
|
|
"limit": number,
|
|
"total": number
|
|
}
|
|
```
|
|
- **Cache**: 30 seconds client-side cache
|
|
- **Authentication**: Required (session-based)
|
|
|
|
#### 2. **GET `/api/notifications/count`**
|
|
- **File**: `app/api/notifications/count/route.ts`
|
|
- **Purpose**: Get notification count (total and unread) for authenticated user
|
|
- **Response**:
|
|
```json
|
|
{
|
|
"total": number,
|
|
"unread": number,
|
|
"sources": {
|
|
[source]: {
|
|
"total": number,
|
|
"unread": number
|
|
}
|
|
}
|
|
}
|
|
```
|
|
- **Cache**: 10 seconds client-side cache
|
|
- **Authentication**: Required
|
|
|
|
#### 3. **POST `/api/notifications/[id]/read`**
|
|
- **File**: `app/api/notifications/[id]/read/route.ts`
|
|
- **Purpose**: Mark a specific notification as read
|
|
- **Parameters**:
|
|
- `id` (path parameter): Notification ID (format: `source-sourceId`)
|
|
- **Response**:
|
|
```json
|
|
{
|
|
"success": boolean
|
|
}
|
|
```
|
|
- **Authentication**: Required
|
|
|
|
#### 4. **POST `/api/notifications/read-all`**
|
|
- **File**: `app/api/notifications/read-all/route.ts`
|
|
- **Purpose**: Mark all notifications as read for authenticated user
|
|
- **Response**:
|
|
```json
|
|
{
|
|
"success": boolean
|
|
}
|
|
```
|
|
- **Authentication**: Required
|
|
|
|
#### 5. **GET `/api/debug/notifications`**
|
|
- **File**: `app/api/debug/notifications/route.ts`
|
|
- **Purpose**: Debug endpoint to test notification system
|
|
- **Response**: Detailed debug information including:
|
|
- Environment variables status
|
|
- User information
|
|
- Notification service test results
|
|
- Performance metrics
|
|
- **Authentication**: Required
|
|
|
|
### Services
|
|
|
|
#### 1. **NotificationService** (Singleton)
|
|
- **File**: `lib/services/notifications/notification-service.ts`
|
|
- **Purpose**: Core notification aggregation service
|
|
- **Features**:
|
|
- Multi-source notification aggregation (adapter pattern)
|
|
- Redis caching (30s for counts, 5min for lists)
|
|
- Background refresh scheduling
|
|
- Cache invalidation on read operations
|
|
- Lock mechanism to prevent concurrent refreshes
|
|
- **Methods**:
|
|
- `getInstance()`: Get singleton instance
|
|
- `getNotifications(userId, page, limit)`: Fetch notifications
|
|
- `getNotificationCount(userId)`: Get notification counts
|
|
- `markAsRead(userId, notificationId)`: Mark notification as read
|
|
- `markAllAsRead(userId)`: Mark all as read
|
|
- `invalidateCache(userId)`: Invalidate user caches
|
|
- `scheduleBackgroundRefresh(userId)`: Schedule background refresh
|
|
|
|
#### 2. **NotificationAdapter Interface**
|
|
- **File**: `lib/services/notifications/notification-adapter.interface.ts`
|
|
- **Purpose**: Interface for notification source adapters
|
|
- **Methods**:
|
|
- `getNotifications(userId, page?, limit?)`: Fetch notifications
|
|
- `getNotificationCount(userId)`: Get counts
|
|
- `markAsRead(userId, notificationId)`: Mark as read
|
|
- `markAllAsRead(userId)`: Mark all as read
|
|
- `isConfigured()`: Check if adapter is configured
|
|
|
|
#### 3. **LeantimeAdapter** (Implementation)
|
|
- **File**: `lib/services/notifications/leantime-adapter.ts`
|
|
- **Purpose**: Leantime notification source adapter
|
|
- **Features**:
|
|
- Fetches notifications from Leantime API via JSON-RPC
|
|
- Maps Leantime user IDs by email
|
|
- Transforms Leantime notifications to unified format
|
|
- Supports marking notifications as read
|
|
- **Configuration**:
|
|
- `LEANTIME_API_URL` environment variable
|
|
- `LEANTIME_TOKEN` environment variable
|
|
|
|
### Components
|
|
|
|
#### 1. **NotificationBadge**
|
|
- **File**: `components/notification-badge.tsx`
|
|
- **Purpose**: Notification bell icon with badge and dropdown
|
|
- **Features**:
|
|
- Displays unread count badge
|
|
- Dropdown menu with recent notifications
|
|
- Manual refresh button
|
|
- Mark as read functionality
|
|
- Mark all as read functionality
|
|
- Source badges (e.g., "Agilité" for Leantime)
|
|
- Links to source systems
|
|
- Error handling and retry
|
|
- **Used in**: `components/main-nav.tsx`
|
|
|
|
#### 2. **MainNav** (Notification Integration)
|
|
- **File**: `components/main-nav.tsx`
|
|
- **Purpose**: Main navigation bar with notification badge
|
|
- **Notification Features**:
|
|
- Includes `<NotificationBadge />` component
|
|
- Browser notification permission handling
|
|
- User status-based notification management
|
|
|
|
### Hooks
|
|
|
|
#### 1. **useNotifications**
|
|
- **File**: `hooks/use-notifications.ts`
|
|
- **Purpose**: React hook for notification management
|
|
- **Features**:
|
|
- Automatic polling (60 seconds interval)
|
|
- Rate limiting (5 seconds minimum between fetches)
|
|
- Debounced count fetching (300ms)
|
|
- Manual refresh support
|
|
- Mount/unmount lifecycle management
|
|
- Error handling
|
|
- **Returns**:
|
|
```typescript
|
|
{
|
|
notifications: Notification[],
|
|
notificationCount: NotificationCount,
|
|
loading: boolean,
|
|
error: string | null,
|
|
fetchNotifications: (page?, limit?) => Promise<void>,
|
|
fetchNotificationCount: () => Promise<void>,
|
|
markAsRead: (notificationId: string) => Promise<boolean>,
|
|
markAllAsRead: () => Promise<boolean>
|
|
}
|
|
```
|
|
|
|
### Types
|
|
|
|
#### 1. **Notification Types**
|
|
- **File**: `lib/types/notification.ts`
|
|
- **Interfaces**:
|
|
- `Notification`: Main notification interface
|
|
- `id`: string (format: `source-sourceId`)
|
|
- `source`: 'leantime' | 'nextcloud' | 'gitea' | 'dolibarr' | 'moodle'
|
|
- `sourceId`: string
|
|
- `type`: string
|
|
- `title`: string
|
|
- `message`: string
|
|
- `link?`: string
|
|
- `isRead`: boolean
|
|
- `timestamp`: Date
|
|
- `priority`: 'low' | 'normal' | 'high'
|
|
- `user`: { id: string, name?: string }
|
|
- `metadata?`: Record<string, any>
|
|
- `NotificationCount`: Count interface
|
|
- `total`: number
|
|
- `unread`: number
|
|
- `sources`: Record<string, { total: number, unread: number }>
|
|
|
|
---
|
|
|
|
## 🎨 Widget Update System
|
|
|
|
### Dashboard Widgets
|
|
|
|
The main dashboard (`app/page.tsx`) contains the following widgets:
|
|
|
|
1. **QuoteCard** - Daily quote widget
|
|
2. **Calendar** - Upcoming events widget
|
|
3. **News** - News articles widget
|
|
4. **Duties** - Tasks/Devoirs widget (Leantime)
|
|
5. **Email** - Email inbox widget
|
|
6. **Parole** - Chat messages widget (Rocket.Chat)
|
|
|
|
### Widget Components & Update Mechanisms
|
|
|
|
#### 1. **Calendar Widget**
|
|
- **Files**:
|
|
- `components/calendar.tsx` (Main dashboard widget)
|
|
- `components/calendar-widget.tsx` (Alternative implementation)
|
|
- `components/calendar/calendar-widget.tsx` (Calendar-specific widget)
|
|
- **Update Mechanism**:
|
|
- **Manual Refresh**: Refresh button in header
|
|
- **Auto Refresh**: Every 5 minutes (300000ms interval)
|
|
- **API Endpoint**: `/api/calendars?refresh=true`
|
|
- **Features**:
|
|
- Fetches calendars with events
|
|
- Filters upcoming events (today and future)
|
|
- Sorts by date (oldest first)
|
|
- Shows up to 7 events
|
|
- Displays calendar color coding
|
|
- **State Management**:
|
|
- `useState` for events, loading, error
|
|
- `useEffect` for initial fetch and interval setup
|
|
|
|
#### 2. **News Widget**
|
|
- **File**: `components/news.tsx`
|
|
- **Update Mechanism**:
|
|
- **Manual Refresh**: Refresh button in header
|
|
- **Initial Load**: On component mount when authenticated
|
|
- **API Endpoint**: `/api/news?limit=100` or `/api/news?refresh=true&limit=100`
|
|
- **Features**:
|
|
- Fetches up to 100 news articles
|
|
- Displays article count
|
|
- Click to open in new tab
|
|
- Scrollable list (max-height: 400px)
|
|
- **State Management**:
|
|
- `useState` for news, loading, error, refreshing
|
|
- `useEffect` for initial fetch on authentication
|
|
|
|
#### 3. **Duties Widget (Tasks)**
|
|
- **File**: `components/flow.tsx`
|
|
- **Update Mechanism**:
|
|
- **Manual Refresh**: Refresh button in header
|
|
- **Initial Load**: On component mount
|
|
- **API Endpoint**: `/api/leantime/tasks?refresh=true`
|
|
- **Features**:
|
|
- Fetches tasks from Leantime
|
|
- Filters out completed tasks (status 5)
|
|
- Sorts by due date (oldest first)
|
|
- Shows up to 7 tasks
|
|
- Displays task status badges
|
|
- Links to Leantime ticket view
|
|
- **State Management**:
|
|
- `useState` for tasks, loading, error, refreshing
|
|
- `useEffect` for initial fetch
|
|
|
|
#### 4. **Email Widget**
|
|
- **File**: `components/email.tsx`
|
|
- **Update Mechanism**:
|
|
- **Manual Refresh**: Refresh button in header
|
|
- **Initial Load**: On component mount
|
|
- **API Endpoint**: `/api/courrier?folder=INBOX&page=1&perPage=5` (+ `&refresh=true` for refresh)
|
|
- **Features**:
|
|
- Fetches 5 most recent emails from INBOX
|
|
- Sorts by date (most recent first)
|
|
- Shows read/unread status
|
|
- Displays sender, subject, date
|
|
- Link to full email view (`/courrier`)
|
|
- **State Management**:
|
|
- `useState` for emails, loading, error, mailUrl
|
|
- `useEffect` for initial fetch
|
|
|
|
#### 5. **Parole Widget (Chat Messages)**
|
|
- **File**: `components/parole.tsx`
|
|
- **Update Mechanism**:
|
|
- **Manual Refresh**: Refresh button in header
|
|
- **Auto Polling**: Every 30 seconds (30000ms interval)
|
|
- **Initial Load**: On authentication
|
|
- **API Endpoint**: `/api/rocket-chat/messages` (+ `?refresh=true` for refresh)
|
|
- **Features**:
|
|
- Fetches recent chat messages from Rocket.Chat
|
|
- Displays sender avatar, name, message
|
|
- Shows room/channel information
|
|
- Click to navigate to full chat (`/parole`)
|
|
- Authentication check with sign-in prompt
|
|
- **State Management**:
|
|
- `useState` for messages, loading, error, refreshing
|
|
- `useEffect` for initial fetch and polling setup
|
|
- Session status checking
|
|
|
|
#### 6. **QuoteCard Widget**
|
|
- **File**: `components/quote-card.tsx`
|
|
- **Update Mechanism**: (To be verified - likely static or daily update)
|
|
|
|
### Widget Update Patterns
|
|
|
|
#### Common Update Mechanisms:
|
|
|
|
1. **Manual Refresh**:
|
|
- All widgets have a refresh button in their header
|
|
- Triggers API call with `refresh=true` parameter
|
|
- Shows loading/spinning state during refresh
|
|
|
|
2. **Auto Refresh/Polling**:
|
|
- **Calendar**: 5 minutes interval
|
|
- **Parole**: 30 seconds interval
|
|
- Others: On component mount only
|
|
|
|
3. **Session-Based Loading**:
|
|
- Widgets check authentication status
|
|
- Only fetch data when `status === 'authenticated'`
|
|
- Show loading state during authentication check
|
|
|
|
4. **Error Handling**:
|
|
- All widgets display error messages
|
|
- Retry buttons available
|
|
- Graceful degradation (empty states)
|
|
|
|
5. **State Management**:
|
|
- All widgets use React `useState` hooks
|
|
- Loading states managed locally
|
|
- Error states managed locally
|
|
|
|
### Related API Routes for Widgets
|
|
|
|
#### Calendar
|
|
- **GET `/api/calendars`**: Fetch calendars with events
|
|
- **GET `/api/calendars/[id]/events`**: Fetch events for specific calendar
|
|
- **GET `/api/calendars/[id]`**: Get calendar details
|
|
|
|
#### News
|
|
- **GET `/api/news`**: Fetch news articles
|
|
- Query params: `limit`, `refresh`
|
|
|
|
#### Tasks (Leantime)
|
|
- **GET `/api/leantime/tasks`**: Fetch tasks
|
|
- Query params: `refresh`
|
|
|
|
#### Email (Courrier)
|
|
- **GET `/api/courrier`**: Fetch emails
|
|
- Query params: `folder`, `page`, `perPage`, `refresh`
|
|
- **POST `/api/courrier/refresh`**: Force refresh email cache
|
|
|
|
#### Chat (Rocket.Chat)
|
|
- **GET `/api/rocket-chat/messages`**: Fetch messages
|
|
- Query params: `refresh`
|
|
|
|
---
|
|
|
|
## 📁 Complete File Structure
|
|
|
|
### Notification Files
|
|
|
|
```
|
|
app/api/notifications/
|
|
├── route.ts # GET /api/notifications
|
|
├── count/
|
|
│ └── route.ts # GET /api/notifications/count
|
|
├── read-all/
|
|
│ └── route.ts # POST /api/notifications/read-all
|
|
└── [id]/
|
|
└── read/
|
|
└── route.ts # POST /api/notifications/[id]/read
|
|
|
|
app/api/debug/
|
|
└── notifications/
|
|
└── route.ts # GET /api/debug/notifications
|
|
|
|
lib/services/notifications/
|
|
├── notification-service.ts # Core notification service
|
|
├── notification-adapter.interface.ts # Adapter interface
|
|
└── leantime-adapter.ts # Leantime adapter implementation
|
|
|
|
lib/types/
|
|
└── notification.ts # Notification type definitions
|
|
|
|
hooks/
|
|
└── use-notifications.ts # React hook for notifications
|
|
|
|
components/
|
|
├── notification-badge.tsx # Notification UI component
|
|
└── main-nav.tsx # Navigation with notification badge
|
|
```
|
|
|
|
### Widget Files
|
|
|
|
```
|
|
app/
|
|
└── page.tsx # Main dashboard with widgets
|
|
|
|
components/
|
|
├── calendar.tsx # Calendar widget
|
|
├── calendar-widget.tsx # Alternative calendar widget
|
|
├── calendar/
|
|
│ └── calendar-widget.tsx # Calendar-specific widget
|
|
├── news.tsx # News widget
|
|
├── flow.tsx # Duties/Tasks widget
|
|
├── email.tsx # Email widget
|
|
├── parole.tsx # Chat messages widget
|
|
└── quote-card.tsx # Quote widget
|
|
|
|
app/api/
|
|
├── calendars/
|
|
│ ├── route.ts # GET /api/calendars
|
|
│ └── [id]/
|
|
│ └── events/
|
|
│ └── route.ts # GET /api/calendars/[id]/events
|
|
├── news/
|
|
│ └── route.ts # GET /api/news
|
|
├── leantime/
|
|
│ └── tasks/
|
|
│ └── route.ts # GET /api/leantime/tasks
|
|
├── courrier/
|
|
│ ├── route.ts # GET /api/courrier
|
|
│ └── refresh/
|
|
│ └── route.ts # POST /api/courrier/refresh
|
|
└── rocket-chat/
|
|
└── messages/
|
|
└── route.ts # GET /api/rocket-chat/messages
|
|
```
|
|
|
|
---
|
|
|
|
## 🔄 Update Flow Diagrams
|
|
|
|
### Notification Update Flow
|
|
|
|
```
|
|
User Action / Polling
|
|
↓
|
|
useNotifications Hook
|
|
↓
|
|
API Route (/api/notifications or /api/notifications/count)
|
|
↓
|
|
NotificationService.getInstance()
|
|
↓
|
|
Check Redis Cache
|
|
├─ Cache Hit → Return cached data
|
|
└─ Cache Miss → Fetch from Adapters
|
|
↓
|
|
LeantimeAdapter (and other adapters)
|
|
↓
|
|
Transform & Aggregate
|
|
↓
|
|
Store in Redis Cache
|
|
↓
|
|
Return to API
|
|
↓
|
|
Return to Hook
|
|
↓
|
|
Update Component State
|
|
```
|
|
|
|
### Widget Update Flow
|
|
|
|
```
|
|
Component Mount / User Click Refresh
|
|
↓
|
|
useEffect / onClick Handler
|
|
↓
|
|
fetch() API Call
|
|
├─ With refresh=true (manual)
|
|
└─ Without refresh (initial)
|
|
↓
|
|
API Route Handler
|
|
├─ Check Cache (if applicable)
|
|
├─ Fetch from External Service
|
|
└─ Return Data
|
|
↓
|
|
Update Component State
|
|
├─ setLoading(false)
|
|
├─ setData(response)
|
|
└─ setError(null)
|
|
↓
|
|
Re-render Component
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Key Features Summary
|
|
|
|
### Notification System
|
|
- ✅ Multi-source aggregation (adapter pattern)
|
|
- ✅ Redis caching with TTL
|
|
- ✅ Background refresh scheduling
|
|
- ✅ Polling mechanism (60s interval)
|
|
- ✅ Rate limiting (5s minimum)
|
|
- ✅ Mark as read / Mark all as read
|
|
- ✅ Cache invalidation on updates
|
|
- ✅ Error handling and retry
|
|
- ✅ Source badges and links
|
|
|
|
### Widget System
|
|
- ✅ Manual refresh buttons
|
|
- ✅ Auto-refresh/polling (widget-specific intervals)
|
|
- ✅ Session-based loading
|
|
- ✅ Error handling
|
|
- ✅ Loading states
|
|
- ✅ Empty states
|
|
- ✅ Responsive design
|
|
|
|
---
|
|
|
|
## 📝 Notes
|
|
|
|
1. **Notification Sources**: Currently only Leantime adapter is implemented. Other adapters (Nextcloud, Gitea, Dolibarr, Moodle) are commented out in the service.
|
|
|
|
2. **Cache Strategy**:
|
|
- Notification counts: 30 seconds TTL
|
|
- Notification lists: 5 minutes TTL
|
|
- Widget data: Varies by widget (some use API-level caching)
|
|
|
|
3. **Polling Intervals**:
|
|
- Notifications: 60 seconds
|
|
- Calendar widget: 5 minutes
|
|
- Parole widget: 30 seconds
|
|
- Other widgets: On mount only
|
|
|
|
4. **Authentication**: All notification and widget APIs require authentication via NextAuth session.
|
|
|
|
5. **Error Handling**: All components implement error states with retry mechanisms.
|
|
|
|
---
|
|
|
|
## 🔍 Debugging
|
|
|
|
- Use `/api/debug/notifications` to test notification system
|
|
- Check browser console for detailed logs (all components log extensively)
|
|
- Check Redis cache keys: `notifications:count:{userId}`, `notifications:list:{userId}:{page}:{limit}`
|
|
|
|
---
|
|
|
|
*Last Updated: Generated from codebase analysis*
|