diff --git a/LOG_FLOW_ANALYSIS.md b/LOG_FLOW_ANALYSIS.md new file mode 100644 index 00000000..18f93d46 --- /dev/null +++ b/LOG_FLOW_ANALYSIS.md @@ -0,0 +1,342 @@ +# Log Flow Analysis - Application Startup & Runtime + +**Date**: 2026-01-01 +**Log Source**: Application startup and initial page load +**Analysis Focus**: Flow patterns, errors, and system behavior + +--- + +## 🔍 Executive Summary + +**Overall Status**: 🟡 **MOSTLY HEALTHY** with one non-critical error + +**Key Findings**: +1. ⚠️ **Syntax Error**: Non-critical error during startup (doesn't block execution) +2. ✅ **Session Management**: Working correctly (5 session callbacks during startup) +3. ✅ **Notification Service**: Initialized and functioning (100 total, 66 unread) +4. ✅ **External Services**: All connecting successfully +5. ⚠️ **No Mark-as-Read Activity**: No API calls to mark notifications as read + +--- + +## 📊 Flow Breakdown + +### Phase 1: Application Startup (Lines 1-33) + +``` +1. Next.js starts (1313ms) +2. Redis connection established ✅ +3. Microsoft OAuth configuration loaded ✅ +4. ⚠️ SyntaxError: Unexpected identifier 'http' (line 29) +5. Redis connection warmed up ✅ +``` + +**Observations**: +- ✅ Startup is fast (1.3 seconds) +- ✅ Redis connection successful +- ⚠️ **Syntax Error** appears but doesn't block execution +- Error occurs between Redis warmup calls + +**Syntax Error Details**: +``` +⨯ SyntaxError: Unexpected identifier 'http' + at Object.Function [as get] () { + digest: '2421336728' + } +``` + +**Analysis**: +- Error is in a route handler (Function.get) +- Likely related to a route file with syntax issue +- Doesn't crash the application +- May be related to dynamic route generation + +**Recommendation**: Investigate route files for syntax errors, especially those using `http` in identifiers. + +--- + +### Phase 2: Initial Session Creation (Lines 34-71) + +``` +1. Session callback triggered +2. Token validation ✅ +3. User roles extracted ✅ +4. Session created successfully ✅ +``` + +**Session Details**: +- User ID: `203cbc91-61ab-47a2-95d2-b5e1159327d7` +- Email: `a.tmiri@clm.foundation` +- Roles: `['expression', 'entrepreneurship', 'admin', 'dataintelligence', 'mediation', 'mentors']` +- Tokens: Access token ✅, Refresh token ✅ + +**Status**: ✅ **HEALTHY** + +--- + +### Phase 3: Rocket.Chat Integration (Lines 72-91) + +``` +1. Rocket.Chat base URL: https://parole.slm-lab.net ✅ +2. Users list fetched (13 users) ✅ +3. User found: aminetmiri ✅ +4. Subscriptions filtered (1 room) ✅ +5. Messages fetched (5 messages) ✅ +6. Messages cached ✅ +7. ⚠️ "No valid session or email found" (line 92) +``` + +**Observations**: +- ✅ Rocket.Chat integration working +- ✅ User authentication successful +- ✅ Messages retrieved and cached +- ⚠️ Warning message at line 92 (may be from another service) + +**Status**: ✅ **HEALTHY** (warning is likely from a different service) + +--- + +### Phase 4: Additional Session Callbacks (Lines 93-169) + +``` +1. Session callback #2 (lines 93-130) +2. Session callback #3 (lines 132-169) +``` + +**Pattern**: Multiple session callbacks during initial page load + +**Frequency**: 3 session callbacks in ~40 lines of log + +**Analysis**: +- Normal behavior for Next.js with multiple API routes +- Each `getServerSession()` call triggers session callback +- All callbacks successful ✅ + +**Status**: ✅ **NORMAL** (but verbose logging as discussed) + +--- + +### Phase 5: Notification Service Initialization (Lines 170-246) + +``` +1. Notification service instance created ✅ +2. Leantime adapter initialized ✅ +3. Adapter registered ✅ +4. getNotificationCount called ✅ +5. Leantime API called ✅ +6. Response received (200) ✅ +7. Notifications parsed ✅ +8. Count calculated: 100 total, 66 unread ✅ +9. Counts cached ✅ +``` + +**Notification Details**: +- **Total**: 100 notifications +- **Unread**: 66 notifications +- **Source**: Leantime +- **Status**: ✅ **WORKING CORRECTLY** + +**Flow**: +``` +[NOTIFICATION_SERVICE] → [LEANTIME_ADAPTER] → Leantime API → Parse → Cache +``` + +**Status**: ✅ **HEALTHY** + +--- + +### Phase 6: Additional Operations (Lines 247-289) + +``` +1. IMAP pool status logged +2. Session callback #4 (lines 248-285) +3. Cached messages used +4. IMAP pool status logged again +``` + +**Observations**: +- ✅ IMAP connection pool healthy (0 active, max 20) +- ✅ Session callbacks continuing (normal) +- ✅ Caching working (messages from cache) + +**Status**: ✅ **HEALTHY** + +--- + +## 🔴 Issues Identified + +### 1. Syntax Error (Line 29) ⚠️ + +**Error**: +``` +⨯ SyntaxError: Unexpected identifier 'http' + at Object.Function [as get] () +``` + +**Impact**: +- ⚠️ **Low**: Doesn't crash application +- ⚠️ **Unknown**: May affect specific route +- ⚠️ **Non-blocking**: Application continues normally + +**Possible Causes**: +1. Route file with syntax error +2. Dynamic route generation issue +3. Template literal or string interpolation problem +4. Environment variable parsing issue + +**Investigation Steps**: +1. Search codebase for routes using `http` as identifier +2. Check dynamic route files +3. Review route handlers for syntax errors +4. Check Next.js route generation + +**Priority**: 🟡 **MEDIUM** - Should be fixed but not blocking + +--- + +### 2. "No valid session or email found" (Line 92) ⚠️ + +**Message**: `No valid session or email found` + +**Context**: Appears after Rocket.Chat operations + +**Analysis**: +- May be from a different service/route +- Doesn't affect Rocket.Chat functionality +- Could be from email service or another API route + +**Investigation**: Check which service logs this message + +**Priority**: 🟡 **LOW** - Appears to be a warning, not an error + +--- + +### 3. No Mark-as-Read Activity ⚠️ + +**Observation**: No `[NOTIFICATION_API]` log entries + +**Expected**: Should see logs when user marks notifications as read + +**Possible Reasons**: +1. User hasn't tested mark-as-read yet +2. API calls not reaching server +3. Client-side errors preventing API calls + +**Status**: ⏳ **PENDING TESTING** + +**Action**: Test mark-as-read functionality and check for new log entries + +--- + +## ✅ Positive Observations + +### 1. Fast Startup +- ✅ Application ready in 1.3 seconds +- ✅ All services initialized quickly + +### 2. Session Management +- ✅ All session callbacks successful +- ✅ Token validation working +- ✅ User roles extracted correctly + +### 3. Notification Service +- ✅ Service initialized correctly +- ✅ Leantime adapter working +- ✅ API calls successful +- ✅ Caching functioning + +### 4. External Services +- ✅ Redis connected +- ✅ Rocket.Chat connected +- ✅ Leantime API responding +- ✅ IMAP pool healthy + +--- + +## 📈 Performance Metrics + +| Metric | Value | Status | +|--------|-------|--------| +| Startup Time | 1313ms | ✅ Good | +| Redis Connection | ✅ Success | ✅ Good | +| Session Callbacks | 5 during startup | ✅ Normal | +| Notification Count | 100 total, 66 unread | ✅ Working | +| Rocket.Chat | ✅ Connected | ✅ Good | +| IMAP Pool | 0/20 active | ✅ Healthy | + +--- + +## 🔄 Flow Patterns + +### Session Callback Pattern +``` +Every getServerSession() call → Session callback → Token validation → Session created +``` + +**Frequency**: 5 times during startup (normal for multi-route page) + +**Recommendation**: Conditional logging (as discussed in impact analysis) + +--- + +### Notification Service Pattern +``` +Service init → Adapter registration → API call → Parse → Cache +``` + +**Status**: ✅ Working correctly + +--- + +## 🎯 Recommendations + +### Immediate Actions + +1. **Investigate Syntax Error** 🔴 + - Search for route files with `http` identifier + - Check dynamic routes + - Fix syntax error + +2. **Test Mark-as-Read** 🟡 + - Mark a notification as read + - Check logs for `[NOTIFICATION_API]` entries + - Verify notification count updates + +3. **Identify "No valid session" Source** 🟡 + - Find which service logs this message + - Determine if it's an error or warning + - Fix if necessary + +### Future Improvements + +4. **Implement Conditional Session Logging** (as planned) + - Add `DEBUG_SESSION` flag + - Reduce production logging + - Keep error logging + +5. **Add Error Monitoring** + - Track syntax errors + - Monitor route handler failures + - Alert on critical errors + +--- + +## 📝 Summary + +**Overall Assessment**: 🟢 **HEALTHY** with minor issues + +**Critical Issues**: 0 +**Warnings**: 2 (syntax error, "no valid session" message) +**Working Correctly**: ✅ All core functionality + +**Next Steps**: +1. Fix syntax error (investigate route files) +2. Test mark-as-read functionality +3. Identify source of "no valid session" message +4. Proceed with conditional session logging (when ready) + +--- + +**Generated**: 2026-01-01 +**Status**: Ready for action items + diff --git a/NOTIFICATION_ISSUES_FIX.md b/NOTIFICATION_ISSUES_FIX.md new file mode 100644 index 00000000..6713ed09 --- /dev/null +++ b/NOTIFICATION_ISSUES_FIX.md @@ -0,0 +1,194 @@ +# Notification Issues - Analysis & Fixes + +**Date**: 2026-01-01 +**Issues Reported**: +1. Count shows 66 messages, but only 10 are displayed +2. "Mark all as read" fails +3. Count doesn't update after marking as read + +--- + +## 🔍 Issue Analysis + +### Issue 1: Count vs Display Discrepancy + +**Symptom**: +- Badge shows: **66 unread notifications** +- Dropdown shows: **Only 10 notifications** + +**Root Cause**: +1. **Count Logic**: `getNotificationCount()` calls `getNotifications(userId, 1, 100)` to count + - Gets first 100 notifications from Leantime + - Counts unread: 66 + - This is correct for the first 100 notifications + +2. **Display Logic**: `getNotifications()` is called with `limit: 20` (default) + - But only 10 are shown (possibly due to pagination or filtering) + - This is a display/pagination issue + +**The Problem**: +- If Leantime has more than 100 notifications total, the count will be inaccurate +- The count only reflects the first 100 notifications +- Display shows fewer notifications than the count + +**Solution**: +- ✅ Added warning log when count reaches 100 (may have more) +- ⚠️ Consider using a dedicated count API if Leantime provides one +- ⚠️ Consider fetching all notifications for accurate count (may be slow) + +--- + +### Issue 2: Mark All As Read Fails + +**Symptom**: +``` +[NOTIFICATION_API] Mark all as read - Failed { userId: '...', duration: '197ms' } +``` + +**Root Cause**: +- Leantime API call is failing +- No detailed error logging to see why + +**Solution Applied**: +- ✅ Added comprehensive error logging to `markAllAsRead()`: + - Logs user email and Leantime user ID + - Logs request body and API URL + - Logs response status and body + - Logs parsed response with error details + - Logs exceptions with stack traces + +**Next Steps**: +1. Test mark-all-as-read again +2. Check logs for detailed error information +3. Verify Leantime API method name is correct +4. Check if Leantime API requires different parameters + +--- + +## 🔧 Fixes Applied + +### 1. Enhanced Error Logging in `markAllAsRead` + +**File**: `lib/services/notifications/leantime-adapter.ts` + +**Changes**: +- Added detailed logging at each step +- Logs request details (body, URL) +- Logs response details (status, body, parsed data) +- Logs errors with full context +- Logs success/failure status + +**Expected Log Output**: +``` +[LEANTIME_ADAPTER] markAllAsRead called for ... +[LEANTIME_ADAPTER] markAllAsRead - User email: ... +[LEANTIME_ADAPTER] markAllAsRead - Leantime user ID: ... +[LEANTIME_ADAPTER] markAllAsRead - Request body: {...} +[LEANTIME_ADAPTER] markAllAsRead - API URL: ... +[LEANTIME_ADAPTER] markAllAsRead - Response status: 200 +[LEANTIME_ADAPTER] markAllAsRead - Response body: {...} +[LEANTIME_ADAPTER] markAllAsRead - Parsed response: {...} +[LEANTIME_ADAPTER] markAllAsRead - Success: true/false +``` + +--- + +### 2. Enhanced Count Logging + +**File**: `lib/services/notifications/leantime-adapter.ts` + +**Changes**: +- Added warning when count reaches 100 (may have more notifications) +- Added read count to logging +- Added note about potential inaccuracy + +--- + +## 🎯 Next Steps + +### Immediate Testing + +1. **Test Mark All As Read** + - Click "Mark all as read" + - Check logs for detailed error information + - Look for `[LEANTIME_ADAPTER] markAllAsRead` entries + +2. **Verify Count Accuracy** + - Check if Leantime has more than 100 notifications + - Verify count matches actual unread notifications + - Check if count updates after marking as read + +### Potential Issues to Check + +1. **Leantime API Method Name** + - Current: `leantime.rpc.Notifications.Notifications.markAllNotificationsAsRead` + - Verify this is the correct method name in Leantime API + +2. **Leantime API Parameters** + - Current: `{ userId: leantimeUserId }` + - May need additional parameters + +3. **Leantime API Response Format** + - Check if response format matches expected format + - May need to handle different response structures + +--- + +## 📊 Expected Behavior After Fixes + +### Mark All As Read + +**Success Case**: +``` +[NOTIFICATION_API] Mark all as read endpoint called +[NOTIFICATION_API] Mark all as read - Processing { userId: '...', timestamp: '...' } +[LEANTIME_ADAPTER] markAllAsRead called for ... +[LEANTIME_ADAPTER] markAllAsRead - Success: true +[NOTIFICATION_API] Mark all as read - Success { userId: '...', duration: 'Xms' } +[NOTIFICATION_SERVICE] Invalidated notification caches for user ... +``` + +**Failure Case** (with detailed error): +``` +[NOTIFICATION_API] Mark all as read endpoint called +[LEANTIME_ADAPTER] markAllAsRead called for ... +[LEANTIME_ADAPTER] markAllAsRead - Response status: 400 +[LEANTIME_ADAPTER] markAllAsRead - Response body: {"error": {...}} +[LEANTIME_ADAPTER] markAllAsRead - API Error: {...} +[NOTIFICATION_API] Mark all as read - Failed { userId: '...', duration: 'Xms' } +``` + +--- + +## 🔍 Debugging Checklist + +When testing, check logs for: + +- [ ] `[LEANTIME_ADAPTER] markAllAsRead - User email:` (should show email) +- [ ] `[LEANTIME_ADAPTER] markAllAsRead - Leantime user ID:` (should show ID) +- [ ] `[LEANTIME_ADAPTER] markAllAsRead - Request body:` (should show JSON-RPC request) +- [ ] `[LEANTIME_ADAPTER] markAllAsRead - Response status:` (should be 200 for success) +- [ ] `[LEANTIME_ADAPTER] markAllAsRead - Response body:` (should show API response) +- [ ] `[LEANTIME_ADAPTER] markAllAsRead - Parsed response:` (should show result/error) +- [ ] `[LEANTIME_ADAPTER] markAllAsRead - Success:` (should be true/false) + +--- + +## 📝 Summary + +**Fixes Applied**: +1. ✅ Enhanced error logging in `markAllAsRead` +2. ✅ Enhanced count logging with warnings + +**Next Actions**: +1. Test mark-all-as-read functionality +2. Review detailed error logs +3. Fix Leantime API call based on error details +4. Verify count accuracy + +**Status**: ⏳ **AWAITING TESTING** - Enhanced logging will reveal the root cause + +--- + +**Generated**: 2026-01-01 + diff --git a/Untitled b/Untitled new file mode 100644 index 00000000..ab298c63 --- /dev/null +++ b/Untitled @@ -0,0 +1,288 @@ +alma@central:~/nextgen/NeahNew$ sudo npm start + +> neah@0.1.0 start +> next start + + ▲ Next.js 15.3.1 + - Local: http://localhost:3000 + - Network: http://172.16.0.102:3000 + + ✓ Starting... + ✓ Ready in 1313ms +Connecting to Redis using environment variables +Microsoft OAuth Configuration: { + tenantId: 'cb4281a9-4a3e-4ff5-9a85-8425dd04e2b2', + authorizeUrl: 'https://login.microsoftonline.com/cb4281a9-4a3e-4ff5-9a85-8425dd04e2b2/oauth2/v2.0/authorize', + tokenUrl: 'https://login.microsoftonline.com/cb4281a9-4a3e-4ff5-9a85-8425dd04e2b2/oauth2/v2.0/token', + clientIdFirstChars: 'afaff...', + redirectUri: 'https://hub.slm-lab.net/ms' +} +Microsoft OAuth Configuration: { + tenantId: 'cb4281a9-4a3e-4ff5-9a85-8425dd04e2b2', + authorizeUrl: 'https://login.microsoftonline.com/cb4281a9-4a3e-4ff5-9a85-8425dd04e2b2/oauth2/v2.0/authorize', + tokenUrl: 'https://login.microsoftonline.com/cb4281a9-4a3e-4ff5-9a85-8425dd04e2b2/oauth2/v2.0/token', + clientIdFirstChars: 'afaff...', + redirectUri: 'https://hub.slm-lab.net/ms' +} +Successfully connected to Redis +Redis connection warmed up + ⨯ SyntaxError: Unexpected identifier 'http' + at Object.Function [as get] () { + digest: '2421336728' +} +Redis connection warmed up +=== SESSION CALLBACK START === +Token error: undefined +Has accessToken: true +Has refreshToken: true +Token role: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Token sub: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Token email: a.tmiri@clm.foundation +Token name: Amine TMIRI +Token username: aminetmiri +User roles for session: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Creating session user object... +Setting session tokens... +✅ Session created successfully +Session user id: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Session user email: a.tmiri@clm.foundation +Session user roles: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +=== SESSION CALLBACK END === +Using Rocket.Chat base URL: https://parole.slm-lab.net +Users list response: { success: true, count: 13, usersCount: 13 } +Found Rocket.Chat user: { username: 'aminetmiri', id: 'a9HwLtHagiRnTWeS5' } +Filtered user subscriptions: { + userId: 'a9HwLtHagiRnTWeS5', + username: 'aminetmiri', + totalSubscriptions: 1, + subscriptionDetails: [ + { + type: 'd', + name: 'Rocket.Cat', + rid: 'a9HwLtHagiRnTWeS5rocket.cat', + alert: true, + unread: 3, + userMentions: 0 + } + ] +} +Messages for room Rocket.Cat: { success: true, count: 5, hasMessages: true } +Messages data cached for user 203cbc91-61ab-47a2-95d2-b5e1159327d7 +No valid session or email found +=== SESSION CALLBACK START === +Token error: undefined +Has accessToken: true +Has refreshToken: true +Token role: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Token sub: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Token email: a.tmiri@clm.foundation +Token name: Amine TMIRI +Token username: aminetmiri +User roles for session: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Creating session user object... +Setting session tokens... +✅ Session created successfully +Session user id: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Session user email: a.tmiri@clm.foundation +Session user roles: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +=== SESSION CALLBACK END === +Using cached messages data for user 203cbc91-61ab-47a2-95d2-b5e1159327d7 +=== SESSION CALLBACK START === +Token error: undefined +Has accessToken: true +Has refreshToken: true +Token role: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Token sub: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Token email: a.tmiri@clm.foundation +Token name: Amine TMIRI +Token username: aminetmiri +User roles for session: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Creating session user object... +Setting session tokens... +✅ Session created successfully +Session user id: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Session user email: a.tmiri@clm.foundation +Session user roles: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +=== SESSION CALLBACK END === +[NOTIFICATION_SERVICE] Creating new notification service instance +[NOTIFICATION_SERVICE] Initializing notification service +[LEANTIME_ADAPTER] Initialized with API URL and token +[NOTIFICATION_SERVICE] Registered notification adapter: leantime +[NOTIFICATION_SERVICE] Registered adapters: [ 'leantime' ] +[NOTIFICATION_SERVICE] getNotificationCount called for user 203cbc91-61ab-47a2-95d2-b5e1159327d7 +[NOTIFICATION_SERVICE] Fetching notification counts for user 203cbc91-61ab-47a2-95d2-b5e1159327d7 from 1 adapters +[NOTIFICATION_SERVICE] Available adapters for count: leantime +[NOTIFICATION_SERVICE] Checking if adapter leantime is configured for count +[NOTIFICATION_SERVICE] Adapter leantime is configured for count: true +[NOTIFICATION_SERVICE] Fetching notification count from leantime for user 203cbc91-61ab-47a2-95d2-b5e1159327d7 +[LEANTIME_ADAPTER] getNotificationCount called for userId: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +[LEANTIME_ADAPTER] getNotifications called for userId: 203cbc91-61ab-47a2-95d2-b5e1159327d7, page: 1, limit: 100 +=== SESSION CALLBACK START === +Token error: undefined +Has accessToken: true +Has refreshToken: true +Token role: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Token sub: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Token email: a.tmiri@clm.foundation +Token name: Amine TMIRI +Token username: aminetmiri +User roles for session: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Creating session user object... +Setting session tokens... +✅ Session created successfully +Session user id: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Session user email: a.tmiri@clm.foundation +Session user roles: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +=== SESSION CALLBACK END === +[LEANTIME_ADAPTER] Retrieved email from session: a.tmiri@clm.foundation +[LEANTIME_ADAPTER] Retrieved Leantime userId for email a.tmiri@clm.foundation: 2 +[LEANTIME_ADAPTER] Sending request to get all notifications +[LEANTIME_ADAPTER] Request body: {"jsonrpc":"2.0","method":"leantime.rpc.Notifications.Notifications.getAllNotifications","params":{"userId":2,"showNewOnly":0,"limitStart":0,"limitEnd":100,"filterOptions":[]},"id":1} +[LEANTIME_ADAPTER] Response status: 200 +[LEANTIME_ADAPTER] Raw response (truncated): {"jsonrpc":"2.0","result":[{"id":2732,"0":2732,"userId":2,"1":2,"read":0,"2":0,"type":"projectUpdate","3":"projectUpdate","module":"tickets","4":"tickets","moduleId":225,"5":225,"datetime":"2025-12-24... +[LEANTIME_ADAPTER] Parsed response data: { + hasResult: true, + resultIsArray: true, + resultLength: 100, + error: undefined +} +[LEANTIME_ADAPTER] Transformed notifications count: 100 +[LEANTIME_ADAPTER] Notification counts: { total: 100, unread: 66 } +[NOTIFICATION_SERVICE] Got count from leantime: { + total: 100, + unread: 66, + sources: { leantime: { total: 100, unread: 66 } } +} +[NOTIFICATION_SERVICE] Adding counts from leantime: total=100, unread=66 +[NOTIFICATION_SERVICE] Aggregated counts for user 203cbc91-61ab-47a2-95d2-b5e1159327d7: { + total: 100, + unread: 66, + sources: { leantime: { total: 100, unread: 66 } } +} +[NOTIFICATION_SERVICE] Cached notification counts for user 203cbc91-61ab-47a2-95d2-b5e1159327d7 +[IMAP POOL] Size: 0, Active: 0, Connecting: 0, Max: 20 +=== SESSION CALLBACK START === +Token error: undefined +Has accessToken: true +Has refreshToken: true +Token role: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Token sub: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Token email: a.tmiri@clm.foundation +Token name: Amine TMIRI +Token username: aminetmiri +User roles for session: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +Creating session user object... +Setting session tokens... +✅ Session created successfully +Session user id: 203cbc91-61ab-47a2-95d2-b5e1159327d7 +Session user email: a.tmiri@clm.foundation +Session user roles: [ + 'expression', + 'entrepreneurship', + 'admin', + 'dataintelligence', + 'mediation', + 'mentors' +] +=== SESSION CALLBACK END === +Using cached messages data for user 203cbc91-61ab-47a2-95d2-b5e1159327d7 +[IMAP POOL] Size: 0, Active: 0, Connecting: 0, Max: 20 + diff --git a/lib/services/notifications/leantime-adapter.ts b/lib/services/notifications/leantime-adapter.ts index 3255eaca..1ede842e 100644 --- a/lib/services/notifications/leantime-adapter.ts +++ b/lib/services/notifications/leantime-adapter.ts @@ -123,6 +123,8 @@ export class LeantimeAdapter implements NotificationAdapter { try { // Get all notifications and count them + // NOTE: This only gets first 100 notifications. If there are more, the count will be inaccurate. + // TODO: Consider using a dedicated count API endpoint if Leantime provides one const notifications = await this.getNotifications(userId, 1, 100); // Get up to 100 for counting // Count total and unread @@ -131,7 +133,9 @@ export class LeantimeAdapter implements NotificationAdapter { console.log('[LEANTIME_ADAPTER] Notification counts:', { total: totalCount, - unread: unreadCount + unread: unreadCount, + read: totalCount - unreadCount, + note: totalCount === 100 ? 'WARNING: May have more than 100 notifications total' : 'OK' }); return { @@ -219,15 +223,17 @@ export class LeantimeAdapter implements NotificationAdapter { // Get user email and ID const email = await this.getUserEmail(); if (!email) { - console.error('[LEANTIME_ADAPTER] Could not get user email from session'); + console.error('[LEANTIME_ADAPTER] markAllAsRead - Could not get user email from session'); return false; } + console.log(`[LEANTIME_ADAPTER] markAllAsRead - User email: ${email}`); const leantimeUserId = await this.getLeantimeUserId(email); if (!leantimeUserId) { - console.error('[LEANTIME_ADAPTER] User not found in Leantime:', email); + console.error('[LEANTIME_ADAPTER] markAllAsRead - User not found in Leantime:', email); return false; } + console.log(`[LEANTIME_ADAPTER] markAllAsRead - Leantime user ID: ${leantimeUserId}`); // Make request to Leantime API to mark all notifications as read const jsonRpcBody = { @@ -239,6 +245,9 @@ export class LeantimeAdapter implements NotificationAdapter { id: 1 }; + console.log(`[LEANTIME_ADAPTER] markAllAsRead - Request body:`, JSON.stringify(jsonRpcBody)); + console.log(`[LEANTIME_ADAPTER] markAllAsRead - API URL: ${this.apiUrl}/api/jsonrpc`); + const response = await fetch(`${this.apiUrl}/api/jsonrpc`, { method: 'POST', headers: { @@ -248,15 +257,44 @@ export class LeantimeAdapter implements NotificationAdapter { body: JSON.stringify(jsonRpcBody) }); + console.log(`[LEANTIME_ADAPTER] markAllAsRead - Response status: ${response.status}`); + if (!response.ok) { - console.error(`[LEANTIME_ADAPTER] Failed to mark all notifications as read: ${response.status}`); + const errorText = await response.text(); + console.error(`[LEANTIME_ADAPTER] markAllAsRead - HTTP Error ${response.status}:`, errorText.substring(0, 500)); return false; } - const data = await response.json(); - return data.result === true || data.result === "true" || !!data.result; + const responseText = await response.text(); + console.log(`[LEANTIME_ADAPTER] markAllAsRead - Response body:`, responseText.substring(0, 500)); + + let data; + try { + data = JSON.parse(responseText); + } catch (parseError) { + console.error(`[LEANTIME_ADAPTER] markAllAsRead - Failed to parse response:`, parseError); + console.error(`[LEANTIME_ADAPTER] markAllAsRead - Raw response:`, responseText); + return false; + } + + console.log(`[LEANTIME_ADAPTER] markAllAsRead - Parsed response:`, { + hasResult: 'result' in data, + result: data.result, + hasError: 'error' in data, + error: data.error + }); + + if (data.error) { + console.error(`[LEANTIME_ADAPTER] markAllAsRead - API Error:`, data.error); + return false; + } + + const success = data.result === true || data.result === "true" || !!data.result; + console.log(`[LEANTIME_ADAPTER] markAllAsRead - Success: ${success}`); + return success; } catch (error) { - console.error('[LEANTIME_ADAPTER] Error marking all notifications as read:', error); + console.error('[LEANTIME_ADAPTER] markAllAsRead - Exception:', error); + console.error('[LEANTIME_ADAPTER] markAllAsRead - Error stack:', error instanceof Error ? error.stack : 'No stack'); return false; } } diff --git a/log b/log index e69de29b..8b137891 100644 --- a/log +++ b/log @@ -0,0 +1 @@ +