A comprehensive job portal built with Next.js 15, TypeScript, and Tailwind CSS. This application provides a complete solution for job seekers and employers to connect and manage job opportunities.
- Job Search & Discovery: Advanced search with filters for location, job type, experience level, and more
- Job Details: Comprehensive job descriptions with company information
- Application Management: Track application status and manage submissions
- User Profiles: Create and manage professional profiles with skills, experience, and education
- Application Tracking: Real-time status updates and interview scheduling
- Company Profiles: Showcase company culture, benefits, and job opportunities
- Job Posting: Create and manage job listings
- Application Review: Review and manage incoming applications
- Admin Dashboard: Comprehensive management interface for all platform activities
- Responsive Design: Mobile-first design that works on all devices
- Modern UI: Clean, professional interface with smooth animations
- Authentication: Secure login and registration system
- Search & Filters: Advanced filtering and search capabilities
- Real-time Updates: Live status updates and notifications
- Framework: Next.js 15 with App Router
- Language: TypeScript
- Styling: Tailwind CSS 4
- CMS: Contentstack (Headless CMS)
- Search: Algolia
- Database: NeonDB (PostgreSQL)
- Authentication: NextAuth.js
- Hosting: Contentstack Launch
- Icons: Lucide React
- State Management: React Hooks
- Date Handling: date-fns
This project leverages multiple Contentstack products and features for a complete headless CMS experience.
| Feature | Description | Files |
|---|---|---|
| Content Fetching | Fetch jobs, companies, blogs, homepage, navigation | lib/contentstack.ts |
| Query Operations | Filter content by URL, UID, slug | getPage(), getJobByUid(), getBlogBySlug() |
| Reference Resolution | Fetch linked company data for jobs | getJobs(), getJobByUid() |
| Multi-locale Support | Fetch content in English (en-us) and Hindi (hi-in) | getBlogs(locale), getBlogByUid(uid, locale) |
| Feature | Description | Files |
|---|---|---|
| Create Entries | Create notification entries programmatically | lib/contentstack-notifications.ts |
| Update Entries | Mark notifications as read | markNotificationAsReadInContentstack() |
| Delete Entries | Remove notifications | deleteNotificationFromContentstack() |
| Publish Entries | Auto-publish after create/update | createNotificationInContentstack() |
| Feature | Description | Files |
|---|---|---|
| User Attributes | Track time_on_site, has_clicked_apply_now, first_time_user | lib/contentstack-personalize.ts |
| Audiences | Match users to segments (e.g., "users_not_applied_30s", "First_time_users") | Personalize Dashboard |
| Experiences | Deliver personalized banner content based on user behavior | components/PersonalizedBanner.tsx |
| Event Tracking | Track banner impressions and CTA clicks | trackPersonalizeEvent() |
| Variant Content | Fetch personalized content for matched audiences | getPersonalizedContent() |
This project integrates Contentstack's Data & Insights (Lytics) for real-time behavior tracking and personalized experiences.
| Feature | Description | Files |
|---|---|---|
| Lytics Tracking Tag | Captures page views and custom events | app/layout.tsx |
| Behavior Tracking | Tracks job views, blog reads, applications, interests | lib/behavior-tracking.ts |
| Session Management | Tracks returning users and session counts | components/BehaviorTracker.tsx |
| Interest Profiling | Builds user interest profiles (categories, skills, locations) | lib/behavior-tracking.ts |
| Personalized Recommendations | Shows "Recommended For You" jobs based on behavior | components/RecommendedForYou.tsx |
| Event | Data Captured | Use Case |
|---|---|---|
job_view |
Job UID, title, category, skills, location, company | Build job interest profile |
blog_read |
Blog UID, title, category, tags | Understand content preferences |
job_application |
Job UID, title, company | Track conversion |
search |
Query, location, category filters | Understand search intent |
session_start |
Session count, returning user status | Segment new vs returning users |
User Behavior (Job Views, Blog Reads)
β
Lytics Tracking (jstag.send)
β
User Profile Built (localStorage + Lytics)
β
Personalize Attributes Updated
β
Audience Matching (Contentstack Personalize)
β
Personalized Content Delivered
| Webhook | Trigger | Action |
|---|---|---|
| New Job Notification | Job entry published | Sends email to all registered users |
| Automation | Trigger | Action |
|---|---|---|
| Application Confirmation Email | HTTP Request from /api/applications/submit |
Sends confirmation email to applicant |
| New Job Alert Email | HTTP Request from /api/webhooks/new-job |
Sends job alert to all users |
| Algolia Index Sync | Job entry publish event | Updates Algolia search index |
| Chatbot Context Feed | Webhook trigger | Feeds content context to AI chatbot |
| App | Purpose |
|---|---|
| Algolia | Search integration - syncs content types to Algolia for fast search |
| AI Chatbot | Chatbot fed with content context via Marketplace app and Automate webhook |
| Feature | Description | Implementation |
|---|---|---|
| Production Hosting | Deploy Next.js app | Automatic builds on push |
| Edge Functions | Run code at the edge | functions/[proxy].edge.js |
| Geolocation Headers | Automatic visitor location | visitor-ip-country, visitor-ip-region, visitor-ip-city |
| Location-Based Recommendations | Prioritize local jobs | /api/jobs/recommendations |
| Endpoint | Description |
|---|---|
/edge |
Returns top paths from Google Analytics for prefetching |
/edge/geo |
Returns visitor's geolocation (country, region, city) |
| Content Type | Purpose | Fields |
|---|---|---|
| Job | Job listings | title, description, requirements, responsibilities, company (ref), location, type, salary, skills, category, status |
| Company | Company profiles | title, description, location, industry, size, logo, benefits |
| Blog Post | Blog articles | title, slug, content, author, featured_image, category, tags |
| Homepage | Homepage content | hero_title, hero_subtitle, featured_jobs, stats |
| Navigation | Site navigation | nav_items (links array) |
| Notification | User notifications | user_email, type, title, message, read, metadata |
| Personalized Banner | Behavior-based banners | banner_title, banner_message, cta_text, cta_link, user_segment, enabled, priority |
βββ app/ # Next.js App Router pages
β βββ page.tsx # Homepage with hero section and featured jobs
β βββ jobs/ # Job-related pages
β β βββ page.tsx # Job listings with search and filters
β β βββ [id]/page.tsx # Individual job details and application form
β βββ companies/ # Company pages
β β βββ page.tsx # Company listings and profiles
β βββ applications/ # Application management
β β βββ page.tsx # User's application tracking
β βββ profile/ # User profile management
β β βββ page.tsx # User profile editing
β βββ login/ # Authentication
β β βββ page.tsx # Login page
β βββ register/ # User registration
β β βββ page.tsx # Registration page
β βββ admin/ # Admin dashboard
β β βββ page.tsx # Admin management interface
β βββ layout.tsx # Root layout with navigation
β βββ globals.css # Global styles and utilities
βββ components/ # Reusable React components
β βββ Navigation.tsx # Main navigation component
βββ lib/ # Utility functions and types
β βββ types.ts # TypeScript type definitions
β βββ utils.ts # Utility functions
β βββ contentstack.ts # CMS integration (legacy)
βββ package.json # Dependencies and scripts
- Modern UI: Clean, professional design with consistent spacing and typography
- Responsive Layout: Mobile-first approach with breakpoints for all screen sizes
- Interactive Elements: Hover effects, smooth transitions, and loading states
- Accessibility: Proper ARIA labels, keyboard navigation, and screen reader support
- Color Scheme: Professional blue and gray color palette
- Typography: Inter font family for excellent readability
- Node.js 18+
- npm or yarn
-
Clone the repository
git clone <repository-url> cd Aryan_project_DND
-
Install dependencies
npm install
-
Run the development server
npm run dev
-
Open your browser Navigate to http://localhost:3000
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLint
You can run the entire application using Docker and Docker Compose. This will set up both the Next.js application and a local PostgreSQL database.
- Docker and Docker Compose installed
-
Configure Environment Variables Ensure your
.env.local(or.env) file is populated with the required keys (Contentstack, Algolia, etc.). Docker Compose will pass these to the application. -
Run with Docker Compose
docker-compose up --build
-
Access the Application The application will be available at http://localhost:3000. The local PostgreSQL database will be initialized with the schema from
scripts/init-db.sql.
- app: Next.js 15 application running in a multi-stage production build.
- db: PostgreSQL 15 database for local user data and skills.
- Hero section with job search
- Featured job listings
- Company showcase
- Statistics and call-to-action sections
- Advanced job search with filters
- Job listings with pagination
- Sort by relevance, date, or salary
- Quick apply functionality
- Comprehensive job information
- Company details and culture
- Application form with file upload
- Related jobs suggestions
- Company directory with search
- Company profiles and job listings
- Industry and size filters
- Company culture and benefits
- Application status tracking
- Interview scheduling
- Application history
- Status updates and notifications
- User profile management
- Skills and experience editing
- Education and work history
- Job preferences and settings
- AI-Powered Job Recommendations based on user skills
The application uses Algolia Search combined with Launch Geolocation Headers to provide personalized job recommendations based on user skills AND location.
- User adds skills to their profile
- Skills are saved to NeonDB
- When user clicks "Find Matching Jobs", skills are sent to Algolia
- Launch automatically injects visitor geolocation (country, region, city)
- Jobs are scored by both skill match AND location proximity
- Results are re-ranked to prioritize local jobs
- β Fuzzy matching (handles typos)
- β OR logic (matches jobs with ANY skill)
- β Match score ranking
- β Highlights matching skills
- β Location-based prioritization (city > region > country)
- β Automatic geolocation via Launch headers
- β Remote job boosting for all visitors
When deployed on Contentstack Launch, these headers are automatically injected:
| Header | Description | Example |
|---|---|---|
visitor-ip-country |
ISO 2-letter country code | US, IN, GB |
visitor-ip-region |
Region/state name | California, Karnataka |
visitor-ip-city |
City name | San Francisco, Bangalore |
Jobs are ranked using a combined score:
- Skill Match (60%): How well the job matches user's skills
- Location Match (40%): How close the job is to the visitor
- City match: 1.0
- Region match: 0.8
- Country match: 0.6
- Remote jobs: 0.3 (base boost)
- Create an Algolia account at algolia.com
- Create an index named
job - Configure searchable attributes:
title,description,skillNames,skillsText,category - Sync jobs using
/api/jobs/sync-algoliaendpoint - Add environment variables:
NEXT_PUBLIC_ALGOLIA_APP_ID=your-app-id
NEXT_PUBLIC_ALGOLIA_SEARCH_KEY=your-search-key
NEXT_PUBLIC_ALGOLIA_INDEX_NAME=job- Secure login and registration
- Social login options
- Password strength validation
- Terms and conditions
- Job management interface
- Application review system
- Company management
- User administration
- Analytics and reporting
- Protected by Edge Function - Requires username/password authentication
The /admin route is protected using a Next.js Edge Function (middleware) with Basic HTTP Authentication.
When accessing /admin:
- Edge function intercepts the request
- Checks for Basic Auth credentials
- Shows browser login prompt if not authenticated
- Grants access only with valid credentials
Set these environment variables:
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your-secure-password- β Runs at the edge (fast, before page loads)
- β Browser-native login prompt
- β No credentials stored in frontend
- β Works with Contentstack Launch
The application uses Tailwind CSS for styling. Custom styles are defined in app/globals.css:
- Custom utility classes
- Animation keyframes
- Gradient backgrounds
- Hover effects
- Responsive breakpoints
Reusable components are located in the components/ directory:
Navigation.tsx- Main navigation with responsive mobile menu- Additional components can be added as needed
TypeScript types are defined in lib/types.ts:
- Job, Company, User, Application interfaces
- Search filters and result types
- Form data types
- API response types
npm run build- Connect your repository to Vercel
- Configure environment variables if needed
- Deploy automatically on push to main branch
Copy env.example to .env.local and fill in your values:
cp env.example .env.localRequired environment variables:
# NextAuth Configuration
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key-here
# Google OAuth Configuration
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# Database Configuration (NeonDB PostgreSQL)
DATABASE_URL=postgresql://[user]:[password]@[host]/[database]?sslmode=require
# Algolia Search Configuration
NEXT_PUBLIC_ALGOLIA_APP_ID=your-algolia-app-id
NEXT_PUBLIC_ALGOLIA_SEARCH_KEY=your-search-only-api-key
NEXT_PUBLIC_ALGOLIA_INDEX_NAME=job
# Admin Panel Protection
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your-secure-admin-password
# Contentstack Automate - Email Notifications
CONTENTSTACK_AUTOMATE_WEBHOOK_URL=https://app.contentstack.com/automations-api/run/your-application-webhook
CONTENTSTACK_NEW_JOB_EMAIL_WEBHOOK=https://app.contentstack.com/automations-api/run/your-new-job-webhook
CONTENTSTACK_WEBHOOK_SECRET=your-webhook-secret
# Contentstack AI Chatbot Widget (optional)
NEXT_PUBLIC_CHATBOT_WIDGET_URL=https://chatbot-marketplace-try.contentstackapps.com/chatbot-widget.js?site_key=your-site-keyThe application includes automated email notifications powered by Contentstack Automate.
| Email Type | Trigger | Recipients |
|---|---|---|
| Application Confirmation | User submits job application | Applicant |
| New Job Alert | Admin publishes new job in CMS | All registered users |
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββ
β New Job ββββββΆβ Contentstack ββββββΆβ Our API ββββββΆβ Automate β
β Published β β Webhook β β /api/webhooks β β Email β
β in CMS β β β β /new-job β β β
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β NeonDB β
β (Get all users)β
βββββββββββββββββββ
- Go to Contentstack β Automate β Create New Automation
- Add HTTP Request Trigger (Step 1)
- Add Email By Automate action (Step 2)
- Configure the email:
To: {{1.body.recipient_email}}
Subject: π New Job Alert: {{1.body.job_title}}
Body Type: HTML
Body:
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; }
.header { background: linear-gradient(135deg, #10b981, #059669); color: white; padding: 30px; text-align: center; border-radius: 8px 8px 0 0; }
.content { background: #f9fafb; padding: 30px; border: 1px solid #e5e7eb; }
.job-card { background: white; padding: 25px; margin: 20px 0; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.cta-button { display: inline-block; background: #2563eb; color: white; padding: 14px 32px; text-decoration: none; border-radius: 8px; font-weight: bold; }
</style>
</head>
<body>
<div class="header">
<h1>π New Job Posted!</h1>
</div>
<div class="content">
<p>Hi {{1.body.recipient_name}},</p>
<div class="job-card">
<h2>{{1.body.job_title}}</h2>
<p>π {{1.body.job_location}} | πΌ {{1.body.job_type}} | π° {{1.body.job_salary}}</p>
<a href="{{1.body.job_url}}" class="cta-button">View Job β</a>
</div>
</div>
</body>
</html>- Activate the Automation
- Copy the HTTP Request Trigger URL to
CONTENTSTACK_NEW_JOB_EMAIL_WEBHOOK
- Go to Contentstack β Settings β Webhooks
- Create new webhook:
- Name:
New Job Notification - URL:
https://your-domain.com/api/webhooks/new-job - Events: Entry β Publish β Job content type
- Headers: Add
x-webhook-secret: your-secret
- Name:
curl -X POST "https://app.contentstack.com/automations-api/run/YOUR_WEBHOOK_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient_email": "test@example.com",
"recipient_name": "Test User",
"job_title": "Software Developer",
"job_location": "San Francisco, CA",
"job_type": "Full-time",
"job_experience": "Mid-Senior",
"job_salary": "$120,000 - $150,000",
"is_remote": "Yes",
"job_url": "https://yoursite.com/jobs/123",
"notification_date": "December 6, 2024"
}'| Endpoint | Method | Description |
|---|---|---|
/api/webhooks/new-job |
POST | Receives Contentstack webhook when job is published |
/api/applications/submit |
POST | Submits job application and sends confirmation email |
/api/jobs/recommendations |
POST | Get job recommendations with location prioritization |
/edge/geo |
GET | Returns visitor geolocation (Launch edge function) |
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable the Google+ API
- Go to "Credentials" and create OAuth 2.0 Client IDs
- Set authorized redirect URIs to:
http://localhost:3000/api/auth/callback/google(for development)https://yourdomain.com/api/auth/callback/google(for production)
- Copy the Client ID and Client Secret to your
.env.localfile
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Next.js team for the amazing framework
- Tailwind CSS for the utility-first CSS framework
- Lucide for the beautiful icon set
- The open-source community for inspiration and tools
JobPortal - Connecting talent with opportunity, one job at a time.