Index: backend/supabase/functions/leaderboard/index.ts
===================================================================
--- backend/supabase/functions/leaderboard/index.ts	(revision e196291edd024fc4223db37151fdedc30846a384)
+++ backend/supabase/functions/leaderboard/index.ts	(revision ed03d445085c472b13707490fa74805ebb81cb54)
@@ -1,15 +1,15 @@
 // Supabase Edge Function - leaderboard.ts
-import { serve } from "https://deno.land/std/http/server.ts";
-import { createClient } from "https://esm.sh/@supabase/supabase-js";
+import { serve } from 'https://deno.land/std/http/server.ts';
+import { createClient } from 'https://esm.sh/@supabase/supabase-js';
 
-// Cache structure and constants
+// Cache constants
+const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
+const PAGE_SIZE = 20;
+
+// Type for stored data
 type CacheEntry = {
   data: any;
   timestamp: number;
 };
-
-const cachedPages = new Map<string, CacheEntry>();
-const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
-const PAGE_SIZE = 20;
 
 serve(async (req: Request): Promise<Response> => {
@@ -29,39 +29,52 @@
     const url = new URL(req.url);
     const page = parseInt(url.searchParams.get('page') || '1');
-    const limit = parseInt(url.searchParams.get('limit') || PAGE_SIZE.toString());
+    const limit = parseInt(
+      url.searchParams.get('limit') || PAGE_SIZE.toString()
+    );
 
     if (page < 1 || limit < 1 || limit > 100) {
-      return new Response(JSON.stringify({
-        error: 'Invalid parameters',
-        message: 'Page must be >= 1 and limit must be between 1 and 100'
-      }), {
-        status: 400,
-        headers: {
-          'Content-Type': 'application/json',
-          'Access-Control-Allow-Origin': '*',
-        },
-      });
+      return new Response(
+        JSON.stringify({
+          error: 'Invalid parameters',
+          message: 'Page must be >= 1 and limit must be between 1 and 100',
+        }),
+        {
+          status: 400,
+          headers: {
+            'Content-Type': 'application/json',
+            'Access-Control-Allow-Origin': '*',
+          },
+        }
+      );
     }
 
     const now = Date.now();
-    const cacheKey = `${page}-${limit}`;
+    const cacheKey = `leaderboard:${page}-${limit}`;
 
-    // Check cache
-    if (cachedPages.has(cacheKey)) {
-      const cached = cachedPages.get(cacheKey)!;
-      if (now - cached.timestamp < CACHE_DURATION) {
-        return new Response(JSON.stringify({ ...cached.data, cached: true }), {
+    // Open KV store
+    const kv = await Deno.openKv();
+
+    // Check cache in KV
+    const cacheResult = await kv.get<CacheEntry>([cacheKey]);
+
+    // If we have a valid cache entry, return it
+    if (
+      cacheResult.value &&
+      now - cacheResult.value.timestamp < CACHE_DURATION
+    ) {
+      return new Response(
+        JSON.stringify({ ...cacheResult.value.data, cached: true }),
+        {
           status: 200,
           headers: {
             'Content-Type': 'application/json',
             'Access-Control-Allow-Origin': '*',
+            'Cache-Control': 'max-age=300', // Allow browser caching for 5 minutes
           },
-        });
-      } else {
-        cachedPages.delete(cacheKey);
-      }
+        }
+      );
     }
 
-    // Load env variables - FIXED
+    // Load env variables
     const supabaseUrl = Deno.env.get('SUPABASE_URL');
     const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY');
@@ -99,18 +112,19 @@
         hasPreviousPage,
         nextPage: hasNextPage ? page + 1 : null,
-        previousPage: hasPreviousPage ? page - 1 : null
+        previousPage: hasPreviousPage ? page - 1 : null,
       },
       timestamp: now,
-      cached: false
+      cached: false,
     };
 
-    // Store in cache
-    cachedPages.set(cacheKey, { data: responseData, timestamp: now });
-
-    // Limit memory usage
-    if (cachedPages.size > 10) {
-      const oldestKey = cachedPages.keys().next().value;
-      cachedPages.delete(oldestKey);
-    }
+    // Store in KV with automatic expiration
+    // This is cleaner than manual deletion as KV handles expiration for us
+    await kv.set(
+      [cacheKey],
+      { data: responseData, timestamp: now },
+      {
+        expireIn: CACHE_DURATION,
+      }
+    );
 
     return new Response(JSON.stringify(responseData), {
@@ -119,20 +133,22 @@
         'Content-Type': 'application/json',
         'Access-Control-Allow-Origin': '*',
+        'Cache-Control': 'max-age=300', // Allow browser caching
       },
     });
-
   } catch (err: any) {
     console.error('Leaderboard error:', err.message);
-    return new Response(JSON.stringify({
-      error: 'Failed to fetch leaderboard',
-      message: err.message
-    }), {
-      status: 500,
-      headers: {
-        'Content-Type': 'application/json',
-        'Access-Control-Allow-Origin': '*',
-      },
-    });
+    return new Response(
+      JSON.stringify({
+        error: 'Failed to fetch leaderboard',
+        message: err.message,
+      }),
+      {
+        status: 500,
+        headers: {
+          'Content-Type': 'application/json',
+          'Access-Control-Allow-Origin': '*',
+        },
+      }
+    );
   }
 });
-
Index: client/package-lock.json
===================================================================
--- client/package-lock.json	(revision e196291edd024fc4223db37151fdedc30846a384)
+++ client/package-lock.json	(revision ed03d445085c472b13707490fa74805ebb81cb54)
@@ -9,4 +9,5 @@
       "version": "0.0.0",
       "dependencies": {
+        "@supabase/supabase-js": "^2.50.0",
         "@tailwindcss/vite": "^4.1.4",
         "class-variance-authority": "^0.7.1",
@@ -16,4 +17,5 @@
         "react-dom": "^19.0.0",
         "react-router-dom": "^7.5.3",
+        "supabase": "^2.24.3",
         "tailwind-merge": "^3.2.0",
         "tailwindcss": "^4.1.4"
@@ -945,4 +947,16 @@
       }
     },
+    "node_modules/@isaacs/fs-minipass": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+      "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+      "license": "ISC",
+      "dependencies": {
+        "minipass": "^7.0.4"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
     "node_modules/@jridgewell/gen-mapping": {
       "version": "0.3.8",
@@ -1257,4 +1271,78 @@
         "win32"
       ]
+    },
+    "node_modules/@supabase/auth-js": {
+      "version": "2.70.0",
+      "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.70.0.tgz",
+      "integrity": "sha512-BaAK/tOAZFJtzF1sE3gJ2FwTjLf4ky3PSvcvLGEgEmO4BSBkwWKu8l67rLLIBZPDnCyV7Owk2uPyKHa0kj5QGg==",
+      "license": "MIT",
+      "dependencies": {
+        "@supabase/node-fetch": "^2.6.14"
+      }
+    },
+    "node_modules/@supabase/functions-js": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.4.4.tgz",
+      "integrity": "sha512-WL2p6r4AXNGwop7iwvul2BvOtuJ1YQy8EbOd0dhG1oN1q8el/BIRSFCFnWAMM/vJJlHWLi4ad22sKbKr9mvjoA==",
+      "license": "MIT",
+      "dependencies": {
+        "@supabase/node-fetch": "^2.6.14"
+      }
+    },
+    "node_modules/@supabase/node-fetch": {
+      "version": "2.6.15",
+      "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz",
+      "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==",
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      }
+    },
+    "node_modules/@supabase/postgrest-js": {
+      "version": "1.19.4",
+      "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.19.4.tgz",
+      "integrity": "sha512-O4soKqKtZIW3olqmbXXbKugUtByD2jPa8kL2m2c1oozAO11uCcGrRhkZL0kVxjBLrXHE0mdSkFsMj7jDSfyNpw==",
+      "license": "MIT",
+      "dependencies": {
+        "@supabase/node-fetch": "^2.6.14"
+      }
+    },
+    "node_modules/@supabase/realtime-js": {
+      "version": "2.11.10",
+      "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.11.10.tgz",
+      "integrity": "sha512-SJKVa7EejnuyfImrbzx+HaD9i6T784khuw1zP+MBD7BmJYChegGxYigPzkKX8CK8nGuDntmeSD3fvriaH0EGZA==",
+      "license": "MIT",
+      "dependencies": {
+        "@supabase/node-fetch": "^2.6.13",
+        "@types/phoenix": "^1.6.6",
+        "@types/ws": "^8.18.1",
+        "ws": "^8.18.2"
+      }
+    },
+    "node_modules/@supabase/storage-js": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.7.1.tgz",
+      "integrity": "sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==",
+      "license": "MIT",
+      "dependencies": {
+        "@supabase/node-fetch": "^2.6.14"
+      }
+    },
+    "node_modules/@supabase/supabase-js": {
+      "version": "2.50.0",
+      "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.50.0.tgz",
+      "integrity": "sha512-M1Gd5tPaaghYZ9OjeO1iORRqbTWFEz/cF3pPubRnMPzA+A8SiUsXXWDP+DWsASZcjEcVEcVQIAF38i5wrijYOg==",
+      "license": "MIT",
+      "dependencies": {
+        "@supabase/auth-js": "2.70.0",
+        "@supabase/functions-js": "2.4.4",
+        "@supabase/node-fetch": "2.6.15",
+        "@supabase/postgrest-js": "1.19.4",
+        "@supabase/realtime-js": "2.11.10",
+        "@supabase/storage-js": "2.7.1"
+      }
     },
     "node_modules/@tailwindcss/node": {
@@ -1570,4 +1658,19 @@
       "license": "MIT"
     },
+    "node_modules/@types/node": {
+      "version": "22.15.30",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.30.tgz",
+      "integrity": "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~6.21.0"
+      }
+    },
+    "node_modules/@types/phoenix": {
+      "version": "1.6.6",
+      "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz",
+      "integrity": "sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==",
+      "license": "MIT"
+    },
     "node_modules/@types/react": {
       "version": "19.1.2",
@@ -1588,4 +1691,13 @@
       "peerDependencies": {
         "@types/react": "^19.0.0"
+      }
+    },
+    "node_modules/@types/ws": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
+      "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
       }
     },
@@ -1633,4 +1745,13 @@
       }
     },
+    "node_modules/agent-base": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+      "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
     "node_modules/ajv": {
       "version": "6.12.6",
@@ -1679,4 +1800,20 @@
       "dev": true,
       "license": "MIT"
+    },
+    "node_modules/bin-links": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-5.0.0.tgz",
+      "integrity": "sha512-sdleLVfCjBtgO5cNjA2HVRvWBJAHs4zwenaCPMNJAJU0yNxpzj80IpjOIimkpkr+mhlA+how5poQtt53PygbHA==",
+      "license": "ISC",
+      "dependencies": {
+        "cmd-shim": "^7.0.0",
+        "npm-normalize-package-bin": "^4.0.0",
+        "proc-log": "^5.0.0",
+        "read-cmd-shim": "^5.0.0",
+        "write-file-atomic": "^6.0.0"
+      },
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
     },
     "node_modules/brace-expansion": {
@@ -1772,4 +1909,13 @@
       }
     },
+    "node_modules/chownr": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+      "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/class-variance-authority": {
       "version": "0.7.1",
@@ -1793,4 +1939,13 @@
       }
     },
+    "node_modules/cmd-shim": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-7.0.0.tgz",
+      "integrity": "sha512-rtpaCbr164TPPh+zFdkWpCyZuKkjpAzODfaZCf/SVJZzJN+4bHQb/LP3Jzq5/+84um3XXY8r548XiWKSborwVw==",
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
     "node_modules/color-convert": {
       "version": "2.0.1",
@@ -1868,9 +2023,17 @@
       }
     },
+    "node_modules/data-uri-to-buffer": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+      "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
     "node_modules/debug": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
       "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -2198,4 +2361,27 @@
       }
     },
+    "node_modules/fetch-blob": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+      "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/jimmywarting"
+        },
+        {
+          "type": "paypal",
+          "url": "https://paypal.me/jimmywarting"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "node-domexception": "^1.0.0",
+        "web-streams-polyfill": "^3.0.3"
+      },
+      "engines": {
+        "node": "^12.20 || >= 14.13"
+      }
+    },
     "node_modules/file-entry-cache": {
       "version": "8.0.0",
@@ -2248,4 +2434,16 @@
       "dev": true,
       "license": "ISC"
+    },
+    "node_modules/formdata-polyfill": {
+      "version": "4.0.10",
+      "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+      "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+      "license": "MIT",
+      "dependencies": {
+        "fetch-blob": "^3.1.2"
+      },
+      "engines": {
+        "node": ">=12.20.0"
+      }
     },
     "node_modules/fsevents": {
@@ -2315,4 +2513,17 @@
       }
     },
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+      "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
     "node_modules/ignore": {
       "version": "5.3.2",
@@ -2346,5 +2557,4 @@
       "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
       "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
-      "dev": true,
       "license": "MIT",
       "engines": {
@@ -2765,9 +2975,44 @@
       }
     },
+    "node_modules/minipass": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/minizlib": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
+      "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
+      "license": "MIT",
+      "dependencies": {
+        "minipass": "^7.1.2"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+      "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+      "license": "MIT",
+      "bin": {
+        "mkdirp": "dist/cjs/src/bin.js"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-      "dev": true,
       "license": "MIT"
     },
@@ -2797,4 +3042,42 @@
       "license": "MIT"
     },
+    "node_modules/node-domexception": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+      "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+      "deprecated": "Use your platform's native DOMException instead",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/jimmywarting"
+        },
+        {
+          "type": "github",
+          "url": "https://paypal.me/jimmywarting"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.5.0"
+      }
+    },
+    "node_modules/node-fetch": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
+      "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
+      "license": "MIT",
+      "dependencies": {
+        "data-uri-to-buffer": "^4.0.0",
+        "fetch-blob": "^3.1.4",
+        "formdata-polyfill": "^4.0.10"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/node-fetch"
+      }
+    },
     "node_modules/node-releases": {
       "version": "2.0.19",
@@ -2803,4 +3086,13 @@
       "dev": true,
       "license": "MIT"
+    },
+    "node_modules/npm-normalize-package-bin": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz",
+      "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==",
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
     },
     "node_modules/optionator": {
@@ -2943,4 +3235,13 @@
       }
     },
+    "node_modules/proc-log": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz",
+      "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==",
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
     "node_modules/punycode": {
       "version": "2.3.1",
@@ -3021,4 +3322,13 @@
         "react": ">=18",
         "react-dom": ">=18"
+      }
+    },
+    "node_modules/read-cmd-shim": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-5.0.0.tgz",
+      "integrity": "sha512-SEbJV7tohp3DAAILbEMPXavBjAnMN0tVnh4+9G8ihV4Pq3HYF9h8QNez9zkJ1ILkv9G2BjdzwctznGZXgu/HGw==",
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
       }
     },
@@ -3117,4 +3427,16 @@
       }
     },
+    "node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
     "node_modules/source-map-js": {
       "version": "1.2.1",
@@ -3139,4 +3461,23 @@
       }
     },
+    "node_modules/supabase": {
+      "version": "2.24.3",
+      "resolved": "https://registry.npmjs.org/supabase/-/supabase-2.24.3.tgz",
+      "integrity": "sha512-mh9pi4C5pM159GyYE+Rv9qL8kg1kqzimQ4FBr6UH/WhzB/VcDaA+vpn/VeRC3CGVKr+d89Ra5MjDWg+/UoPpXg==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "bin-links": "^5.0.0",
+        "https-proxy-agent": "^7.0.2",
+        "node-fetch": "^3.3.2",
+        "tar": "7.4.3"
+      },
+      "bin": {
+        "supabase": "bin/supabase"
+      },
+      "engines": {
+        "npm": ">=8"
+      }
+    },
     "node_modules/supports-color": {
       "version": "7.2.0",
@@ -3177,4 +3518,30 @@
       }
     },
+    "node_modules/tar": {
+      "version": "7.4.3",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
+      "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
+      "license": "ISC",
+      "dependencies": {
+        "@isaacs/fs-minipass": "^4.0.0",
+        "chownr": "^3.0.0",
+        "minipass": "^7.1.2",
+        "minizlib": "^3.0.1",
+        "mkdirp": "^3.0.1",
+        "yallist": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tar/node_modules/yallist": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+      "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/tinyglobby": {
       "version": "0.2.13",
@@ -3192,4 +3559,10 @@
         "url": "https://github.com/sponsors/SuperchupuDev"
       }
+    },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+      "license": "MIT"
     },
     "node_modules/turbo-stream": {
@@ -3211,4 +3584,10 @@
         "node": ">= 0.8.0"
       }
+    },
+    "node_modules/undici-types": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+      "license": "MIT"
     },
     "node_modules/update-browserslist-db": {
@@ -3327,4 +3706,29 @@
       }
     },
+    "node_modules/web-streams-polyfill": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
+      "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
     "node_modules/which": {
       "version": "2.0.2",
@@ -3353,4 +3757,38 @@
       }
     },
+    "node_modules/write-file-atomic": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-6.0.0.tgz",
+      "integrity": "sha512-GmqrO8WJ1NuzJ2DrziEI2o57jKAVIQNf8a18W3nCYU3H7PNWqCCVTeH6/NQE93CIllIgQS98rrmVkYgTX9fFJQ==",
+      "license": "ISC",
+      "dependencies": {
+        "imurmurhash": "^0.1.4",
+        "signal-exit": "^4.0.1"
+      },
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/ws": {
+      "version": "8.18.2",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
+      "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/yallist": {
       "version": "3.1.1",
Index: client/package.json
===================================================================
--- client/package.json	(revision e196291edd024fc4223db37151fdedc30846a384)
+++ client/package.json	(revision ed03d445085c472b13707490fa74805ebb81cb54)
@@ -12,4 +12,5 @@
   },
   "dependencies": {
+    "@supabase/supabase-js": "^2.50.0",
     "@tailwindcss/vite": "^4.1.4",
     "class-variance-authority": "^0.7.1",
@@ -19,4 +20,5 @@
     "react-dom": "^19.0.0",
     "react-router-dom": "^7.5.3",
+    "supabase": "^2.24.3",
     "tailwind-merge": "^3.2.0",
     "tailwindcss": "^4.1.4"
Index: client/src/LogIn/LogIn.jsx
===================================================================
--- client/src/LogIn/LogIn.jsx	(revision e196291edd024fc4223db37151fdedc30846a384)
+++ client/src/LogIn/LogIn.jsx	(revision ed03d445085c472b13707490fa74805ebb81cb54)
@@ -1,5 +1,5 @@
 import React, { useState } from 'react';
 import { Link, useNavigate } from 'react-router-dom';
-
+import { supabase } from '../contexts/AuthContext';
 const Login = () => {
   const [email, setEmail] = useState('');
@@ -25,5 +25,16 @@
       if (data.success) {
         console.log(data);
+
+        // Store user in localStorage
         localStorage.setItem('user', JSON.stringify(data.user));
+
+        // Also sign in with the Supabase client
+        // This is needed to update the AuthContext
+        await supabase.auth.signInWithPassword({
+          email,
+          password,
+        });
+
+        // Now navigate - the AuthContext will pick up the session change
         navigate('/dashboard');
       } else {
Index: client/src/contexts/AuthContext.jsx
===================================================================
--- client/src/contexts/AuthContext.jsx	(revision ed03d445085c472b13707490fa74805ebb81cb54)
+++ client/src/contexts/AuthContext.jsx	(revision ed03d445085c472b13707490fa74805ebb81cb54)
@@ -0,0 +1,149 @@
+import { createContext, useContext, useState, useEffect, useRef } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { createClient } from '@supabase/supabase-js';
+import { useCallback } from 'react';
+
+const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
+const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
+
+export const supabase = createClient(supabaseUrl, supabaseAnonKey);
+
+// Create the context
+export const AuthContext = createContext();
+
+// Custom hook to use the auth context
+export const useAuth = () => useContext(AuthContext);
+
+// Provider component
+export const AuthProvider = ({ children }) => {
+  const [user, setUser] = useState(null);
+  const [loading, setLoading] = useState(true);
+  const inactivityTimeoutRef = useRef(null); // Use ref instead of state
+  const navigate = useNavigate();
+
+  // Inactivity duration in milliseconds (30 minutes)
+  const INACTIVITY_TIMEOUT = 30 * 60 * 1000;
+
+  // Function to handle logout - use useCallback to prevent recreation on every render
+  const logout = useCallback(async () => {
+    try {
+      await supabase.auth.signOut();
+      localStorage.removeItem('user');
+      sessionStorage.clear();
+      setUser(null);
+      navigate('/login?reason=inactivity');
+    } catch (error) {
+      console.error('Error during logout:', error);
+    }
+  }, [navigate]);
+
+  // Function to reset the inactivity timer - use useCallback
+  const resetInactivityTimer = useCallback(() => {
+    if (inactivityTimeoutRef.current) {
+      clearTimeout(inactivityTimeoutRef.current);
+    }
+
+    // Only set timer if user is logged in
+    if (user) {
+      inactivityTimeoutRef.current = setTimeout(() => {
+        console.log('User inactive for too long, logging out...');
+        logout();
+      }, INACTIVITY_TIMEOUT);
+    }
+  }, [logout, INACTIVITY_TIMEOUT, user]);
+
+  // Set up event listeners for user activity
+  useEffect(() => {
+    const activityEvents = [
+      'mousedown',
+      'mousemove',
+      'keypress',
+      'scroll',
+      'touchstart',
+    ];
+
+    const handleActivity = () => {
+      if (user) {
+        // Only reset if there's a user
+        resetInactivityTimer();
+      }
+    };
+
+    // Add event listeners
+    activityEvents.forEach((event) => {
+      document.addEventListener(event, handleActivity, { passive: true });
+    });
+
+    // Initial timer setup if user exists
+    if (user) {
+      resetInactivityTimer();
+    }
+
+    // Cleanup
+    return () => {
+      if (inactivityTimeoutRef.current) {
+        clearTimeout(inactivityTimeoutRef.current);
+      }
+
+      activityEvents.forEach((event) => {
+        document.removeEventListener(event, handleActivity);
+      });
+    };
+  }, [resetInactivityTimer, user]); // Depend on both resetInactivityTimer and user
+
+  // Initialize user state from Supabase session
+  useEffect(() => {
+    const initializeAuth = async () => {
+      try {
+        const { data } = await supabase.auth.getSession();
+
+        if (data?.session?.user) {
+          setUser(data.session.user);
+        } else {
+          // If no Supabase session, check localStorage
+          const storedUser = localStorage.getItem('user');
+          if (storedUser) {
+            setUser(JSON.parse(storedUser));
+          }
+        }
+      } catch (error) {
+        console.error('Error retrieving session:', error);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    initializeAuth();
+
+    // Listen for auth changes
+    const { data: authListener } = supabase.auth.onAuthStateChange(
+      (event, session) => {
+        if (session?.user) {
+          setUser(session.user);
+        } else if (event === 'SIGNED_OUT') {
+          setUser(null);
+          if (inactivityTimeoutRef.current) {
+            clearTimeout(inactivityTimeoutRef.current);
+            inactivityTimeoutRef.current = null;
+          }
+        }
+      }
+    );
+
+    return () => {
+      if (authListener?.subscription) {
+        authListener.subscription.unsubscribe();
+      }
+    };
+  }, []);
+
+  // Auth context value
+  const value = {
+    user,
+    loading,
+    logout,
+    resetInactivityTimer,
+  };
+
+  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
+};
Index: client/src/main.jsx
===================================================================
--- client/src/main.jsx	(revision e196291edd024fc4223db37151fdedc30846a384)
+++ client/src/main.jsx	(revision ed03d445085c472b13707490fa74805ebb81cb54)
@@ -3,4 +3,5 @@
 import './index.css';
 
+import ProtectedRoute from './routes/ProtectedRoute';
 import LandingPage from './LandingPage/LandingPage';
 import Register from './Register/Register';
@@ -13,22 +14,74 @@
 import Profile from './Dashboard/components/Profile';
 import LeaderBoardEx from './LandingPage/components/LeaderBoardEx';
-import ManagePosts from "@/Dashboard/components/ManagePosts.jsx";
+import ManagePosts from '@/Dashboard/components/ManagePosts.jsx';
+import { AuthProvider } from './contexts/AuthContext';
+
 createRoot(document.getElementById('root')).render(
   <Router>
-    <Routes>
-      <Route path="/" element={<LandingPage />} />
-      <Route path="/register" element={<Register />} />
-      <Route path="/login" element={<Login />} />
-      <Route path="/dashboard" element={<Task />} />
-      <Route path="/dashboard/create-post" element={<CreatePost />} />
-      <Route path="/dashboard/forum" element={<Forum />} />
-      <Route path="/dashboard/manage-posts" element={<ManagePosts />} />
-      <Route
-        path="/dashboard/forum-detail/:postId"
-        element={<ForumPostDetail />}
-      />
-      <Route path="/dashboard/profile" element={<Profile />} />
-      <Route path="/dashboard/leaderboard" element={<LeaderBoardEx />} />
-    </Routes>
+    <AuthProvider>
+      <Routes>
+        <Route path="/" element={<LandingPage />} />
+        <Route path="/register" element={<Register />} />
+        <Route path="/login" element={<Login />} />
+
+        {/* Protected routes - let ProtectedRoute handle the logic */}
+        <Route
+          path="/dashboard"
+          element={
+            <ProtectedRoute>
+              <Task />
+            </ProtectedRoute>
+          }
+        />
+        <Route
+          path="/dashboard/create-post"
+          element={
+            <ProtectedRoute>
+              <CreatePost />
+            </ProtectedRoute>
+          }
+        />
+        <Route
+          path="/dashboard/forum"
+          element={
+            <ProtectedRoute>
+              <Forum />
+            </ProtectedRoute>
+          }
+        />
+        <Route
+          path="/dashboard/manage-posts"
+          element={
+            <ProtectedRoute>
+              <ManagePosts />
+            </ProtectedRoute>
+          }
+        />
+        <Route
+          path="/dashboard/forum-detail/:postId"
+          element={
+            <ProtectedRoute>
+              <ForumPostDetail />
+            </ProtectedRoute>
+          }
+        />
+        <Route
+          path="/dashboard/profile"
+          element={
+            <ProtectedRoute>
+              <Profile />
+            </ProtectedRoute>
+          }
+        />
+        <Route
+          path="/dashboard/leaderboard"
+          element={
+            <ProtectedRoute>
+              <LeaderBoardEx />
+            </ProtectedRoute>
+          }
+        />
+      </Routes>
+    </AuthProvider>
   </Router>
 );
Index: client/src/routes/ProtectedRoute.jsx
===================================================================
--- client/src/routes/ProtectedRoute.jsx	(revision ed03d445085c472b13707490fa74805ebb81cb54)
+++ client/src/routes/ProtectedRoute.jsx	(revision ed03d445085c472b13707490fa74805ebb81cb54)
@@ -0,0 +1,48 @@
+import { Navigate, useLocation } from 'react-router-dom';
+import { useAuth } from '../contexts/AuthContext';
+import React, { useState, useEffect } from 'react';
+
+const ProtectedRoute = ({ children }) => {
+  const { user, loading } = useAuth();
+  const [localUser, setLocalUser] = useState(null);
+  const [isChecking, setIsChecking] = useState(true);
+  const location = useLocation();
+
+  useEffect(() => {
+    try {
+      const userFromStorage = localStorage.getItem('user');
+      if (userFromStorage) {
+        setLocalUser(JSON.parse(userFromStorage));
+      }
+    } catch (err) {
+      console.error('Error reading from localStorage:', err);
+    } finally {
+      setIsChecking(false);
+    }
+  }, []);
+
+  // Show loading spinner while checking auth
+  if (loading || isChecking) {
+    return (
+      <div className="flex h-screen items-center justify-center">
+        <span className="loading loading-spinner loading-lg"></span>
+      </div>
+    );
+  }
+
+  // IMPORTANT: This is the key fix - explicitly check if both are null/undefined
+  if (!user || !localUser) {
+    console.log('Not authenticated, redirecting to login');
+    return (
+      <Navigate
+        to={`/login?redirect=${encodeURIComponent(location.pathname)}`}
+        replace
+      />
+    );
+  }
+
+  // If we get here, we're authenticated
+  return children;
+};
+
+export default ProtectedRoute;
