Skip to content
Merged
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
9 changes: 9 additions & 0 deletions .gitconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[core]
hooksPath = .husky
ignorecase = false

[hooks]
enforceForAll = true

[receive]
denyNonFastForwards = true
54 changes: 54 additions & 0 deletions .github/workflows/branch-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Branch Name Check

on:
push:
branches-ignore:
- main
- develop
pull_request:
branches:
- main
- develop

jobs:
check-branch-name:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Check branch name
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
BRANCH="${{ github.head_ref }}"
else
BRANCH=${GITHUB_REF#refs/heads/}
fi

if [[ ! $BRANCH =~ ^[a-zA-Z0-9]+/[a-zA-Z0-9-]+$ ]]; then
echo "🚫 Branch name validation failed"
echo "Branch: $BRANCH"
echo "Required format: username/feature-name"
exit 1
fi
echo "✅ Branch name follows convention: $BRANCH"

validate-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'

- name: Install commitlint
run: |
npm install --save-dev @commitlint/cli @commitlint/config-conventional

- name: Check commit message
run: |
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
git log -1 --pretty=format:"%s" | npx commitlint
16 changes: 10 additions & 6 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# #!/usr/bin/env sh
# . "$(dirname -- "$0")/_/husky.sh"
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# Validate commit message format
npx --no -- commitlint --edit "$1"
Expand All @@ -9,10 +9,14 @@ BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
BRANCH_PATTERN="^[a-zA-Z0-9]+/[a-zA-Z0-9-]+$"

if ! echo "$BRANCH_NAME" | grep -E "$BRANCH_PATTERN" > /dev/null; then
echo "🚫 Branch name must follow pattern: username/feature-name"
echo "❌ Your branch name: $BRANCH_NAME"
echo "✅ Example: john/add-footer"
echo "🚫 Branch name validation failed"
echo "Branch: $BRANCH_NAME"
echo "Required format: username/feature-name"
echo "Examples:"
echo "✅ john/add-footer"
echo "✅ jane/fix-auth"
echo "❌ feature-only"
echo "❌ MainBranch"
exit 1
fi

echo "✅ Branch name follows convention: $BRANCH_NAME"
17 changes: 17 additions & 0 deletions .husky/pre-receive
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh

# Enforce branch naming
while read oldrev newrev refname; do
branch=$(echo "$refname" | sed -n 's|refs/heads/||p')
if [[ ! $branch =~ ^[a-zA-Z0-9]+/[a-zA-Z0-9-]+$ ]]; then
echo "🚫 ERROR: Branch '$branch' does not follow naming convention"
echo "✅ Required format: username/feature-name"
exit 1
fi
done

# Block force pushes
if git rev-list $newrev..$oldrev >/dev/null 2>&1; then
echo "🚫 Force pushes are not allowed"
exit 1
fi
9 changes: 5 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ FROM node:18-alpine AS deps
WORKDIR /app

# Install dependencies needed for build
RUN apk add --no-cache libc6-compat
RUN apk add --no-cache libc6-compat git

# Copy package files
COPY package.json package-lock.json ./
COPY package*.json ./

# Install dependencies
RUN npm ci
# Install dependencies (without husky)
RUN npm ci --ignore-scripts

# Stage 2: Builder
FROM node:18-alpine AS builder
Expand All @@ -22,6 +22,7 @@ COPY . .
# Set environment variables for build
ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_ENV production
ENV HUSKY 0

# Build application
RUN npm run build
Expand Down
58 changes: 42 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ npm install
3. **Run development server**
```bash
npm run dev
# or with Docker
docker compose up --build
```

Open [http://localhost:3000](http://localhost:3000) to view the project.
Expand All @@ -27,43 +29,67 @@ Open [http://localhost:3000](http://localhost:3000) to view the project.
### Prerequisites
- Node.js (v18 or higher)
- npm (v9 or higher)
- Docker (optional)

### Environment Setup
1. Copy the environment template:
```bash
cp .env.example .env.local
cp .env.example .env.production
```

2. Install husky hooks:
```bash
npm run prepare
git config core.hooksPath .husky
```

## 🐳 Docker

### Build and Run
```bash
docker compose up --build
```

### Environment Variables
Required in `.env.production`:
```env
GOOGLE_CLIENT_ID=your_client_id
GOOGLE_CLIENT_SECRET=your_client_secret
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your_secret
POSTHOG_KEY=your_key
POSTHOG_HOST=your_host
```

## 📝 Contributing

### Strict Git Enforcement
All commits and branches are strictly enforced through:
- Local git hooks (husky)
- Server-side hooks
- GitHub Actions
- GUI client configurations

### Branch Naming Convention
All branches must follow the pattern:
```
username/feature-name
```
Example: `john/add-ai-page`

### Pre-commit Checks
Before committing, ensure:
1. Code is linted and formatted:
```bash
npm run lint
```

2. TypeScript types are valid:
```bash
npm run type-check
```
Enforcement:
- Pre-receive hooks
- GitHub Actions
- Local git hooks
- No force pushes allowed

3. Build succeeds:
```bash
npm run build
```
### Pre-commit Checks
Before committing, the following are automatically enforced:
1. Code linting and formatting
2. TypeScript type checking
3. Successful build
4. Branch name validation
5. Commit message format

### Commit Message Format
Follow the conventional commits specification:
Expand Down
74 changes: 44 additions & 30 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Montserrat } from 'next/font/google';
import { PostHogProvider } from '@/components/providers/PostHogProvider'
import { PostHogPageview } from '@/components/PostHogPageview'
import { NextAuthProvider } from '@/components/providers/NextAuthProvider'
import { websiteSchema, organizationSchema } from './schema'

const geistSans = localFont({
src: "./fonts/GeistVF.woff",
Expand All @@ -25,46 +26,45 @@ const montserrat = Montserrat({
export const metadata: Metadata = {
metadataBase: new URL('https://coc-landing.vercel.app'),
title: {
default: "VJTI Resources & Communities",
template: "%s | VJTI Resources"
},
description: "Access curated educational resources, join tech communities, and connect with VJTI's developer ecosystem. Features AI, Web Dev, CP, and academic materials.",
keywords: ["VJTI", "education", "resources", "developer communities", "engineering", "tech clubs", "Mumbai","AI","Web Dev","CP","academic materials","coc","coding"],
authors: [{ name: "VJTI Resources Team" }],
openGraph: {
type: "website",
locale: "en_IN",
url: "https://coc-landing.vercel.app",
siteName: "VJTI Resources",
images: [{
url: "/coc_vjti.jpeg",
width: 1200,
height: 630,
alt: "VJTI Resources & Communities Logo"
}],
},
twitter: {
card: "summary_large_image",
site: "@vjti_resources",
images: "/coc_vjti.jpeg",
},
icons: {
icon: "/coc_vjti.jpeg",
default: "Community of Coders VJTI | COC Landing",
template: "%s | Community of Coders VJTI"
},
description: "Access curated educational resources, join tech communities, and explore learning paths for Web Development, AI/ML, Competitive Programming at VJTI.",
keywords: ["VJTI", "COC", "tech communities", "educational resources", "web development", "AI/ML", "competitive programming", "student clubs"],
authors: [{ name: "Community of Coders" }],
creator: "Community of Coders VJTI",
publisher: "VJTI",
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-video-preview": -1,
"max-image-preview": "large",
"max-snippet": -1,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
verification: {
google: "your-google-verification-code",
openGraph: {
type: 'website',
locale: 'en_US',
url: 'https://coc-landing.vercel.app',
title: 'Community of Coders VJTI',
description: 'Access curated educational resources and join tech communities at VJTI.',
siteName: 'Community of Coders VJTI',
},
twitter: {
card: 'summary_large_image',
title: 'Community of Coders VJTI',
description: 'Access curated educational resources and join tech communities at VJTI.',
creator: '@COC_VJTI',
},
alternates: {
canonical: 'https://coc-landing.vercel.app',
},
verification: {
google: 'your-google-verification-code',
}
};

export default function RootLayout({
Expand All @@ -74,6 +74,20 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(websiteSchema)
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(organizationSchema)
}}
/>
</head>
<body
className={`${geistSans.variable} ${geistMono.variable} ${montserrat.variable} antialiased`}
>
Expand Down
23 changes: 23 additions & 0 deletions app/schema.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const websiteSchema = {
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Community of Coders VJTI",
"url": "https://coc-landing.vercel.app",
"potentialAction": {
"@type": "SearchAction",
"target": "https://coc-landing.vercel.app/search?q={search_term_string}",
"query-input": "required name=search_term_string"
}
};

export const organizationSchema = {
"@context": "https://schema.org",
"@type": "Organization",
"name": "Community of Coders VJTI",
"url": "https://coc-landing.vercel.app",
"logo": "https://coc-landing.vercel.app/logo.png",
"sameAs": [
"https://www.linkedin.com/company/community-of-coders-vjti",
"https://github.com/Community-Of-Coders"
]
};
1 change: 0 additions & 1 deletion app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { domains } from '@/config/navigation'
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = 'https://coc-landing.vercel.app'

// Base routes
const routes = [
'',
'/about',
Expand Down
Loading
Loading