Core Concepts

This document explains the key architectural patterns and data models used in the FriendZone application.

Authentication and Route Protection

The application uses next-auth for authentication, specifically with a Google OAuth provider.

Authentication Flow

  1. Configuration (src/lib/auth.ts): This file sets up next-auth. It configures the UpstashRedisAdapter to store session and user data in Redis. It also defines the jwt and session callbacks to enrich the session token with the user's database ID.
  2. Login Page (src/app/(auth)/login/page.tsx): The login page provides a simple button that triggers the signIn('google') function from next-auth/react.
  3. Middleware (src/middleware.ts): A crucial part of the security model. The middleware checks every incoming request to sensitive routes (like /dashboard).
    • If a user is not authenticated and tries to access a protected route, they are redirected to /login.
    • If an authenticated user tries to access /login, they are redirected to /dashboard.

Real-time Communication with Pusher

Pusher is used to push real-time updates to connected clients, avoiding the need for clients to constantly poll the server for new data.

Setup (src/lib/pusher.ts)

  • pusherServer: A server-side instance of Pusher used in API routes to trigger events.
  • pusherClient: A client-side instance used in React components to subscribe to channels and bind to events.

Channels and Events

The application uses a specific channel naming convention managed by toPusherKey() to ensure compatibility.

  • Friend Requests:

    • Channel: user:{userId}:incoming_friend_requests
    • Event: incoming_friend_requests
    • Triggered: When a user sends a friend request in POST /api/friends/add.
    • Listened by: FriendRequests.tsx and FriendRequestSidebarOptions.tsx to update the UI in real-time.
  • New Friends:

    • Channel: user:{userId}:friends
    • Event: new_friend
    • Triggered: When a user accepts a friend request in POST /api/friends/accept.
    • Listened by: SidebarChatList.tsx to add the new friend to the chat list, and FriendRequestSidebarOptions.tsx to decrement the request counter.
  • Chat Messages:

    • Channel: chat:{chatId}
    • Event: incoming-message
    • Triggered: When a message is sent in POST /api/message/send.
    • Listened by: Messages.tsx to display the new message in the chat window.
  • New Chat Notifications:

    • Channel: user:{friendId}:chats
    • Event: new_message
    • Triggered: When a message is sent in POST /api/message/send.
    • Listened by: SidebarChatList.tsx to show a notification toast and update the unread message count for the relevant chat.

Redis Data Model

Upstash Redis is used as the application's database due to its high performance, which is ideal for a real-time chat application.

  • User Data:

    • user:{userId}: A JSON string containing the user's id, name, email, and image.
    • user:email:{email}: A simple key that stores the userId corresponding to an email address. This allows for quick lookups when adding a friend by email.
  • Friend Relationships:

    • user:{userId}:friends: A Redis Set containing the IDs of all users who are friends with {userId}. Sets are efficient for checking membership (e.g., are these two users friends?).
  • Friend Requests:

    • user:{userId}:incoming_friend_requests: A Redis Set containing the IDs of all users who have sent a friend request to {userId}.
  • Chat Messages:

    • chat:{chatId}:messages: A Redis Sorted Set. Each member of the set is a JSON string representing a message object. The score for each member is the message timestamp. This allows for efficient, chronologically ordered retrieval of messages.