diff --git a/app/api/leantime/tasks/route.ts b/app/api/leantime/tasks/route.ts index e633d03..d92e694 100644 --- a/app/api/leantime/tasks/route.ts +++ b/app/api/leantime/tasks/route.ts @@ -68,7 +68,6 @@ async function getLeantimeUserId(email: string): Promise { if (user) { logger.debug('[LEANTIME_TASKS] Found Leantime user', { - id: user.id, emailHash: Buffer.from(email.toLowerCase()).toString('base64').slice(0, 12), }); } else { @@ -102,7 +101,7 @@ export async function GET(request: NextRequest) { const cachedTasks = await getCachedTasksData(session.user.id); if (cachedTasks) { logger.debug('[LEANTIME_TASKS] Using cached tasks data', { - userId: session.user.id, + emailHash: Buffer.from(session.user.email.toLowerCase()).toString('base64').slice(0, 12), taskCount: Array.isArray(cachedTasks) ? cachedTasks.length : undefined, }); return NextResponse.json(cachedTasks); @@ -121,8 +120,8 @@ export async function GET(request: NextRequest) { return NextResponse.json({ error: "User not found in Leantime" }, { status: 404 }); } - logger.debug('[LEANTIME_TASKS] Fetching tasks for Leantime user ID', { - userId, + logger.debug('[LEANTIME_TASKS] Fetching tasks for Leantime user', { + emailHash: Buffer.from(session.user.email.toLowerCase()).toString('base64').slice(0, 12), }); const headers: Record = { 'Content-Type': 'application/json', diff --git a/app/api/twenty-crm/tasks/route.ts b/app/api/twenty-crm/tasks/route.ts index d18a11a..b6fcac7 100644 --- a/app/api/twenty-crm/tasks/route.ts +++ b/app/api/twenty-crm/tasks/route.ts @@ -115,7 +115,6 @@ async function getTwentyCrmUserId(email: string): Promise { if (member) { logger.debug('[TWENTY_CRM_TASKS] Found workspace member', { - memberId: member.node.id, emailHash: Buffer.from(email.toLowerCase()).toString('base64').slice(0, 12), }); return member.node.id; @@ -230,12 +229,11 @@ async function fetchTwentyTasks(userId?: string): Promise { return []; } - // Log raw response for debugging (using error level to ensure visibility) - logger.error('[TWENTY_CRM_TASKS] Raw GraphQL response', { + // Log raw response metadata (no sensitive data) + logger.debug('[TWENTY_CRM_TASKS] Raw GraphQL response received', { hasData: !!data.data, dataKeys: data.data ? Object.keys(data.data) : [], tasksEdgesCount: data.data?.tasks?.edges?.length || 0, - sampleResponse: JSON.stringify(data.data).substring(0, 1000), }); // Try different possible response structures @@ -270,21 +268,12 @@ async function fetchTwentyTasks(userId?: string): Promise { if (!activitiesData) { logger.warn('[TWENTY_CRM_TASKS] Unexpected response format from Twenty CRM', { dataKeys: Object.keys(data.data || {}), - fullData: JSON.stringify(data.data).substring(0, 2000), }); return []; } logger.debug('[TWENTY_CRM_TASKS] Activities data extracted', { count: activitiesData.length, - sample: activitiesData.length > 0 ? { - firstTask: { - id: activitiesData[0]?.node?.id || activitiesData[0]?.id, - title: activitiesData[0]?.node?.title || activitiesData[0]?.title, - status: activitiesData[0]?.node?.status || activitiesData[0]?.status, - dueAt: activitiesData[0]?.node?.dueAt || activitiesData[0]?.dueAt, - } - } : null, }); // Transform Twenty CRM tasks to match our Task interface @@ -318,37 +307,20 @@ async function fetchTwentyTasks(userId?: string): Promise { }; }); - // Log all tasks before filtering for debugging (using error level to ensure visibility) - logger.error('[TWENTY_CRM_TASKS] All tasks before filtering', { + // Log task count before filtering (no sensitive data) + logger.debug('[TWENTY_CRM_TASKS] Tasks before filtering', { count: allTasks.length, - tasks: allTasks.map(t => ({ - id: t.id, - title: t.title, - status: t.status, - dueAt: t.dueAt, - assigneeId: t.assigneeId, - hasDueDate: !!t.dueAt, - })), }); // Filter by assignee if userId is provided let filteredByAssignee = allTasks; if (userId) { filteredByAssignee = allTasks.filter((task: TwentyTask) => { - const isAssignedToUser = task.assigneeId === userId; - if (!isAssignedToUser) { - logger.debug('[TWENTY_CRM_TASKS] Filtering out task not assigned to user', { - id: task.id, - assigneeId: task.assigneeId, - userId, - }); - } - return isAssignedToUser; + return task.assigneeId === userId; }); - logger.error('[TWENTY_CRM_TASKS] Tasks after assignee filter', { + logger.debug('[TWENTY_CRM_TASKS] Tasks after assignee filter', { before: allTasks.length, after: filteredByAssignee.length, - userId, }); } @@ -363,12 +335,10 @@ async function fetchTwentyTasks(userId?: string): Promise { .filter((task: TwentyTask) => { // Filter: only overdue tasks (dueAt < today) and not completed if (task.status === 'Done') { - logger.debug('[TWENTY_CRM_TASKS] Filtering out Done task', { id: task.id, status: task.status }); return false; } if (!task.dueAt) { - logger.debug('[TWENTY_CRM_TASKS] Filtering out task without due date', { id: task.id }); return false; // Exclude tasks without due date } @@ -386,14 +356,6 @@ async function fetchTwentyTasks(userId?: string): Promise { (taskYear === todayYear && taskMonth < todayMonth) || (taskYear === todayYear && taskMonth === todayMonth && taskDay <= todayDay); - logger.error('[TWENTY_CRM_TASKS] Task date check', { - id: task.id, - dueAt: task.dueAt, - taskDate: `${taskYear}-${String(taskMonth + 1).padStart(2, '0')}-${String(taskDay).padStart(2, '0')}`, - todayDate: `${todayYear}-${String(todayMonth + 1).padStart(2, '0')}-${String(todayDay).padStart(2, '0')}`, - isOverdueOrDueToday, - }); - return isOverdueOrDueToday; // Include overdue tasks and tasks due today }) .sort((a: TwentyTask, b: TwentyTask) => { @@ -406,12 +368,6 @@ async function fetchTwentyTasks(userId?: string): Promise { logger.debug('[TWENTY_CRM_TASKS] Tasks after filtering', { count: tasks.length, - tasks: tasks.map(t => ({ - id: t.id, - title: t.title, - status: t.status, - dueAt: t.dueAt, - })), }); logger.debug('[TWENTY_CRM_TASKS] Successfully fetched tasks from Twenty CRM', { @@ -463,7 +419,6 @@ export async function GET(request: NextRequest) { } logger.debug('[TWENTY_CRM_TASKS] Found Twenty CRM user ID', { - userId: twentyCrmUserId, emailHash: Buffer.from(session.user.email.toLowerCase()).toString('base64').slice(0, 12), }); diff --git a/lib/redis.ts b/lib/redis.ts index f7a11ee..adf60aa 100644 --- a/lib/redis.ts +++ b/lib/redis.ts @@ -1,5 +1,6 @@ import Redis from 'ioredis'; import CryptoJS from 'crypto-js'; +import { logger } from './logger'; // Initialize Redis client let redisClient: Redis | null = null; @@ -518,9 +519,14 @@ export async function cacheCalendarData( try { await redis.set(key, JSON.stringify(data), 'EX', TTL.CALENDAR); - console.log(`Calendar data cached for user ${userId}`); + logger.debug('[REDIS] Calendar data cached', { + userIdHash: Buffer.from(userId).toString('base64').slice(0, 12), + }); } catch (error) { - console.error(`Error caching calendar data for user ${userId}:`, error); + logger.error('[REDIS] Error caching calendar data', { + userIdHash: Buffer.from(userId).toString('base64').slice(0, 12), + error: error instanceof Error ? error.message : String(error), + }); } } @@ -641,9 +647,14 @@ export async function cacheTasksData( try { await redis.set(key, JSON.stringify(data), 'EX', TTL.TASKS); - console.log(`Tasks data cached for user ${userId}`); + logger.debug('[REDIS] Tasks data cached', { + userIdHash: Buffer.from(userId).toString('base64').slice(0, 12), + }); } catch (error) { - console.error(`Error caching tasks data for user ${userId}:`, error); + logger.error('[REDIS] Error caching tasks data', { + userIdHash: Buffer.from(userId).toString('base64').slice(0, 12), + error: error instanceof Error ? error.message : String(error), + }); } } @@ -664,7 +675,10 @@ export async function getCachedTasksData( return JSON.parse(cachedData); } catch (error) { - console.error(`Error getting cached tasks data for user ${userId}:`, error); + logger.error('[REDIS] Error getting cached tasks data', { + userIdHash: Buffer.from(userId).toString('base64').slice(0, 12), + error: error instanceof Error ? error.message : String(error), + }); return null; } } @@ -680,9 +694,14 @@ export async function invalidateTasksCache( try { await redis.del(key); - console.log(`Tasks cache invalidated for user ${userId}`); + logger.debug('[REDIS] Tasks cache invalidated', { + userIdHash: Buffer.from(userId).toString('base64').slice(0, 12), + }); } catch (error) { - console.error(`Error invalidating tasks cache for user ${userId}:`, error); + logger.error('[REDIS] Error invalidating tasks cache', { + userIdHash: Buffer.from(userId).toString('base64').slice(0, 12), + error: error instanceof Error ? error.message : String(error), + }); } } @@ -698,10 +717,14 @@ export async function cacheMessagesData( try { await redis.set(key, JSON.stringify(data), 'EX', TTL.MESSAGES); - // Debug-only; safe to be silent in production - // logger.debug('[REDIS] Messages data cached', { userId }); + logger.debug('[REDIS] Messages data cached', { + userIdHash: Buffer.from(userId).toString('base64').slice(0, 12), + }); } catch (error) { - console.error(`Error caching messages data for user ${userId}:`, error); + logger.error('[REDIS] Error caching messages data', { + userIdHash: Buffer.from(userId).toString('base64').slice(0, 12), + error: error instanceof Error ? error.message : String(error), + }); } }