Frontend Architecture
Relevant source files
The following files were used as context for generating this wiki page:
The Grapevine website is a modern web application built with Next.js 16 and TypeScript. It serves as the company's main marketing and information site, designed to be performant, SEO-friendly, and easily maintainable. The architecture leverages the Next.js App Router for server-centric rendering and routing, with client-side interactivity added where necessary.
The frontend is characterized by a component-based structure, a utility-first styling approach with Tailwind CSS, and a strong emphasis on Search Engine Optimization (SEO) through structured data generation. Animations are handled by Framer Motion to provide a fluid user experience.
Technology Stack
The core of the frontend is built upon a curated set of modern technologies. The primary dependencies and their roles are outlined below.
| Technology | Version | Role | Source |
|---|---|---|---|
| Next.js | 16.0.3 | Full-stack React framework for routing, rendering, and tooling. | package.json:15 |
| React | 19.2.0 | UI library for building components. | package.json:16 |
| TypeScript | ^5 | Statically types the JavaScript codebase for improved robustness. | package.json:30 |
| Tailwind CSS | ^4 | A utility-first CSS framework for styling. | package.json:29 |
| Framer Motion | ^12.23.24 | A production-ready motion library for React animations. | package.json:13 |
| Lucide React | ^0.554.0 | Provides a set of clean and consistent icons. | package.json:14 |
| clsx | ^2.1.1 | A tiny utility for constructing className strings conditionally. | package.json:12 |
| tailwind-merge | ^3.4.0 | Utility to merge Tailwind CSS classes without style conflicts. | package.json:18 |
Sources: package.json, README.md:5-10
Project Structure
The project follows a standard Next.js App Router structure, organizing files by feature and route.
This diagram illustrates the main directories and their purpose within the project.
Sources: README.md:31-37
| Directory | Description |
|---|---|
app/ | Contains all routes, pages, and layouts, following the Next.js App Router conventions. Also includes API routes and sitemap generation. |
components/ | Holds reusable React components, categorized into primitives, animations, icons, and larger composite components. |
lib/ | Contains utility functions, helper scripts, and shared logic, such as the SEO generation module. |
public/ | Stores static assets like images, fonts, and the favicon.ico. |
Sources: README.md:31-37, app/sitemap.ts, lib/seo.ts
Routing and Layouts
The application uses the Next.js App Router for its file-system-based routing.
Root Layout
The main entry point for the UI is app/layout.tsx. This file defines the root layout that wraps every page. Its key responsibilities include:
- Defining the
<html>and<body>tags. - Loading the global CSS file (
./globals.css). - Configuring and applying the custom local font, "Ambit".
- Rendering a common
<Header />and<Footer />. - Injecting site-wide JSON-LD structured data for SEO, specifically the
Organizationschema. - Defining global metadata, including title templates, descriptions, and Open Graph tags.
Sources: app/layout.tsx
The following diagram shows how a page is constructed with the root layout.
Sources: app/layout.tsx:138-142
Page Structure
Each page is a React component exported as the default from a page.tsx file within the app directory (e.g., app/about/page.tsx). Pages are primarily server components, fetching data and composing UI on the server. They can export a metadata object to define page-specific SEO information, which Next.js uses to generate <head> tags.
Sources: app/page.tsx:11-17, app/about/page.tsx:5-11
State Management and Interactivity
For components requiring client-side interactivity, the "use client" directive is used. State is managed locally within these components using React hooks like useState.
A clear example is the contact-form.tsx component, which manages form data, validation errors, and submission status.
// components/contact-form.tsx:21-32
const [formData, setFormData] = useState<FormData>({
fullName: "",
workEmail: "",
iAmA: "",
companyName: "",
role: "",
message: "",
});
const [errors, setErrors] = useState<FormErrors>({});
const [isSubmitted, setIsSubmitted] = useState(false);
const [isLoading, setIsLoading] = useState(false);
Sources: [components/contact-form.tsx:21-32]
Animations are implemented using framer-motion, as seen in the conditional rendering of the success message in the contact form.
Sources: components/contact-form.tsx:216-238, package.json:13
SEO and Metadata
SEO is a first-class citizen in the architecture, managed centrally through lib/seo.ts and applied at both the layout and page levels.
SEO Configuration
The lib/seo.ts file exports a siteConfig object containing global SEO details like the site name, description, URL, and social media handles.
// lib/seo.ts:1-10
export const siteConfig = {
name: "Grapevine",
description:
"Grapevine detects gaps in itineraries and sends personalised prompts that encourage traveller to book in-platform, driving compliance for corporates and revenue for TMCs.",
url: process.env.NEXT_PUBLIC_APP_URL || "https://grapevine.travel",
ogImage: "/images/og-image.png",
xHandle: "grapevine_trvl",
// ...
};
Sources: [lib/seo.ts:1-10]
Structured Data (JSON-LD)
The application generates multiple types of schema.org structured data to improve search engine understanding. The lib/seo.ts file contains interfaces and generator functions for various schemas.
| Function | Schema Type | Purpose |
|---|---|---|
generateOrganizationSchema() | Organization | Describes the company. Used in the root layout. |
generateWebPageSchema() | WebPage | Describes a generic web page. |
generateSoftwareSchema() | SoftwareApplication | Describes the Grapevine software product. |
generateBreadcrumbSchema() | BreadcrumbList | Provides breadcrumb navigation for pages. |
generateFAQSchema() | FAQPage | Structures frequently asked questions. |
generateServiceSchema() | Service | Describes services offered to TMCs or Corporates. |
Sources: [lib/seo.ts]
This structured data is injected into pages using a client component <JsonLd /> which safely renders the JSON object in a <script> tag.
The diagram below shows the flow for generating and rendering SEO data for a specific page.
Sources: app/about/page.tsx:13-17, app/about/page.tsx:21-22, [lib/seo.ts]
API Interaction
Client components interact with backend API endpoints using the browser's fetch API. The contact form provides a clear example of this pattern. On submission, it sends a POST request to /api/contact.
The following sequence diagram illustrates the contact form submission flow.
Sources: [components/contact-form.tsx:87-120]