diff --git a/apps/server/src/modules/account/repositories/index.ts b/apps/server/src/modules/account/repositories/index.ts index 732fb0d..c2e3484 100644 --- a/apps/server/src/modules/account/repositories/index.ts +++ b/apps/server/src/modules/account/repositories/index.ts @@ -1,16 +1,7 @@ import { db, eq, sql } from "@fixr/db/connection"; import { clients, companies, employees, users } from "@fixr/db/schema"; import { accountSchema } from "@fixr/schemas/account"; -<<<<<<< HEAD -import { Cached } from "../../../shared/infra/cache"; -======= -import { redis } from "../../../config/redis"; -import { - accountCacheKey, - CACHE_TTL, - jwtPayloadCacheKey, -} from "../../../core/lib/cache"; ->>>>>>> 990eba6 (Feat(Server): Add avatar upload presign, update, and remove endpoints) +import { Cached, InvalidateCache } from "../../../shared/infra/cache"; /** @description Account data access layer */ export class AccountRepository { @@ -62,11 +53,8 @@ export class AccountRepository { * @param userId - The user ID * @param avatarUrl - The new avatar URL */ + @InvalidateCache({ patterns: ["account:*", "jwt:*"] }) static async updateAvatarUrl(userId: string, avatarUrl: string | null) { await db.update(users).set({ avatarUrl }).where(eq(users.id, userId)); - - const cacheKey = accountCacheKey(userId); - const jwtCacheKey = jwtPayloadCacheKey(userId); - await Promise.all([redis.del(cacheKey), redis.del(jwtCacheKey)]); } } diff --git a/apps/web/app/(protected)/dashboard/[subdomain]/layout.tsx b/apps/web/app/(protected)/dashboard/[subdomain]/layout.tsx index 9287049..ba1333f 100644 --- a/apps/web/app/(protected)/dashboard/[subdomain]/layout.tsx +++ b/apps/web/app/(protected)/dashboard/[subdomain]/layout.tsx @@ -5,6 +5,7 @@ import { SessionProvider } from "@/lib/hooks/use-session"; import QueryClientWrapper from "@/lib/query-client"; import "../../../globals.css"; import { cookies } from "next/headers"; +import { redirect } from "next/navigation"; import { Header } from "@/components/dashboard/sidebar/header"; import { ThemeProvider } from "@/components/theme-provider"; import { ThemedToaster } from "@/components/themed-toaster"; @@ -35,6 +36,10 @@ export default async function RootLayout({ const cookieStore = await cookies(); const session = getSession(cookieStore); + if (!session) { + redirect("/auth/login"); + } + return (
| null { + const jwt = cookies + ? parseJwt(cookies.get(cookieKey("session"))?.value) + : parseJwt(parseCookies()[cookieKey("session")]); - const cookieStore = parseCookies(); - const jwt = parseJwt(cookieStore[cookieKey("session")]); // Corrected access using cookieKey - return userJWT.parse(jwt); + // Missing/expired sessions are expected (the middleware revalidates the token + // before this runs); fail gracefully to null instead of throwing a ZodError. + const result = userJWT.safeParse(jwt); + return result.success ? result.data : null; } export const getClientSession = (): ReturnType