From 00549b5dfe3e8874eb330a1ab49240caee7214b0 Mon Sep 17 00:00:00 2001 From: Aryanshravan Date: Thu, 21 May 2026 00:06:08 +0530 Subject: [PATCH] Feat implement centralized error handling for API routes --- CODEBASE_ISSUES.md | 708 +++++++++++++++++++++++ package-lock.json | 67 +-- src/app/api/badge/commits/route.ts | 9 +- src/app/api/badge/streak-shield/route.ts | 9 +- src/app/api/webhooks/github/route.ts | 11 +- src/lib/error-handler.ts | 92 +++ 6 files changed, 828 insertions(+), 68 deletions(-) create mode 100644 CODEBASE_ISSUES.md create mode 100644 src/lib/error-handler.ts diff --git a/CODEBASE_ISSUES.md b/CODEBASE_ISSUES.md new file mode 100644 index 00000000..66d7f497 --- /dev/null +++ b/CODEBASE_ISSUES.md @@ -0,0 +1,708 @@ +# DevTrack Codebase Analysis Report +**Generated:** May 20, 2026 +**Total Issues Found:** 15 intermediate-level issues + +--- + +## 🔴 Issue #1: Missing Input Validation in Goal Creation Form + +**Title:** Goal title input lacks validation constraints (length limits, special characters) + +**Description:** +The goal creation form in `GoalTracker.tsx` accepts any string as a title without validation. There are no: +- Maximum length limits (could cause DB storage issues or UI overflow) +- Minimum length validation (empty string after trim check could be submitted) +- Sanitization of special characters (potential XSS or SQL injection vectors) +- Required field indicators for users + +Users can create goals with titles that are excessively long or contain problematic characters. + +**Location:** [src/components/GoalTracker.tsx](src/components/GoalTracker.tsx#L60-L75) + +**Code Context:** +```typescript +async function handleCreate(e: React.FormEvent) { + // ... + const response = await fetch("/api/goals", { + method: "POST", + body: JSON.stringify({ title, target, unit, recurrence }), + }); + // Only checks if title exists, no length/content validation +} +``` + +**Difficulty:** Intermediate + +**Why It Matters:** +- Could lead to UI layout issues with extremely long titles +- Database might enforce limits that aren't reflected in UI (poor UX) +- Special characters could cause rendering issues or security vulnerabilities +- Users get no feedback about constraints before submission + +**Suggested Approach:** +1. Add client-side validation in `handleCreate()`: check title length (2-100 chars recommended) +2. Add HTML5 `maxLength` attribute to the input field +3. Validate target is a positive integer +4. Show error messages for invalid inputs before submit +5. Add required field indicators with asterisks +6. Sanitize title on the server (POST `/api/goals`) as backup + +**Impact:** Medium - affects usability and data quality + +--- + +## 🔴 Issue #2: Missing Error Boundary on Dashboard Page + +**Title:** No error boundary wrapper for dashboard components + +**Description:** +The dashboard page renders 17+ complex components (ContributionGraph, PRMetrics, etc.) but has no error boundary to catch component errors. If any single component throws an uncaught error, the entire dashboard becomes unusable with a blank screen or cryptic browser error. + +**Location:** [src/app/dashboard/page.tsx](src/app/dashboard/page.tsx#L1-L70) + +**Current State:** +- Only the app-level `error.tsx` exists +- Dashboard components can fail independently +- No fallback UI for individual widget failures +- Users can't identify which component failed + +**Difficulty:** Intermediate + +**Why It Matters:** +- Improves resilience - one broken widget doesn't crash the entire dashboard +- Better error reporting - can log which specific component failed +- Better UX - users see partial dashboard instead of blank page +- Easier debugging - error boundaries show stack traces + +**Suggested Approach:** +1. Create a `DashboardErrorBoundary.tsx` wrapper component +2. Wrap each major section (StreakTracker, PRMetrics, GoalTracker, etc.) or use a grid-level boundary +3. Show error UI with "Try again" button and error message per widget +4. Log errors to monitoring service (if available) +5. Add `ErrorBoundary` from a library like `react-error-boundary` if not already imported + +**Impact:** High - affects user experience during failures + +--- + +## 🔴 Issue #3: Incomplete Error Handling with Empty Catch Blocks + +**Title:** Multiple catch blocks silently swallow errors without logging + +**Description:** +Several components use `.catch(() => {})` patterns that swallow errors completely without any logging, fallback, or user notification. This makes debugging difficult and hides potential issues. + +**Location:** Multiple files +- [src/components/GoalTracker.tsx](src/components/GoalTracker.tsx#L48-L52) - `loadGoals().catch(() => {})` +- [src/components/StreakAtRiskBanner.tsx](src/components/StreakAtRiskBanner.tsx#L33) - `.catch(() => {})` +- [src/components/ContributionHeatmap.tsx](src/components/ContributionHeatmap.tsx#L71-L100) + +**Code Example:** +```typescript +// Bad: Silently fails +loadGoals() + .catch(() => {}) + .finally(() => { setLoading(false); }); + +// Better: Log error +loadGoals() + .catch((err) => { + console.error("Failed to load goals:", err); + setError("Failed to load goals. Please try again."); + }) +``` + +**Difficulty:** Intermediate + +**Why It Matters:** +- Errors are hidden from developers - makes debugging nearly impossible +- Users don't know something failed +- Can mask data corruption or API issues +- Makes monitoring and alerting ineffective + +**Suggested Approach:** +1. Add error logging to console: `console.error(error)` +2. Set error state to show user feedback: `setError("Failed to load data")` +3. Consider adding error tracking service (Sentry, etc.) +4. Create a shared `logError()` utility function for consistency +5. Show toast/banner notifications for recoverable errors + +**Impact:** Medium - affects debugging and monitoring + +--- + +## 🔴 Issue #4: Race Condition in Goal Period Reset + +**Title:** Concurrent requests can cause goal progress to be lost during period reset + +**Description:** +The `/api/goals` GET endpoint has a race condition where concurrent requests checking period_start can both see the old value and attempt to reset. While there's a `.lt()` condition to prevent double-updates, if two requests race, the second one might not see the reset goal before returning. + +**Location:** [src/app/api/goals/route.ts](src/app/api/goals/route.ts#L50-L80) + +**Code Context:** +```typescript +// Two concurrent requests both see period_start < periodStart +// Request 1 updates: current = 0, period_start = new +// Request 2 sees .lt() fails, tries to fetch again +// But there's a window where both see stale data +``` + +**Difficulty:** Intermediate + +**Why It Matters:** +- Goal progress could be lost if reset happens at the same time as fetch +- Users might not see accurate goal progress +- Edge case that's hard to reproduce and debug +- Could cause frustration if users' goal progress mysteriously resets + +**Suggested Approach:** +1. Use server-side caching with a cache key including period to prevent multiple resets +2. Add optimistic locking with version numbers to goals table +3. Use database transactions if Supabase supports them +4. Consider moving period reset logic to a scheduled job rather than on GET +5. Add a debounce on the frontend to prevent multiple concurrent API calls + +**Impact:** Medium - affects data consistency + +--- + +## 🔴 Issue #5: Missing Null Safety Checks in Contribution Graph + +**Title:** Potential null/undefined errors in `mergeContributionData()` function + +**Description:** +The `mergeContributionData()` function doesn't validate input arrays before processing them. If the API returns null or undefined, the code will throw an error. + +**Location:** [src/components/ContributionGraph.tsx](src/components/ContributionGraph.tsx#L40-L65) + +**Code:** +```typescript +function mergeContributionData( + myData: DayData[], + friendData: DayData[] +): GraphPoint[] { + const map = new Map(); + + myData.forEach(d => { // ❌ myData could be null + map.set(d.day, { date: d.day, you: d.commits, friend: 0 }); + }); + // No null checks +} +``` + +**Difficulty:** Intermediate + +**Why It Matters:** +- Unhandled errors crash the component +- Defensive programming catches API inconsistencies +- Better error messages help debugging +- Improves component reliability + +**Suggested Approach:** +1. Add null checks: `if (!myData?.length || !friendData?.length) return [];` +2. Add type guards for expected data shape +3. Return early with fallback value if data is invalid +4. Log warning if data shape is unexpected +5. Add unit tests for edge cases + +**Impact:** Medium - affects component reliability + +--- + +## 🔴 Issue #6: Missing Accessibility Labels on Form Inputs + +**Title:** Goal tracker form inputs missing associated labels and ARIA attributes + +**Description:** +The goal creation form inputs (`title`, `target`, `unit`, `recurrence`) lack proper `