From b2122cf6456780b40c96652b16be92c3f365dbb9 Mon Sep 17 00:00:00 2001 From: hafzism Date: Fri, 6 Mar 2026 09:51:25 +0530 Subject: [PATCH 1/4] feat: enable analytics cron jobs, refactor rate limiter middleware import paths --- .gitignore | 4 +++- .../ratelimit.middleware.ts} | 12 ++++------ backend/src/routes/analytics.routes.ts | 2 +- backend/src/routes/auth.routes.ts | 2 +- backend/src/routes/generative.routes.ts | 2 +- backend/src/services/cron/analytics.cron.ts | 24 ++++++------------- 6 files changed, 17 insertions(+), 29 deletions(-) rename backend/src/{utils/ratelimit.ts => middleware/ratelimit.middleware.ts} (72%) diff --git a/.gitignore b/.gitignore index 5bd61a0..4d071ff 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,6 @@ dist/ next-env.d.ts logs/ -*.log \ No newline at end of file +*.log +# Firebase service account +serviceAccountKey.json diff --git a/backend/src/utils/ratelimit.ts b/backend/src/middleware/ratelimit.middleware.ts similarity index 72% rename from backend/src/utils/ratelimit.ts rename to backend/src/middleware/ratelimit.middleware.ts index db9a661..a270c01 100644 --- a/backend/src/utils/ratelimit.ts +++ b/backend/src/middleware/ratelimit.middleware.ts @@ -1,7 +1,7 @@ import { Request, Response, NextFunction } from "express"; import redisClient from "../config/redis"; -import { ErrorResponse } from "./responses"; -import logger from "./logger"; +import { ErrorResponse } from "../utils/responses"; +import logger from "../utils/logger"; export const rateLimiter = ( prefix: string, @@ -10,15 +10,13 @@ export const rateLimiter = ( getIdentifier?: (req: Request) => string | undefined, ) => { return async (req: Request, res: Response, next: NextFunction) => { - const identifier = getIdentifier?.(req) || req.auth?.id || req.ip; + const identifier = getIdentifier?.(req) || req.auth?.id; if (!identifier) { - next(); // Should not happen with req.ip fallback + next(); return; } - // Key format: ratelimit:{prefix}:{identifier}:{window_start_timestamp} - // We use a fixed-window approach where the window is identified by the floor of the current timestamp const now = Math.floor(Date.now() / 1000); const windowStart = now - (now % windowSeconds); const key = `ratelimit:${prefix}:${identifier}:${windowStart}`; @@ -27,7 +25,6 @@ export const rateLimiter = ( const current = await redisClient.incr(key); if (current === 1) { - // First request in this window, set expiration await redisClient.expire(key, windowSeconds); } @@ -50,7 +47,6 @@ export const rateLimiter = ( next(); } catch (error) { logger.error(`[RateLimit] Error for ${key}:`, error); - // Fail open: allow the request if Redis is down, but log the error next(); } }; diff --git a/backend/src/routes/analytics.routes.ts b/backend/src/routes/analytics.routes.ts index 288d940..8b5ea17 100644 --- a/backend/src/routes/analytics.routes.ts +++ b/backend/src/routes/analytics.routes.ts @@ -2,7 +2,7 @@ import express from "express"; import { authenticate } from "../middleware/auth.middleware"; import * as analyticsController from "../controllers/analytics.controller"; -import { rateLimiter } from "../utils/ratelimit"; +import { rateLimiter } from "../middleware/ratelimit.middleware"; const router = express.Router(); diff --git a/backend/src/routes/auth.routes.ts b/backend/src/routes/auth.routes.ts index 40b99f9..1b2eaa3 100644 --- a/backend/src/routes/auth.routes.ts +++ b/backend/src/routes/auth.routes.ts @@ -20,7 +20,7 @@ import { logoutDevice, } from "../controllers/auth.controller"; import { authenticate } from "../middleware/auth.middleware"; -import { rateLimiter } from "../utils/ratelimit"; +import { rateLimiter } from "../middleware/ratelimit.middleware"; import { validate } from "../middleware/validate.middleware"; import { diff --git a/backend/src/routes/generative.routes.ts b/backend/src/routes/generative.routes.ts index 1fa9f2f..26a039e 100644 --- a/backend/src/routes/generative.routes.ts +++ b/backend/src/routes/generative.routes.ts @@ -5,7 +5,7 @@ import { } from "../controllers/generative.controller"; import { authenticate } from "../middleware/auth.middleware"; import { checkUserGenerationLimit } from "../middleware/limitChecker.middleware"; -import { rateLimiter } from "../utils/ratelimit"; +import { rateLimiter } from "../middleware/ratelimit.middleware"; const router = Router(); diff --git a/backend/src/services/cron/analytics.cron.ts b/backend/src/services/cron/analytics.cron.ts index 5291d92..28b80c1 100644 --- a/backend/src/services/cron/analytics.cron.ts +++ b/backend/src/services/cron/analytics.cron.ts @@ -1,4 +1,4 @@ -// import cron from "node-cron"; +import cron from "node-cron"; import logger from "../../utils/logger"; import * as SocialAccountRepository from "../../repositories/socialAccount.repository"; import * as postRepository from "../../repositories/post.repository"; @@ -9,14 +9,14 @@ export class AnalyticsCronService { logger.info("📅 Initializing Analytics Cron Service..."); // 1. Post Analytics Job - Run every 2 hours to support smart fetching - // cron.schedule("0 */2 * * *", async () => { - // await this.schedulePostAnalyticsTasks(); - // }); + cron.schedule("0 */2 * * *", async () => { + await this.schedulePostAnalyticsTasks(); + }); // 2. Account Analytics Job - Run once a day at 12:00 AM - // cron.schedule("0 0 * * *", async () => { - // await this.scheduleAccountAnalyticsTasks(); - // }); + cron.schedule("0 0 * * *", async () => { + await this.scheduleAccountAnalyticsTasks(); + }); logger.info("✅ Analytics Cron Jobs ready (Automated scheduling disabled in DEV)."); } @@ -58,9 +58,6 @@ export class AnalyticsCronService { } } - /** - * Helper to check if a specific platform status within a post needs an update - */ private static checkSpecificPlatformNeedsUpdate( postCreatedAt: Date | undefined, lastFetch?: Date, @@ -75,21 +72,15 @@ export class AnalyticsCronService { const ONE_DAY = 24 * 60 * 60 * 1000; const SEVEN_DAYS = 7 * ONE_DAY; - // Fresh (< 24h): 2h interval if (ageMs < ONE_DAY) { return diffMs >= 2 * 60 * 60 * 1000; } - // Recent (1-7d): 12h interval if (ageMs < SEVEN_DAYS) { return diffMs >= 12 * 60 * 60 * 1000; } - // Old (> 7d): 24h interval return diffMs >= ONE_DAY; } - /** - * Schedules account-level metrics fetch (followers) for all connected accounts - */ public static async scheduleAccountAnalyticsTasks() { logger.info("🔄 Checking for accounts needing follower updates..."); @@ -97,7 +88,6 @@ export class AnalyticsCronService { const accounts = await SocialAccountRepository.findAll(); for (const account of accounts) { - // Collect platforms where at least one sub-platform is connected const platforms: string[] = []; if (account.facebook?.connected) platforms.push("facebook"); From 29d0ff1c1a3fde4e25d97f4f56e551060bb855fe Mon Sep 17 00:00:00 2001 From: star-boy Date: Fri, 6 Mar 2026 10:14:32 +0530 Subject: [PATCH 2/4] fix(ui-resposive): calendar page card responsiveness added --- frontend/src/app/(user)/calendar/page.tsx | 4 +-- .../components/calendar/CalendarComponent.tsx | 26 +++++++++---------- .../components/calendar/CalendarPostCard.tsx | 22 ++++++++-------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/frontend/src/app/(user)/calendar/page.tsx b/frontend/src/app/(user)/calendar/page.tsx index 256b120..b9316c2 100644 --- a/frontend/src/app/(user)/calendar/page.tsx +++ b/frontend/src/app/(user)/calendar/page.tsx @@ -48,7 +48,7 @@ export default function CalendarPage() { {/* Main Content Area */}
{user && ( -
+
+
{!user ? (
diff --git a/frontend/src/components/calendar/CalendarComponent.tsx b/frontend/src/components/calendar/CalendarComponent.tsx index a2179b0..05a7e8d 100644 --- a/frontend/src/components/calendar/CalendarComponent.tsx +++ b/frontend/src/components/calendar/CalendarComponent.tsx @@ -89,16 +89,16 @@ export default function CalendarComponent() { }; return ( -
+
{/* Calendar Header matching mockup */} -
+
{/* Year Label */} -

+

{format(currentDate, "yyyy")}

{/* Month Navigation Pill */} -
+
- + {format(currentDate, "MMMM")} @@ -120,7 +120,7 @@ export default function CalendarComponent() {
{/* Calendar Grid Container */} -
+
{/* Days Header */}
{(isMobile @@ -129,7 +129,7 @@ export default function CalendarComponent() { ).map((day) => (
{day}
@@ -137,7 +137,7 @@ export default function CalendarComponent() {
{/* Days Grid */} -
+
{calendarDays.map((day, idx) => { const isSelected = isSameDay(day, selectedDate); const isCurrentMonth = isSameMonth(day, monthStart); @@ -173,7 +173,7 @@ export default function CalendarComponent() { className={cn( "relative flex flex-col transition-all duration-300", "aspect-square md:aspect-[1.3/1]", - "rounded-full p-2 md:rounded-[18px] md:p-4", + "rounded-full p-1 sm:p-2 md:rounded-[18px] md:p-4", !isCurrentMonth ? "opacity-30 md:bg-white/40" : "opacity-100", isSelected ? "bg-[#318D62] text-white shadow-lg md:shadow-none" @@ -185,7 +185,7 @@ export default function CalendarComponent() { {/* Date Number - Top Left on Desktop, Center on Mobile */} -
-

+
+

{isSameDay(selectedDate, new Date()) ? "Today's Content" : format(selectedDate, "MMMM do")} @@ -380,7 +380,7 @@ export default function CalendarComponent() {

) : ( -
+
diff --git a/frontend/src/components/calendar/CalendarPostCard.tsx b/frontend/src/components/calendar/CalendarPostCard.tsx index 4ea9455..d7619f5 100644 --- a/frontend/src/components/calendar/CalendarPostCard.tsx +++ b/frontend/src/components/calendar/CalendarPostCard.tsx @@ -21,10 +21,10 @@ export function CalendarPostCard({ return (
{/* Post Image */} -
+
{imageUrl ? ( Post Content ) : ( @@ -49,23 +49,23 @@ export function CalendarPostCard({
{/* Post Details */} -
+
-

+

{description}

-
-
- +
+
+ posted -
+
{platformStatuses.map((p, idx) => (
-
From c5128f7be0069ec786074d389fcf80eafb3c2827 Mon Sep 17 00:00:00 2001 From: star-boy Date: Fri, 6 Mar 2026 10:43:02 +0530 Subject: [PATCH 3/4] chore(details-navigation): detailed navigation added in caleder cards --- .../src/components/calendar/CalendarPostCard.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/calendar/CalendarPostCard.tsx b/frontend/src/components/calendar/CalendarPostCard.tsx index d7619f5..8915b42 100644 --- a/frontend/src/components/calendar/CalendarPostCard.tsx +++ b/frontend/src/components/calendar/CalendarPostCard.tsx @@ -1,6 +1,7 @@ "use client"; import Image from "next/image"; +import { useRouter } from "next/navigation"; import { ArrowUpRight } from "lucide-react"; interface CalendarPostCardProps { @@ -13,14 +14,25 @@ interface CalendarPostCardProps { } export function CalendarPostCard({ + id, imageUrl, description, platformStatuses = [], onClick, }: CalendarPostCardProps) { + const router = useRouter(); + + const handleClick = () => { + if (onClick) { + onClick(); + } else { + router.push(`/history/${id}`); + } + }; + return (
{/* Post Image */} From d0161fabfee70dd7acfeb37bb91c2f4c32201d33 Mon Sep 17 00:00:00 2001 From: star-boy Date: Fri, 6 Mar 2026 10:48:16 +0530 Subject: [PATCH 4/4] fix(ui): calendar responsive --- frontend/src/components/calendar/CalendarComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/calendar/CalendarComponent.tsx b/frontend/src/components/calendar/CalendarComponent.tsx index 05a7e8d..24ae684 100644 --- a/frontend/src/components/calendar/CalendarComponent.tsx +++ b/frontend/src/components/calendar/CalendarComponent.tsx @@ -171,7 +171,7 @@ export default function CalendarComponent() { key={idx} onClick={() => setSelectedDate(day)} className={cn( - "relative flex flex-col transition-all duration-300", + "relative flex items-center justify-center md:flex-col md:items-stretch md:justify-start transition-all duration-300", "aspect-square md:aspect-[1.3/1]", "rounded-full p-1 sm:p-2 md:rounded-[18px] md:p-4", !isCurrentMonth ? "opacity-30 md:bg-white/40" : "opacity-100",