Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# robots.txt — Citronics 2026 (cdgicitronics.in)
# Generated for optimal Google / Bing / Edge crawling

User-agent: *
Allow: /
Allow: /about
Allow: /events
Allow: /events/
Allow: /gallery
Allow: /team
Allow: /register

# Exclude auth, transactional, and private pages from indexation
Disallow: /login
Disallow: /dashboard
Disallow: /tickets
Disallow: /api/
Disallow: /401
Disallow: /404
Disallow: /500

# Next.js internals — allow render-critical JS/CSS but block image optimizer
Disallow: /_next/
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Allow: /_next/static/
Disallow: /_next/image

# Exclude admin routes
Disallow: /admin
Disallow: /admin/

# Sitemap location
Sitemap: https://cdgicitronics.in/sitemap.xml
91 changes: 91 additions & 0 deletions src/components/SEO/SEOHead.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* ┌──────────────────────────────────────────────────────────────────────────┐
* │ SEOHead — Core <Head> Component │
* │ │
* │ Renders title, meta description, keywords, canonical URL, Open Graph, │
* │ Twitter Card, and JSON-LD structured data. │
* │ │
* │ NOT imported directly in pages — wrapped by per-page components like │
* │ HomeSEO, AboutSEO, etc. that pre-fill all props. │
* └──────────────────────────────────────────────────────────────────────────┘
*/
import Head from 'next/head'
import { SITE, buildCanonical } from './seo.config'

const SEOHead = ({
title,
description,
keywords,
canonicalPath = '/',
ogType = 'website',
ogImage,
noIndex = false,
schemas = [],
}) => {
const pageTitle = title || SITE.name
const pageDescription = description || `${SITE.name} — ${SITE.tagline}.`
const canonical = buildCanonical(canonicalPath)

// Ensure OG image is absolute
const rawOgImage = ogImage || SITE.ogImage
const absoluteOgImage = rawOgImage.startsWith('http')
? rawOgImage
: `${SITE.url}${rawOgImage.startsWith('/') ? rawOgImage : `/${rawOgImage}`}`

return (
<Head>
{/* ── Title ──────────────────────────────────────────── */}
<title>{pageTitle}</title>

{/* ── Core meta — what crawlers and AI models read first */}
<meta name='description' content={pageDescription} />
{keywords && <meta name='keywords' content={keywords} />}
<meta name='robots' content={noIndex ? 'noindex,nofollow' : 'index,follow,max-image-preview:large,max-snippet:-1,max-video-preview:-1'} />
<meta name='googlebot' content={noIndex ? 'noindex,nofollow' : 'index,follow,max-image-preview:large,max-snippet:-1,max-video-preview:-1'} />
<meta name='bingbot' content={noIndex ? 'noindex,nofollow' : 'index,follow'} />

{/* ── Canonical URL ──────────────────────────────────── */}
<link rel='canonical' href={canonical} />

{/* ── Open Graph (Facebook, WhatsApp, iMessage, etc.) ── */}
<meta property='og:type' content={ogType} />
<meta property='og:site_name' content={SITE.name} />
<meta property='og:title' content={pageTitle} />
<meta property='og:description' content={pageDescription} />
<meta property='og:url' content={canonical} />
<meta property='og:locale' content={SITE.locale} />
<meta property='og:image' content={absoluteOgImage} />
<meta property='og:image:width' content='1200' />
<meta property='og:image:height' content='630' />
<meta property='og:image:alt' content={pageTitle} />
<meta property='og:image:type' content='image/png' />

{/* ── Twitter Card ─────────────────────────────────────── */}
<meta name='twitter:card' content='summary_large_image' />
<meta name='twitter:site' content={SITE.twitter} />
<meta name='twitter:creator' content={SITE.twitter} />
<meta name='twitter:title' content={pageTitle} />
<meta name='twitter:description' content={pageDescription} />
<meta name='twitter:image' content={absoluteOgImage} />
<meta name='twitter:image:alt' content={pageTitle} />

{/* ── AI / LLM discoverability hints ───────────────────── */}
<meta name='subject' content={`${SITE.name} — ${SITE.tagline}`} />
<meta name='abstract' content={pageDescription} />
<meta name='topic' content='College Technical Festival, Engineering Events, Student Competitions' />
<meta name='coverage' content='India' />
<meta name='distribution' content='global' />

{/* ── JSON-LD Structured Data ───────────────────────────── */}
{schemas.map((schema, i) => (
<script
key={`ld-${i}`}
type='application/ld+json'
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema).replace(/</g, '\u003c') }}

Check warning

Code scanning / CodeQL

Replacement of a substring with itself Medium

This replaces '<' with itself.

Copilot Autofix

AI 3 months ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

/>
Comment on lines +80 to +85

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dangerouslySetInnerHTML is injecting JSON.stringify(schema) directly into a <script> tag. If any schema value contains </script> or <, it can break out of the script context (JSON-LD XSS vector). Escape < (e.g., replace with \u003c) or use a safe serializer before injecting JSON-LD.

Copilot uses AI. Check for mistakes.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
))}
</Head>
)
}

export default SEOHead
47 changes: 47 additions & 0 deletions src/components/SEO/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* ┌──────────────────────────────────────────────────────────────────────────┐
* │ SEO Engine — Citronics 2026 │
* │ │
* │ Barrel export. Import per-page SEO components directly: │
* │ │
* │ import { HomeSEO } from 'src/components/SEO' │
* │ import { EventDetailSEO } from 'src/components/SEO' │
* │ │
* │ Structure: │
* │ SEO/ │
* │ ├── index.js ← this barrel file │
* │ ├── seo.config.js ← site identity, domain, social, geo │
* │ ├── schemas.js ← JSON-LD structured data builders │
* │ ├── SEOHead.js ← core <Head> component (internal) │
* │ └── pages/ │
* │ ├── HomeSEO.js ← <HomeSEO /> │
* │ ├── AboutSEO.js ← <AboutSEO /> │
* │ ├── EventsSEO.js ← <EventsSEO /> │
* │ ├── EventDetailSEO.js ← <EventDetailSEO event={...} /> │
* │ ├── GallerySEO.js ← <GallerySEO /> │
* │ ├── TeamSEO.js ← <TeamSEO /> │
* │ ├── CartSEO.js ← <CartSEO /> │
* │ ├── CheckoutSEO.js ← <CheckoutSEO /> │
* │ ├── LoginSEO.js ← <LoginSEO /> │
* │ └── RegisterSEO.js ← <RegisterSEO /> │
* └──────────────────────────────────────────────────────────────────────────┘
*/

// Per-page SEO components — one import, one JSX tag per page
export { default as HomeSEO } from './pages/HomeSEO'
export { default as AboutSEO } from './pages/AboutSEO'
export { default as EventsSEO } from './pages/EventsSEO'
export { default as EventDetailSEO } from './pages/EventDetailSEO'
export { default as GallerySEO } from './pages/GallerySEO'
export { default as TeamSEO } from './pages/TeamSEO'
export { default as CartSEO } from './pages/CartSEO'
export { default as CheckoutSEO } from './pages/CheckoutSEO'
export { default as LoginSEO } from './pages/LoginSEO'
export { default as RegisterSEO } from './pages/RegisterSEO'
export { default as TicketsSEO } from './pages/TicketsSEO'
export { default as TicketVerifySEO } from './pages/TicketVerifySEO'
export { default as PaymentStatusSEO } from './pages/PaymentStatusSEO'

// Low-level exports (for advanced use / sitemap / events/[id] getServerSideProps)
export { SITE, buildCanonical } from './seo.config'
export { eventSchema } from './schemas'
56 changes: 56 additions & 0 deletions src/components/SEO/pages/AboutSEO.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* AboutSEO — drop-in SEO for /about
*
* Schemas: Organization · festEvent · Breadcrumb · FAQ
* Target queries: "about Citronics", "CDGI fest info", "Citronics 2026 details"
*/
import SEOHead from '../SEOHead'
import {
organizationSchema,
festEventSchema,
breadcrumbSchema,
faqSchema,
} from '../schemas'

const ABOUT_FAQS = [
{
question: 'What is Citronics 2026?',
answer: 'Citronics 2026 is the flagship annual techno-management fest of Chameli Devi Group of Institutions (CDGI), Indore. It features 35+ competitions across AI, robotics, coding, management, and cultural events with 5000+ participants from colleges all over India.',
},
{
question: 'When and where is Citronics 2026 held?',
answer: 'Citronics 2026 takes place from April 7 to April 9, 2026 at the CDGI campus on Airport Road, Indore, Madhya Pradesh, India.',
},
{
question: 'How can I register for Citronics 2026?',
answer: 'Visit cdgicitronics.in, create a free account, browse all 35+ events, and register for the competitions you want to participate in. You can purchase tickets directly through the website.',
},
{
question: 'Is Citronics 2026 open to students from other colleges?',
answer: 'Yes, Citronics is a national-level fest open to students from all colleges and universities across India. Students from engineering, management, design, and other disciplines are welcome.',
},
{
question: 'What kind of events does Citronics have?',
answer: 'Citronics features technical events (AI/ML challenges, robotics, hackathons, coding battles), management case studies, cultural performances, debates, quizzes, workshops, keynote sessions, and more across 14+ departments.',
},
]

const AboutSEO = () => (
<SEOHead
title='About Citronics 2026 — CDGI Flagship Tech Fest | 35+ Events · 5000+ Participants · 3 Days'
description='Citronics is the annual techno-management fest of Chameli Devi Group of Institutions (CDGI), Indore. 35+ technical and cultural competitions, 5000+ student participants, 14+ departments, keynotes, workshops, and 3 packed days of innovation — April 7–9, 2026.'
keywords='about Citronics 2026, CDGI annual fest, Citronics 2026, Citronics 2k26, CDGI tech fest 2026, Chameli Devi Group of Institutions, CDGI Indore, Central India tech fest, Indore technical festival, CDGI departments, tech fest 3 days, Central India biggest college fest, what is Citronics, CDGI fest information, engineering fest MP'
canonicalPath='/about'
schemas={[
organizationSchema(),
festEventSchema(),
breadcrumbSchema([
{ name: 'Home', path: '/' },
{ name: 'About Citronics 2026', path: '/about' },
]),
faqSchema(ABOUT_FAQS),
]}
/>
)

export default AboutSEO
15 changes: 15 additions & 0 deletions src/components/SEO/pages/CartSEO.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* CartSEO — SEO for /cart (noindex — transactional page)
*/
import SEOHead from '../SEOHead'

const CartSEO = () => (
<SEOHead
title='Cart | Citronics 2026'
description='Review your selected event tickets for Citronics 2026 before proceeding to secure checkout.'
canonicalPath='/cart'
noIndex
/>
)

export default CartSEO
15 changes: 15 additions & 0 deletions src/components/SEO/pages/CheckoutSEO.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* CheckoutSEO — SEO for /checkout (noindex — transactional page)
*/
import SEOHead from '../SEOHead'

const CheckoutSEO = () => (
<SEOHead
title='Checkout | Citronics 2026'
description='Complete your registration and ticket purchase for Citronics 2026 events at CDGI, Indore.'
canonicalPath='/checkout'
noIndex
/>
)

export default CheckoutSEO
61 changes: 61 additions & 0 deletions src/components/SEO/pages/EventDetailSEO.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* EventDetailSEO — dynamic SEO for /events/[id]
*
* Accepts an event object (from getServerSideProps) and generates
* title, description, keywords, and JSON-LD dynamically.
*
* Schemas: Event (single) · Breadcrumb
*/
import SEOHead from '../SEOHead'
import { SITE } from '../seo.config'
import { eventSchema, breadcrumbSchema } from '../schemas'

/**
* @param {{ event: object|null }} props
* event — serialized event row from getServerSideProps (can be null)
*/
const EventDetailSEO = ({ event }) => {
if (!event) {
return (
<SEOHead
title='Event | Citronics 2026 — CDGI Tech Fest'
description='View event details, timings, venue, and registration info for this competition at Citronics 2026, CDGI Indore.'
canonicalPath='/events'
noIndex
/>
)
}

const { id, name, tagline, description, venue, department_name, ticket_price, banner_url } = event

const eventName = name || 'Event'
const dept = department_name ? ` · ${department_name}` : ''
const priceTag = ticket_price != null && ticket_price > 0 ? ` | ₹${ticket_price}` : ' | Free Entry'

// Build a natural description — crawlers and AI models prefer complete sentences
const rawDesc = tagline || description || ''
const pageDesc = rawDesc
? `${rawDesc.slice(0, 140).trim()}${rawDesc.length > 140 ? '…' : ''} — at Citronics 2026, CDGI Indore.`
: `${eventName} at Citronics 2026 — compete, collaborate and win at ${SITE.college}, Indore. ${department_name ? `Organised by ${department_name}.` : ''} April 7–9, 2026.`

return (
<SEOHead
title={`${eventName}${dept} | Citronics 2026 — CDGI Tech Fest${priceTag}`}
description={pageDesc.slice(0, 160)}
keywords={`${eventName}, ${department_name || 'CDGI'}, Citronics 2026 event, CDGI competition, ${venue || 'Indore'}, college tech fest event, register ${eventName}, Citronics 2k26`}
canonicalPath={`/events/${id}`}
ogType='article'
ogImage={banner_url || undefined}
schemas={[
eventSchema(event),
breadcrumbSchema([
{ name: 'Home', path: '/' },
{ name: 'Events', path: '/events' },
{ name: eventName, path: `/events/${id}` },
]),
]}
/>
)
}

export default EventDetailSEO
26 changes: 26 additions & 0 deletions src/components/SEO/pages/EventsSEO.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* EventsSEO — drop-in SEO for /events (listing page)
*
* Schemas: Organization · Breadcrumb
* Target queries: "Citronics events", "CDGI competitions 2026", "tech fest events Indore"
*/
import SEOHead from '../SEOHead'
import { organizationSchema, breadcrumbSchema } from '../schemas'

const EventsSEO = () => (
<SEOHead
title='Events & Competitions | Citronics 2026 — CDGI Tech Fest Indore'
description='Explore 35+ competitive events at Citronics 2026: AI/ML challenges, robotics, coding hackathons, management case studies, cultural performances, debates, quizzes, and workshops. CDGI, Indore — April 7–9, 2026. Filter by category and register online.'
keywords='events Citronics 2026, CDGI competitions 2026, technical events Indore, robotics competition, coding competition, hackathon CDGI, AI ML challenge 2026, management case study, cultural fest events, debate competition college, college tech fest events, national level technical fest events, hackathon Indore 2026, Citronics 2k26 events, CDGI event list'
canonicalPath='/events'
schemas={[
organizationSchema(),
breadcrumbSchema([
{ name: 'Home', path: '/' },
{ name: 'Events & Competitions', path: '/events' },
]),
]}
/>
)

export default EventsSEO
26 changes: 26 additions & 0 deletions src/components/SEO/pages/GallerySEO.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* GallerySEO — drop-in SEO for /gallery
*
* Schemas: ImageGallery · Breadcrumb
* Target queries: "Citronics photos", "CDGI fest gallery", "tech fest highlights"
*/
import SEOHead from '../SEOHead'
import { imageGallerySchema, breadcrumbSchema } from '../schemas'

const GallerySEO = () => (
<SEOHead
title='Gallery — Citronics 2026 | CDGI Tech Fest Photos, Highlights & Moments'
description="Browse photos and highlights from Citronics — CDGI annual tech fest in Indore. Explore event moments, cultural performances, workshops, competition finals, campus life, and behind-the-scenes captures from one of Central India's biggest college festivals."
keywords='Citronics gallery, CDGI fest photos, tech fest highlights, Citronics 2026 images, college fest moments 2026, CDGI campus photos, cultural fest Indore pictures, competition highlights, behind the scenes tech fest, Citronics 2k26 gallery'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
canonicalPath='/gallery'
schemas={[
imageGallerySchema(),
breadcrumbSchema([
{ name: 'Home', path: '/' },
{ name: 'Gallery', path: '/gallery' },
]),
]}
/>
)

export default GallerySEO
Loading
Loading