Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Jason-AML/MonzaSport-Nextjs/llms.txt

Use this file to discover all available pages before exploring further.

Monza Motors includes a floating AI chat assistant that lets signed-in customers ask questions about the vehicle catalog and get instant, contextual answers. The assistant is accessible via the FloatingBar at the bottom of the page and is powered by Groq’s llama-3.3-70b-versatile model. Every conversation is persisted in Supabase’s messages table and delivered to the browser in real time via Supabase Realtime, so new assistant replies appear without polling or page refreshes.

How It Works

1

User opens the chat panel

The chat panel is part of the FloatingBar component and is only interactive when the user is signed in. Unauthenticated visitors see a “Please sign in” prompt instead of the message input.
2

useChat() loads history and subscribes to Realtime

When the ChatAssistant component mounts, the useChat() hook fires. It queries the messages table for all rows matching the current user_id, ordered by created_at, and sets the initial messages state. In a parallel useEffect, it opens a Supabase Realtime channel scoped to the same user_id filter.
3

User sends a message

When the user submits text, sendMessage(content) first inserts the message into the messages table with role: 'user', then POSTs the user_id and content to /api/chat.
4

API route builds context and calls Groq

The POST /api/chat handler fetches the full vehicle catalog via getCollections() and retrieves the last 20 messages from the messages table for that user. It assembles a system prompt containing the formatted catalog data and passes the history plus the new user message to Groq’s llama-3.3-70b-versatile model using the Vercel AI SDK’s generateText helper.
5

Assistant reply is saved to Supabase

Once Groq responds, the API route inserts the generated text into the messages table with role: 'assistant'. The browser’s open Realtime channel immediately receives the new row via a postgres_changes event.
6

Realtime pushes the reply to the UI

The Realtime subscription callback appends payload.new to the messages array in state. The ChatAssistant component’s message list re-renders and auto-scrolls to the bottom ref, displaying the assistant’s answer without any polling.

useChat Hook

The useChat hook at src/hooks/useChat.js encapsulates all chat state, history loading, Realtime subscriptions, and message sending. It reads the authenticated user from useAuth() so it automatically becomes active the moment the user signs in.
import { useChat } from '@/hooks/useChat';

const { messages, loading, sendMessage, user } = useChat();
// messages: array of { id, user_id, role, content, created_at }
// loading: boolean — true while AI is generating
// sendMessage(text): async function to send a user message
// user: current Supabase user object (null if not logged in)
  • messages — The full conversation history for the current user, sorted oldest-first. Each entry includes id, user_id, role ('user' or 'assistant'), content, and created_at.
  • loading — Set to true when sendMessage is in flight (from the moment the user message is inserted until the API route returns). The ChatAssistant renders a “Your assistant is typing…” indicator while this is true.
  • sendMessage(text) — An async function memoised with useCallback. It guards against empty strings and skips the call if user is null.
  • user — The Supabase user object sourced from AuthProvider. The hook short-circuits both useEffect hooks when user is null, so no Supabase calls are made for unauthenticated visitors.

Real-time Subscriptions

The useChat hook creates one Supabase Realtime channel per signed-in session, named chat-{user.id}. The channel listens for INSERT events on the messages table filtered to the current user:
const channel = supabase
  .channel('chat-' + user.id)
  .on(
    'postgres_changes',
    {
      event: 'INSERT',
      schema: 'public',
      table: 'messages',
      filter: `user_id=eq.${user.id}`,
    },
    (payload) => {
      setMessages((prev) => [...prev, payload.new]);
    }
  )
  .subscribe();
Because the filter is scoped to the user’s own ID, each client only receives its own messages. The channel is torn down via supabase.removeChannel(channel) when the component unmounts or the user changes.

System Prompt and Catalog Context

The /api/chat route constructs a system prompt at runtime that embeds the entire vehicle catalog so the model can answer precise questions about specs, pricing, and availability. Each vehicle is formatted as a colon-separated string containing all key fields:
- {nombre_vehiculo}:{modelo}:{anio}:{precio}:{motor}:{poder_hp}:{aceleracion_0_100}:{velocidad_maxima}:{torque_nm}:{peso_kg}: {description}
The system prompt instructs the model to:
  • Base answers on the catalog context, and may supplement with additional relevant information.
  • Never alter prices or specifications from the provided context.
  • Treat all prices as USD.
  • Politely redirect off-topic questions back to the catalog.
Because the catalog data is injected at request time, it always reflects the latest vehicles in the database without redeploying the application.

Message Storage Schema

All chat messages — both user and assistant — are stored in the messages table in Supabase:
ColumnTypeDescription
iduuidPrimary key, auto-generated
user_iduuidReferences the Supabase auth user
roletextEither 'user' or 'assistant'
contenttextThe message body (supports Markdown for assistant replies)
created_attimestamptzAuto-set on insert, used for ordering
The ChatAssistant component renders content through react-markdown, so the model can return formatted lists, bold text, or tables when describing vehicle comparisons.
The chat is only available to authenticated users. When user is null, the ChatAssistant component renders a "Inicia sesión para chatear." (“Please sign in to chat”) message in place of the message list and input field.
To keep Groq token usage low, the API route fetches only the last 20 messages from the messages table when building the conversation history. Older messages are excluded from the request but remain stored in Supabase and are visible when the user reopens the chat panel.

Build docs developers (and LLMs) love