Fondation

This commit is contained in:
alma 2026-01-16 21:50:59 +01:00
parent 0bfa26838a
commit c341468996
3 changed files with 42 additions and 65 deletions

View File

@ -68,7 +68,6 @@ async function getLeantimeUserId(email: string): Promise<number | null> {
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<string, string> = {
'Content-Type': 'application/json',

View File

@ -115,7 +115,6 @@ async function getTwentyCrmUserId(email: string): Promise<string | null> {
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<TwentyTask[]> {
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<TwentyTask[]> {
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<TwentyTask[]> {
};
});
// 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<TwentyTask[]> {
.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<TwentyTask[]> {
(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<TwentyTask[]> {
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),
});

View File

@ -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),
});
}
}