From ac36667dade49bec5d55ae05056c2f483cf23227 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 06:30:49 +0100 Subject: [PATCH 01/21] auto-claude: subtask-1-1 - Add JSDoc to errorHandling.ts (AppError class, han --- src/utils/errorHandling.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/utils/errorHandling.ts b/src/utils/errorHandling.ts index 3a6e561..4a8689f 100644 --- a/src/utils/errorHandling.ts +++ b/src/utils/errorHandling.ts @@ -1,5 +1,13 @@ +/** + * Error Handling Utilities + * Centralized error handling and custom error types + */ + import { trackEvent } from './analytics'; +/** + * Custom application error class with error codes, severity levels, and metadata + */ export class AppError extends Error { constructor( message: string, @@ -12,6 +20,9 @@ export class AppError extends Error { } } +/** + * Standard error codes used throughout the application + */ export const errorCodes = { NETWORK_ERROR: 'ERR_NETWORK', API_ERROR: 'ERR_API', @@ -20,6 +31,9 @@ export const errorCodes = { UNKNOWN_ERROR: 'ERR_UNKNOWN' } as const; +/** + * Handle and normalize errors with tracking and logging + */ export const handleError = (error: unknown, context: string) => { let appError: AppError; @@ -52,6 +66,9 @@ export const handleError = (error: unknown, context: string) => { return appError; }; +/** + * Create an API error with HTTP status code + */ export const createAPIError = (status: number, message: string) => { return new AppError( message, From d1b866565269cea503bafb38b7e0d3cd2f55d201 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 06:32:11 +0100 Subject: [PATCH 02/21] auto-claude: subtask-1-2 - Add JSDoc to cache.ts (Cache class and its 5 methods) --- src/utils/cache.ts | 50 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/src/utils/cache.ts b/src/utils/cache.ts index d04a660..9f701e0 100644 --- a/src/utils/cache.ts +++ b/src/utils/cache.ts @@ -1,18 +1,39 @@ +/** + * In-Memory Cache Utility + * Provides simple key-value caching with TTL (Time To Live) support + */ + +/** + * Cache item structure with value, timestamp, and TTL + */ type CacheItem = { value: T; timestamp: number; ttl: number; }; +/** + * In-memory cache implementation with automatic expiration + */ class Cache { private storage: Map>; private readonly defaultTTL: number; + /** + * Create a new cache instance + * @param defaultTTL - Default time-to-live in milliseconds (default: 5 minutes) + */ constructor(defaultTTL = 5 * 60 * 1000) { // 5 minutes default TTL this.storage = new Map(); this.defaultTTL = defaultTTL; } + /** + * Store a value in cache with optional TTL + * @param key - Cache key + * @param value - Value to cache + * @param ttl - Time-to-live in milliseconds (uses default if not specified) + */ set(key: string, value: T, ttl = this.defaultTTL): void { this.storage.set(key, { value, @@ -21,30 +42,51 @@ class Cache { }); } + /** + * Retrieve a value from cache + * Returns null if key doesn't exist or has expired + * @param key - Cache key + * @returns Cached value or null + */ get(key: string): T | null { const item = this.storage.get(key); - + if (!item) return null; - + if (Date.now() > item.timestamp + item.ttl) { this.storage.delete(key); return null; } - + return item.value; } + /** + * Check if a key exists and is not expired + * @param key - Cache key + * @returns True if key exists and is valid + */ has(key: string): boolean { return this.get(key) !== null; } + /** + * Remove a specific key from cache + * @param key - Cache key to delete + */ delete(key: string): void { this.storage.delete(key); } + /** + * Clear all cached items + */ clear(): void { this.storage.clear(); } } -export const cache = new Cache(); \ No newline at end of file +/** + * Shared cache instance with 5-minute default TTL + */ +export const cache = new Cache(); From baa3ad05715ab664ef0b9d813898802b4527ac8b Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 06:33:46 +0100 Subject: [PATCH 03/21] auto-claude: subtask-1-3 - Add JSDoc to rateLimiting.ts (RateLimiter class and methods) Co-Authored-By: Claude Sonnet 4.5 --- src/utils/rateLimiting.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/utils/rateLimiting.ts b/src/utils/rateLimiting.ts index f1a77b7..7ce2248 100644 --- a/src/utils/rateLimiting.ts +++ b/src/utils/rateLimiting.ts @@ -1,3 +1,6 @@ +/** + * Rate limit entry tracking request count and timestamp + */ interface RateLimitEntry { count: number; timestamp: number; @@ -6,6 +9,10 @@ interface RateLimitEntry { const WINDOW_SIZE_MS = 3600000; // 1 hour const MAX_REQUESTS = 5; // Maximum requests per hour +/** + * Rate Limiter for API request throttling + * Manages rate limiting based on IP addresses with sliding window + */ class RateLimiter { private cache: Map; @@ -13,6 +20,9 @@ class RateLimiter { this.cache = new Map(); } + /** + * Check if an IP address is currently rate limited + */ isRateLimited(ip: string): boolean { const now = Date.now(); const entry = this.cache.get(ip); @@ -35,6 +45,9 @@ class RateLimiter { return false; } + /** + * Get remaining attempts for an IP address + */ getRemainingAttempts(ip: string): number { const entry = this.cache.get(ip); if (!entry) { @@ -43,6 +56,9 @@ class RateLimiter { return Math.max(0, MAX_REQUESTS - entry.count); } + /** + * Get time in milliseconds until rate limit resets for an IP + */ getTimeToReset(ip: string): number { const entry = this.cache.get(ip); if (!entry) { From f2b4c0a227404c3a796e93257f6b2de3614b5386 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 06:35:04 +0100 Subject: [PATCH 04/21] auto-claude: subtask-1-4 - Add JSDoc to api.ts (fetchWithTimeout function) --- src/utils/api.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/utils/api.ts b/src/utils/api.ts index 53326d6..b244e06 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -1,9 +1,25 @@ +/** + * API Utility Functions + * Provides enhanced fetch functionality with timeout support + */ + import { handleError, createAPIError } from './errorHandling'; +/** + * Extended request options with timeout support + */ interface RequestOptions extends RequestInit { + /** Request timeout in milliseconds (default: 8000ms) */ timeout?: number; } +/** + * Fetch with automatic timeout and error handling + * @param resource - URL or resource to fetch + * @param options - Request options including optional timeout + * @returns Promise resolving to the fetch Response + * @throws {Error} On timeout, network error, or HTTP error status + */ export async function fetchWithTimeout( resource: string, options: RequestOptions = {} From 09c6f31ff0c4c434d25a147eaac69f3877483d09 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 06:36:11 +0100 Subject: [PATCH 05/21] auto-claude: subtask-2-1 - Add JSDoc to auth.ts (checkAuth, signOut functions) --- src/utils/auth.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/utils/auth.ts b/src/utils/auth.ts index c57b754..3af825e 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,17 +1,33 @@ +/** + * Authentication Utility Functions + * Handles user authentication checks and sign out operations + */ + import { supabase } from './supabaseClient'; import { NavigateFunction } from 'react-router-dom'; +/** + * Check if user is authenticated + * Verifies the current session and redirects to login if not authenticated + * @param {NavigateFunction} navigate - React Router navigate function for redirects + * @returns {Promise} True if authenticated, false otherwise + */ export const checkAuth = async (navigate: NavigateFunction) => { const { data: { session } } = await supabase.auth.getSession(); - + if (!session) { navigate('/login'); return false; } - + return true; }; +/** + * Sign out current user + * Terminates the user session and redirects to login page + * @param {NavigateFunction} navigate - React Router navigate function for redirects + */ export const signOut = async (navigate: NavigateFunction) => { await supabase.auth.signOut(); navigate('/login'); From 9860aa0dd26d744bdcc09a8bdf1f124ff8304e4c Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 06:37:23 +0100 Subject: [PATCH 06/21] auto-claude: subtask-2-2 - Add JSDoc to csrf.ts --- src/utils/csrf.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/utils/csrf.ts b/src/utils/csrf.ts index 98f24f0..7430a6d 100644 --- a/src/utils/csrf.ts +++ b/src/utils/csrf.ts @@ -1,20 +1,31 @@ +/** + * CSRF Token Utility + * Verwaltung von Cross-Site Request Forgery Schutz-Tokens + */ + import { v4 as uuidv4 } from 'uuid'; // CSRF token storage let csrfToken: string | null = null; -// Generate a new CSRF token +/** + * Generate a new CSRF token + */ export const generateCsrfToken = (): string => { csrfToken = uuidv4(); return csrfToken; }; -// Validate a CSRF token +/** + * Validate a CSRF token + */ export const validateCsrfToken = (token: string): boolean => { return token === csrfToken; }; -// Get the current CSRF token +/** + * Get the current CSRF token + */ export const getCsrfToken = (): string => { if (!csrfToken) { return generateCsrfToken(); From a033c0d9e666f01f46b7c256ac630daa3bf58192 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 06:39:22 +0100 Subject: [PATCH 07/21] auto-claude: subtask-2-3 - Add JSDoc to analytics.ts --- src/utils/analytics.ts | 45 +++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/utils/analytics.ts b/src/utils/analytics.ts index 6fa8535..4f268d8 100644 --- a/src/utils/analytics.ts +++ b/src/utils/analytics.ts @@ -1,9 +1,16 @@ +/** + * Analytics Service + * Zentrale Verwaltung von Google Analytics, Facebook Pixel und Cookie-basiertem Tracking + */ + import ReactGA from 'react-ga4'; const TRACKING_ID = 'G-N0PZBL7X18'; const FB_PIXEL_ID = 'XXXXXXXXXXXXXXXXX'; // Ersetze mit deiner Facebook Pixel ID -// Prüft, ob eine bestimmte Cookie-Kategorie aktiviert ist +/** + * Prüft, ob eine bestimmte Cookie-Kategorie aktiviert ist + */ export const isCookieCategoryEnabled = (category: string): boolean => { try { const cookieSettings = localStorage.getItem('cookieSettings'); @@ -17,7 +24,9 @@ export const isCookieCategoryEnabled = (category: string): boolean => { } }; -// Entfernt alle Google Analytics Cookies +/** + * Entfernt alle Google Analytics Cookies + */ const removeGACookies = (): void => { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { @@ -33,7 +42,9 @@ const removeGACookies = (): void => { } }; -// Google Analytics Initialisierung - mit strikter Zustimmungsprüfung +/** + * Initialisiert Google Analytics mit strikter Zustimmungsprüfung + */ export const initGA = (): void => { if (!isCookieCategoryEnabled('analytics')) { // Entferne bestehende GA-Cookies, falls keine Zustimmung @@ -49,6 +60,9 @@ export const initGA = (): void => { }); }; +/** + * Loggt einen Seitenaufruf in Google Analytics + */ export const logPageView = (): void => { if (!isCookieCategoryEnabled('analytics')) { return; @@ -61,6 +75,9 @@ export const logPageView = (): void => { }); }; +/** + * Trackt ein benutzerdefiniertes Event + */ export const trackEvent = (category: string, action: string, label?: string): void => { if (!isCookieCategoryEnabled('analytics')) { return; @@ -73,6 +90,9 @@ export const trackEvent = (category: string, action: string, label?: string): vo }); }; +/** + * Trackt eine Conversion + */ export const trackConversion = (value?: number): void => { if (!isCookieCategoryEnabled('analytics')) { return; @@ -85,6 +105,9 @@ export const trackConversion = (value?: number): void => { }); }; +/** + * Trackt Performance-Timing + */ export const trackTiming = (category: string, variable: string, value: number): void => { if (!isCookieCategoryEnabled('analytics')) { return; @@ -98,7 +121,9 @@ export const trackTiming = (category: string, variable: string, value: number): }); }; -// Facebook Pixel Initialisierung - nur mit Zustimmung +/** + * Initialisiert Facebook Pixel nur mit Zustimmung + */ export const initFBPixel = (): void => { if (!isCookieCategoryEnabled('marketing')) { return; @@ -122,7 +147,9 @@ export const initFBPixel = (): void => { } }; -// Facebook Event tracking +/** + * Trackt Facebook Pixel Events + */ export const trackFBEvent = (event: string, params?: Record): void => { if (!isCookieCategoryEnabled('marketing') || typeof window === 'undefined' || !window.fbq) { return; @@ -131,7 +158,9 @@ export const trackFBEvent = (event: string, params?: Record): v window.fbq('track', event, params); }; -// Google Fonts Handling - nur mit funktionaler Cookie-Zustimmung +/** + * Initialisiert Google Fonts nur mit funktionaler Cookie-Zustimmung + */ export const initGoogleFonts = (): void => { if (!isCookieCategoryEnabled('functional')) { // Entferne bestehende Google Fonts @@ -151,7 +180,9 @@ export const initGoogleFonts = (): void => { // Code hier zur lokalen Einbindung der Schriftarten }; -// Funktionale Cookies initialisieren +/** + * Initialisiert funktionale Cookies und Services + */ export const initFunctionalCookies = (): void => { if (!isCookieCategoryEnabled('functional')) { return; From 4d9e0d3a2947c61996c5cc102839883f2182be50 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 06:40:57 +0100 Subject: [PATCH 08/21] auto-claude: subtask-3-1 - Add JSDoc to constants.ts --- src/utils/constants.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index f8df747..bbac2da 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1,6 +1,12 @@ -// src/utils/constants.ts -// Zentrale Konstanten für die gesamte Website +/** + * Application Constants + * Zentrale Konstanten für die gesamte Website + */ +/** + * Contact information + * Kontaktinformationen für alle Kontaktpunkte auf der Website + */ export const CONTACT = { email: "info@damjan-savic.com", phone: "+49 175 695 0979", @@ -14,12 +20,20 @@ export const CONTACT = { } } as const; +/** + * Current professional role + * Aktuelle berufliche Position und Unternehmen + */ export const CURRENT_ROLE = { company: "Everlast Consulting GmbH", position: "Process Automation Specialist", since: "2024-12" } as const; +/** + * Profile information + * Profil- und persönliche Informationen für die gesamte Website + */ export const PROFILE = { name: "Damjan Savić", title: "AI & Automation Specialist", From b4f9ac947b2e9788b22f5ce9b067bb17500d6888 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 06:42:26 +0100 Subject: [PATCH 09/21] auto-claude: subtask-3-2 - Add JSDoc to fontLoader.ts --- src/utils/fontLoader.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/utils/fontLoader.ts b/src/utils/fontLoader.ts index 3aab35f..f04ec64 100644 --- a/src/utils/fontLoader.ts +++ b/src/utils/fontLoader.ts @@ -1,4 +1,13 @@ -// Font loading utility to ensure fonts are loaded before showing content +/** + * Font Loading Utility + * Ensures fonts are loaded before showing content to prevent FOUT/FOIT + */ + +/** + * Preload fonts asynchronously + * Uses the Font Loading API to ensure Inter font is loaded + * Falls back to system fonts on error + */ export const preloadFonts = async () => { if ('fonts' in document) { try { @@ -12,14 +21,18 @@ export const preloadFonts = async () => { } }; -// Call this function as early as possible +/** + * Initialize font loading process + * Should be called as early as possible in the application lifecycle + * Adds loading state and fallback timeout to prevent indefinite loading + */ export const initializeFonts = () => { // Add loading class immediately document.documentElement.classList.add('fonts-loading'); - + // Start font loading preloadFonts(); - + // Remove loading class after a timeout to prevent indefinite loading state setTimeout(() => { document.documentElement.classList.remove('fonts-loading'); @@ -27,4 +40,4 @@ export const initializeFonts = () => { document.documentElement.classList.add('fonts-fallback'); } }, 3000); -}; \ No newline at end of file +}; From cf6b80201c0e56b9689540f9e70a2a9b56b4c0c9 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 11:54:12 +0100 Subject: [PATCH 10/21] auto-claude: subtask-3-3 - Add JSDoc to serviceWorkerRegistration.ts --- src/utils/serviceWorkerRegistration.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/utils/serviceWorkerRegistration.ts b/src/utils/serviceWorkerRegistration.ts index 1246246..72d05f3 100644 --- a/src/utils/serviceWorkerRegistration.ts +++ b/src/utils/serviceWorkerRegistration.ts @@ -1,3 +1,12 @@ +/** + * Service Worker Registration Utility + * Handles registration and unregistration of service workers for PWA functionality + */ + +/** + * Registers the service worker + * Automatically registers the service worker after the window load event + */ export function register() { if ('serviceWorker' in navigator) { window.addEventListener('load', () => { @@ -14,6 +23,10 @@ export function register() { } } +/** + * Unregisters the service worker + * Removes the currently registered service worker + */ export function unregister() { if ('serviceWorker' in navigator) { navigator.serviceWorker.ready From a64647cce0b268d7c7153a2026f1157f0ef39ed2 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 11:55:17 +0100 Subject: [PATCH 11/21] auto-claude: subtask-3-4 - Add JSDoc to supabaseClient.ts --- .auto-claude-security.json | 227 ++++++++++++++++++++++++++++++++++++ .auto-claude-status | 25 ++++ .claude_settings.json | 39 +++++++ .gitignore | 5 +- src/utils/supabaseClient.ts | 24 ++++ 5 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 .auto-claude-security.json create mode 100644 .auto-claude-status create mode 100644 .claude_settings.json diff --git a/.auto-claude-security.json b/.auto-claude-security.json new file mode 100644 index 0000000..eed60a2 --- /dev/null +++ b/.auto-claude-security.json @@ -0,0 +1,227 @@ +{ + "base_commands": [ + ".", + "[", + "[[", + "ag", + "awk", + "basename", + "bash", + "bc", + "break", + "cat", + "cd", + "chmod", + "clear", + "cmp", + "column", + "comm", + "command", + "continue", + "cp", + "curl", + "cut", + "date", + "df", + "diff", + "dig", + "dirname", + "du", + "echo", + "egrep", + "env", + "eval", + "exec", + "exit", + "expand", + "export", + "expr", + "false", + "fd", + "fgrep", + "file", + "find", + "fmt", + "fold", + "gawk", + "gh", + "git", + "grep", + "gunzip", + "gzip", + "head", + "help", + "host", + "iconv", + "id", + "jobs", + "join", + "jq", + "kill", + "killall", + "less", + "let", + "ln", + "ls", + "lsof", + "man", + "mkdir", + "mktemp", + "more", + "mv", + "nl", + "paste", + "pgrep", + "ping", + "pkill", + "popd", + "printenv", + "printf", + "ps", + "pushd", + "pwd", + "read", + "readlink", + "realpath", + "reset", + "return", + "rev", + "rg", + "rm", + "rmdir", + "sed", + "seq", + "set", + "sh", + "shuf", + "sleep", + "sort", + "source", + "split", + "stat", + "tail", + "tar", + "tee", + "test", + "time", + "timeout", + "touch", + "tr", + "tree", + "true", + "type", + "uname", + "unexpand", + "uniq", + "unset", + "unzip", + "watch", + "wc", + "wget", + "whereis", + "which", + "whoami", + "xargs", + "yes", + "yq", + "zip", + "zsh" + ], + "stack_commands": [ + "ar", + "clang", + "clang++", + "cmake", + "composer", + "dive", + "docker", + "docker-buildx", + "docker-compose", + "dockerfile", + "eslint", + "g++", + "gcc", + "ipython", + "jupyter", + "ld", + "make", + "meson", + "next", + "ninja", + "nm", + "node", + "notebook", + "npm", + "npx", + "objdump", + "pdb", + "php", + "pip", + "pip3", + "pipx", + "pnpm", + "pnpx", + "pudb", + "python", + "python3", + "react-scripts", + "strip", + "ts-node", + "tsc", + "tsx", + "vitest" + ], + "script_commands": [ + "bun", + "npm", + "pnpm", + "yarn" + ], + "custom_commands": [], + "detected_stack": { + "languages": [ + "python", + "javascript", + "typescript", + "php", + "c" + ], + "package_managers": [ + "pnpm" + ], + "frameworks": [ + "nextjs", + "react", + "vitest", + "eslint" + ], + "databases": [], + "infrastructure": [ + "docker" + ], + "cloud_providers": [], + "code_quality_tools": [], + "version_managers": [] + }, + "custom_scripts": { + "npm_scripts": [ + "dev", + "build", + "start", + "lint", + "build:images", + "generate:images", + "generate:images:dry", + "test", + "test:coverage" + ], + "make_targets": [], + "poetry_scripts": [], + "cargo_aliases": [], + "shell_scripts": [] + }, + "project_dir": "C:\\Users\\damja\\WebstormProjects\\Portfolio", + "created_at": "2026-01-22T15:28:38.237190", + "project_hash": "c4ad399e16be367eb4e6b076fe1d9ee3", + "inherited_from": "C:\\Users\\damja\\WebstormProjects\\Portfolio" +} \ No newline at end of file diff --git a/.auto-claude-status b/.auto-claude-status new file mode 100644 index 0000000..533d015 --- /dev/null +++ b/.auto-claude-status @@ -0,0 +1,25 @@ +{ + "active": true, + "spec": "018-add-jsdoc-documentation-to-utility-modules-and-cus", + "state": "building", + "subtasks": { + "completed": 10, + "total": 21, + "in_progress": 1, + "failed": 0 + }, + "phase": { + "current": "Document Remaining Utilities", + "id": null, + "total": 5 + }, + "workers": { + "active": 0, + "max": 1 + }, + "session": { + "number": 3, + "started_at": "2026-01-25T11:52:33.491759" + }, + "last_update": "2026-01-25T11:54:37.749955" +} \ No newline at end of file diff --git a/.claude_settings.json b/.claude_settings.json new file mode 100644 index 0000000..ab87f32 --- /dev/null +++ b/.claude_settings.json @@ -0,0 +1,39 @@ +{ + "sandbox": { + "enabled": true, + "autoAllowBashIfSandboxed": true + }, + "permissions": { + "defaultMode": "acceptEdits", + "allow": [ + "Read(./**)", + "Write(./**)", + "Edit(./**)", + "Glob(./**)", + "Grep(./**)", + "Read(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\018-add-jsdoc-documentation-to-utility-modules-and-cus/**)", + "Write(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\018-add-jsdoc-documentation-to-utility-modules-and-cus/**)", + "Edit(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\018-add-jsdoc-documentation-to-utility-modules-and-cus/**)", + "Glob(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\018-add-jsdoc-documentation-to-utility-modules-and-cus/**)", + "Grep(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\018-add-jsdoc-documentation-to-utility-modules-and-cus/**)", + "Read(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\018-add-jsdoc-documentation-to-utility-modules-and-cus\\.auto-claude\\specs\\018-add-jsdoc-documentation-to-utility-modules-and-cus/**)", + "Write(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\018-add-jsdoc-documentation-to-utility-modules-and-cus\\.auto-claude\\specs\\018-add-jsdoc-documentation-to-utility-modules-and-cus/**)", + "Edit(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude\\worktrees\\tasks\\018-add-jsdoc-documentation-to-utility-modules-and-cus\\.auto-claude\\specs\\018-add-jsdoc-documentation-to-utility-modules-and-cus/**)", + "Read(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)", + "Write(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)", + "Edit(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)", + "Glob(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)", + "Grep(C:\\Users\\damja\\WebstormProjects\\Portfolio\\.auto-claude/**)", + "Bash(*)", + "WebFetch(*)", + "WebSearch(*)", + "mcp__context7__resolve-library-id(*)", + "mcp__context7__get-library-docs(*)", + "mcp__graphiti-memory__search_nodes(*)", + "mcp__graphiti-memory__search_facts(*)", + "mcp__graphiti-memory__add_episode(*)", + "mcp__graphiti-memory__get_episodes(*)", + "mcp__graphiti-memory__get_entity_edge(*)" + ] + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index a484ab2..fa65296 100644 --- a/.gitignore +++ b/.gitignore @@ -81,4 +81,7 @@ supabase/.temp/ .history/ # Source images (originals before optimization) -source-images/ \ No newline at end of file +source-images/ + +# Auto Claude data directory +.auto-claude/ diff --git a/src/utils/supabaseClient.ts b/src/utils/supabaseClient.ts index 3e9dcc1..566d67e 100644 --- a/src/utils/supabaseClient.ts +++ b/src/utils/supabaseClient.ts @@ -1,6 +1,30 @@ +/** + * Supabase Client Configuration + * Zentrale Konfiguration für die Supabase-Verbindung + */ + import { createClient } from '@supabase/supabase-js'; const supabaseUrl = 'https://mxadgucxhmstlzsbgmoz.supabase.co'; const supabaseAnonKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im14YWRndWN4aG1zdGx6c2JnbW96Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzkwMDgwNjIsImV4cCI6MjA1NDU4NDA2Mn0.MmFqEm7OfwzOlSegLYl9YWLCmIp8YajzK3Aozubn66Q'; +/** + * Supabase Client Instanz + * + * Vorkonfigurierter Supabase-Client für den Zugriff auf die Datenbank. + * Verwendet die anonyme (anon) Rolle für öffentliche Zugriffe. + * + * @example + * // Daten aus einer Tabelle abrufen + * const { data, error } = await supabase + * .from('table_name') + * .select('*'); + * + * @example + * // Authentifizierung + * const { user, error } = await supabase.auth.signIn({ + * email: 'user@example.com', + * password: 'password' + * }); + */ export const supabase = createClient(supabaseUrl, supabaseAnonKey); \ No newline at end of file From 09b31fd7c163c178b1cd99e0f172f07d33b8926d Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 11:57:04 +0100 Subject: [PATCH 12/21] auto-claude: subtask-3-5 - Add JSDoc to webVitals.ts --- src/utils/webVitals.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/utils/webVitals.ts b/src/utils/webVitals.ts index 8fb3ba1..8de9a4c 100644 --- a/src/utils/webVitals.ts +++ b/src/utils/webVitals.ts @@ -1,5 +1,13 @@ +/** + * Web Vitals Reporting Service + * Tracks and reports Core Web Vitals metrics to Google Analytics + */ + import { onCLS, onINP, onLCP, onFCP, onTTFB } from 'web-vitals'; +/** + * Web Vitals metric data structure + */ interface Metric { name: string; value: number; @@ -8,6 +16,9 @@ interface Metric { id: string; } +/** + * Send Web Vitals metric to Google Analytics and dispatch custom event + */ function sendToAnalytics(metric: Metric) { const body = JSON.stringify({ name: metric.name, @@ -45,6 +56,9 @@ function sendToAnalytics(metric: Metric) { // } } +/** + * Initialize Web Vitals reporting for all Core Web Vitals metrics + */ export function reportWebVitals() { onCLS(sendToAnalytics); onINP(sendToAnalytics); @@ -53,7 +67,9 @@ export function reportWebVitals() { onTTFB(sendToAnalytics); } -// Helper function to get Web Vitals score +/** + * Calculate Web Vitals rating based on metric thresholds + */ export function getWebVitalsScore(metric: Metric): string { const thresholds = { LCP: { good: 2500, poor: 4000 }, From 6558e9ae798e76b359aaa80c656f4d0d6e2296e8 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 11:58:32 +0100 Subject: [PATCH 13/21] auto-claude: subtask-4-1 - Add JSDoc to useAsync.ts hook --- src/hooks/useAsync.ts | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/hooks/useAsync.ts b/src/hooks/useAsync.ts index 23499ef..73f0d0c 100644 --- a/src/hooks/useAsync.ts +++ b/src/hooks/useAsync.ts @@ -1,12 +1,44 @@ +/** + * Custom Hook for Async Operations + * Provides a reusable pattern for handling asynchronous operations with loading, error, and data states + */ + import { useState, useCallback } from 'react'; import { handleError } from '../utils/errorHandling'; +/** + * State interface for async operations + * @template T - The type of data returned by the async operation + */ interface AsyncState { + /** The data returned from the async operation, null if not yet loaded or error occurred */ data: T | null; + /** Error object if the operation failed, null otherwise */ error: Error | null; + /** Loading state indicator, true while operation is in progress */ loading: boolean; } +/** + * Custom hook for managing asynchronous operations + * Handles loading states, error handling, and data management for async functions + * + * @template T - The type of data returned by the async operation + * @returns Object containing: + * - data: The result of the async operation or null + * - error: Any error that occurred or null + * - loading: Boolean indicating if operation is in progress + * - execute: Function to trigger the async operation + * + * @example + * ```tsx + * const { data, error, loading, execute } = useAsync(); + * + * useEffect(() => { + * execute(() => fetchUser(userId)); + * }, [userId]); + * ``` + */ export function useAsync() { const [state, setState] = useState>({ data: null, From 0a69a9bfbf12cb30645c562658e41bb510062a57 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 11:59:48 +0100 Subject: [PATCH 14/21] auto-claude: subtask-4-2 - Add JSDoc to useOnClickOutside.ts hook --- src/hooks/useOnClickOutside.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/hooks/useOnClickOutside.ts b/src/hooks/useOnClickOutside.ts index dbd277b..555a81d 100644 --- a/src/hooks/useOnClickOutside.ts +++ b/src/hooks/useOnClickOutside.ts @@ -1,5 +1,21 @@ +/** + * Click Outside Detection Hook + * Detects clicks outside of a referenced element and triggers a handler + */ + import { RefObject, useEffect } from 'react'; +/** + * Hook that triggers a handler when user clicks outside the referenced element + * Useful for closing dropdowns, modals, or menus when clicking outside + * + * @param ref - React ref object pointing to the element to monitor + * @param handler - Callback function to execute when click occurs outside the element + * + * @example + * const menuRef = useRef(null); + * useOnClickOutside(menuRef, () => setMenuOpen(false)); + */ export function useOnClickOutside(ref: RefObject, handler: (event: MouseEvent | TouchEvent) => void) { useEffect(() => { const listener = (event: MouseEvent | TouchEvent) => { From a4f7db006ecdd04d3b94b00e58ab28458d751592 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 12:00:57 +0100 Subject: [PATCH 15/21] auto-claude: subtask-4-3 - Add JSDoc to useProjectData.ts hook --- src/hooks/useProjectData.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/hooks/useProjectData.ts b/src/hooks/useProjectData.ts index f1849ef..3bb704e 100644 --- a/src/hooks/useProjectData.ts +++ b/src/hooks/useProjectData.ts @@ -1,7 +1,18 @@ -// src/hooks/useProjectData.ts +/** + * Project Data Hook + * Custom hook for dynamically loading project data based on current language + */ + import { useTranslation } from 'react-i18next'; import { useState, useEffect } from 'react'; +/** + * Loads project data dynamically based on project ID and current language + * + * @template T - The type of the project data object + * @param {string} projectId - The unique identifier of the project + * @returns {T | null} The project data object or null if loading fails + */ export const useProjectData = (projectId: string): T | null => { const { i18n } = useTranslation(); const [projectData, setProjectData] = useState(null); From 7d17d8e262657818fc16fea3d1d821d45d807933 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 12:02:08 +0100 Subject: [PATCH 16/21] auto-claude: subtask-4-4 - Add JSDoc to useScrollLock.ts hook --- src/hooks/useScrollLock.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/hooks/useScrollLock.ts b/src/hooks/useScrollLock.ts index d790af5..4ff48ca 100644 --- a/src/hooks/useScrollLock.ts +++ b/src/hooks/useScrollLock.ts @@ -1,8 +1,18 @@ +/** + * Scroll Lock Hook + * Manages body scroll locking based on state and navigation transitions + */ + // hooks/useScrollLock.ts import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; import { useScrollContext } from '../components/ScrollContext'; +/** + * Custom hook to lock/unlock page scrolling + * Automatically handles scroll restoration on route changes and cleanup on unmount + * @param lock - Whether to lock the page scroll + */ export const useScrollLock = (lock: boolean) => { const location = useLocation(); const { isTransitioning, lockScroll, unlockScroll } = useScrollContext(); From 6a910b211a7ab312043cce968e02bc04d8c3ec8d Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 12:03:24 +0100 Subject: [PATCH 17/21] auto-claude: subtask-4-5 - Add JSDoc to useScrollTracking.ts hook --- src/hooks/useScrollTracking.ts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/hooks/useScrollTracking.ts b/src/hooks/useScrollTracking.ts index 8eebbc7..d024bba 100644 --- a/src/hooks/useScrollTracking.ts +++ b/src/hooks/useScrollTracking.ts @@ -1,8 +1,37 @@ +/** + * Scroll Tracking Hook + * Tracks user scroll depth and sends events to Google Tag Manager + */ + import { useEffect, useRef } from 'react'; import { trackScrollDepth } from '../services/gtm'; /** - * Hook to track scroll depth for GTM + * Custom hook to track scroll depth for GTM analytics + * + * Monitors user scroll behavior and triggers GTM events when the user reaches + * specific depth milestones (25%, 50%, 75%, 90%, 100%). Each milestone is + * tracked only once per page visit to avoid duplicate events. + * + * Features: + * - Debounced scroll event handling (100ms) for performance + * - Tracks depth milestones: 25%, 50%, 75%, 90%, 100% + * - Prevents duplicate tracking of the same milestone + * - Automatically resets tracking state on route changes + * - Checks initial scroll position on mount + * + * @example + * ```tsx + * function MyPage() { + * useScrollTracking(); + * return
...
; + * } + * ``` + * + * @remarks + * This hook should be used at the page/route level component to ensure + * accurate tracking across navigation. The tracking state is automatically + * reset when the URL pathname changes. */ export const useScrollTracking = () => { const trackedDepths = useRef(new Set()); From 889fbb410dc6e39a37041247418b146260cda029 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 12:05:28 +0100 Subject: [PATCH 18/21] auto-claude: subtask-5-1 - Add JSDoc to blog.ts --- src/lib/blog.ts | 52 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/lib/blog.ts b/src/lib/blog.ts index 567ae70..15bb6e2 100644 --- a/src/lib/blog.ts +++ b/src/lib/blog.ts @@ -1,20 +1,41 @@ +/** + * Blog Post Management Service + * Zentrale Verwaltung aller Blog-Beiträge mit automatischer Kategorie-Erkennung + */ + import fs from 'fs'; import path from 'path'; +/** + * Blog Post Interface + * Definiert die Struktur eines Blog-Beitrags + */ export interface BlogPost { + /** URL-freundlicher Slug */ slug: string; + /** Titel des Beitrags */ title: string; + /** Veröffentlichungsdatum (ISO 8601) */ date: string; + /** Kurze Zusammenfassung */ excerpt: string; + /** Pfad zum Cover-Bild */ coverImage: string; + /** Kategorie des Beitrags */ category?: string; + /** Schlagwörter/Tags */ tags?: string[]; + /** Vollständiger Markdown-Inhalt */ content?: string; } +// Verzeichnis der Blog-Beiträge const BLOG_POSTS_DIR = path.join(process.cwd(), 'blog-posts'); -// Category mapping based on filename patterns +/** + * Kategorie-Mapping basierend auf Dateinamen- und Inhaltsmustern + * Ordnet Keywords automatisch passenden Kategorien zu + */ const categoryMap: Record = { 'agentic': 'KI-Agenten', 'ai-agent': 'KI-Agenten', @@ -58,6 +79,13 @@ const categoryMap: Record = { 'home-assistant': 'Smart Home', }; +/** + * Erkennt automatisch die Kategorie eines Blog-Posts + * Analysiert Dateiname und Inhalt auf Keywords + * @param filename - Dateiname des Blog-Posts + * @param content - Inhalt des Blog-Posts + * @returns Die erkannte Kategorie oder 'Technologie' als Fallback + */ function detectCategory(filename: string, content: string): string { const lowerFilename = filename.toLowerCase(); const lowerContent = content.toLowerCase().slice(0, 500); @@ -70,6 +98,13 @@ function detectCategory(filename: string, content: string): string { return 'Technologie'; } +/** + * Parst einen Markdown-Blog-Post und extrahiert alle Metadaten + * Extrahiert Titel, Meta-Description, Keywords, Kategorie und generiert Slug + * @param filename - Dateiname des Markdown-Posts + * @param content - Vollständiger Markdown-Inhalt + * @returns BlogPost-Objekt oder null bei Fehler + */ function parseMarkdownPost(filename: string, content: string): BlogPost | null { try { // Extract title from first H1 @@ -129,6 +164,11 @@ function parseMarkdownPost(filename: string, content: string): BlogPost | null { } } +/** + * Lädt alle Blog-Posts aus dem Dateisystem + * Posts werden nach Datum absteigend sortiert (neueste zuerst) + * @returns Array aller Blog-Posts + */ export function getAllBlogPosts(): BlogPost[] { if (!fs.existsSync(BLOG_POSTS_DIR)) { console.warn('Blog posts directory not found:', BLOG_POSTS_DIR); @@ -154,11 +194,21 @@ export function getAllBlogPosts(): BlogPost[] { return posts.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); } +/** + * Sucht einen Blog-Post anhand seines Slugs + * @param slug - Der URL-Slug des gesuchten Posts + * @returns Der gefundene Blog-Post oder null + */ export function getBlogPostBySlug(slug: string): BlogPost | null { const posts = getAllBlogPosts(); return posts.find(post => post.slug === slug) || null; } +/** + * Gibt alle verfügbaren Blog-Post Slugs zurück + * Nützlich für statische Seitengenerierung + * @returns Array aller Post-Slugs + */ export function getBlogPostSlugs(): string[] { return getAllBlogPosts().map(post => post.slug); } From 54caa12821010343ff0033a46ceaab685d2bbc6f Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 12:06:50 +0100 Subject: [PATCH 19/21] auto-claude: subtask-5-2 - Add JSDoc to markdown.tsx --- src/lib/markdown.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/lib/markdown.tsx b/src/lib/markdown.tsx index 1ddde9d..1ff8f5c 100644 --- a/src/lib/markdown.tsx +++ b/src/lib/markdown.tsx @@ -1,5 +1,14 @@ +/** + * Markdown Rendering Utility + * Converts markdown text to styled React components + */ + import React from 'react'; +/** + * Parse inline markdown syntax (code, bold, italic, links) + * Converts inline markdown elements within a text string to React components + */ function parseInlineMarkdown(text: string): React.ReactNode { const parts: React.ReactNode[] = []; let remaining = text; @@ -63,6 +72,10 @@ function parseInlineMarkdown(text: string): React.ReactNode { return parts.length === 1 ? parts[0] : <>{parts}; } +/** + * Render markdown content to React components + * Supports headers, lists, code blocks, tables, blockquotes, and inline formatting + */ export function renderMarkdown(content: string): React.ReactNode { const lines = content.split('\n'); const elements: React.ReactNode[] = []; From c23bcafacb92cc66a784985011293b7e04d93d3e Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 12:07:50 +0100 Subject: [PATCH 20/21] auto-claude: subtask-5-3 - Add JSDoc to supabase/client.ts --- .auto-claude-status | 10 +++++----- src/lib/supabase/client.ts | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.auto-claude-status b/.auto-claude-status index 533d015..9bf3e11 100644 --- a/.auto-claude-status +++ b/.auto-claude-status @@ -3,23 +3,23 @@ "spec": "018-add-jsdoc-documentation-to-utility-modules-and-cus", "state": "building", "subtasks": { - "completed": 10, + "completed": 19, "total": 21, "in_progress": 1, "failed": 0 }, "phase": { - "current": "Document Remaining Utilities", + "current": "Document Library Modules", "id": null, - "total": 5 + "total": 4 }, "workers": { "active": 0, "max": 1 }, "session": { - "number": 3, + "number": 12, "started_at": "2026-01-25T11:52:33.491759" }, - "last_update": "2026-01-25T11:54:37.749955" + "last_update": "2026-01-25T12:07:15.359150" } \ No newline at end of file diff --git a/src/lib/supabase/client.ts b/src/lib/supabase/client.ts index e6db2a1..71be730 100644 --- a/src/lib/supabase/client.ts +++ b/src/lib/supabase/client.ts @@ -1,5 +1,14 @@ +/** + * Supabase Browser Client + * Client-side Supabase client for authentication and database access + */ + import { createBrowserClient } from '@supabase/ssr'; +/** + * Creates a Supabase browser client instance + * @returns Supabase client configured with environment variables + */ export function createClient() { return createBrowserClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, From 409a3d8d54d327722ccd5b6654477ced73b44e1b Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 12:09:02 +0100 Subject: [PATCH 21/21] auto-claude: subtask-5-4 - Add JSDoc to supabase/server.ts --- src/lib/supabase/server.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lib/supabase/server.ts b/src/lib/supabase/server.ts index 7c29af0..6e300f9 100644 --- a/src/lib/supabase/server.ts +++ b/src/lib/supabase/server.ts @@ -1,6 +1,17 @@ +/** + * Supabase Server Client Utility + * Creates server-side Supabase clients with cookie handling for SSR + */ + import { createServerClient } from '@supabase/ssr'; import { cookies } from 'next/headers'; +/** + * Creates a Supabase client for server-side usage + * Handles cookie management for authentication in Next.js server components + * + * @returns {Promise} Supabase server client instance + */ export async function createClient() { const cookieStore = await cookies();