ALX Project Nexus is a comprehensive job board platform built with Django and Django REST Framework. The platform connects job seekers with employers through a robust API that handles the complete job application lifecycle. The system features three distinct user roles (Admin, Employer, and Job Seeker), each with specific permissions and capabilities.
The platform enables employers to create company profiles, manage multiple job locations, and post job openings across various industries. Job seekers can browse available positions, submit applications with resumes and cover letters, and track their application status in real-time. Employers can review applications, update candidate status, and manage their hiring pipeline efficiently.
Built with security and scalability in mind, the API uses JWT token authentication, implements role-based access control, and follows RESTful design principles. The modular architecture is organized into three main applications: Accounts (user management), Jobs (job posting and company management), and Applications (application tracking and review).
- Backend Framework: Django 4.x
- API Framework: Django REST Framework
- Authentication: JWT (djangorestframework-simplejwt)
- API Documentation: drf-yasg (Swagger/OpenAPI)
- Database: PostgreSQL/MySQL (configurable, SQLite for development)
- File Storage: Django File Storage
- Filtering: django-filter
alx-project-nexus/
├── accounts/ # User authentication and profiles
│ ├── models.py # User and UserProfile models
│ ├── serializers.py # Authentication serializers
│ ├── views.py # Register and Login viewsets
│ ├── urls.py # Authentication routes
│ └── permissions.py # Custom permissions
├── applications/ # Job application management
│ ├── models.py # ApplyJob model
│ ├── serializers.py # Application serializers
│ ├── views.py # Application viewsets
│ ├── urls.py # Application routes
│ └── permissions.py # Application permissions
├── jobs/ # Job posting and management
│ ├── models.py # Industry, Location, Company, Job models
│ ├── serializers.py # Job-related serializers
│ ├── views.py # Job management viewsets
│ ├── urls.py # Job routes
│ └── permissions.py # Job permissions
├── requirements.txt # Project dependencies
└── manage.py
- Python 3.8+
- pip
- Virtual environment (recommended)
- PostgreSQL/MySQL (optional, SQLite works for development)
- Clone the repository
git clone [email protected]:LinusBwana/alx-project-nexus.git
cd alx-project-nexus- Create and activate virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate- Install dependencies
pip install -r requirements.txt-
Configure database settings Edit
settings.pyto configure your database connection. -
Run migrations
python manage.py makemigrations
python manage.py migrate- Create superuser
python manage.py createsuperuser- Run development server
python manage.py runserverThe API will be available at http://localhost:8000/
Main urls.py:
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
schema_view = get_schema_view(
openapi.Info(
title="ALX Project Nexus",
default_version='v1',
description="Backend for a Job Board Platform - ProDev BE",
),
public=True,
permission_classes=(permissions.AllowAny,),
)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/auth/', include('accounts.urls')),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/jobs/', include('jobs.urls')),
path('api/applications/', include('applications.urls')),
# Swagger urls
path('api/docs/.<format>/', schema_view.without_ui(cache_timeout=0), name='schema-json'),
path('api/docs/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)accounts/urls.py:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import RegisterViewSet, LoginViewSet
router = DefaultRouter()
router.register(r'register', RegisterViewSet, basename='register')
router.register(r'login', LoginViewSet, basename='login')
urlpatterns = [
path('', include(router.urls)),
]Endpoints:
POST /api/auth/register/- User registrationPOST /api/auth/login/- User loginPOST /api/token/- Obtain JWT tokenPOST /api/token/refresh/- Refresh JWT token
jobs/urls.py:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import IndustryViewset, LocationViewset, CompanyViewset, PostJobViewset, AvailableJobsViewset
router = DefaultRouter()
router.register(r'industries', IndustryViewset, basename='industries')
router.register(r'locations', LocationViewset, basename='locations')
router.register(r'companies', CompanyViewset, basename='companies')
router.register(r'postjobs', PostJobViewset, basename='postjobs')
router.register(r'availablejobs', AvailableJobsViewset, basename='availablejobs')
urlpatterns = [
path('', include(router.urls)),
]Endpoints:
GET /api/jobs/industries/- List all industries (Admin only)POST /api/jobs/industries/- Create industry (Admin only)GET /api/jobs/industries/{id}/- Retrieve industry (Admin only)PUT/PATCH /api/jobs/industries/{id}/- Update industry (Admin only)DELETE /api/jobs/industries/{id}/- Delete industry (Admin only)GET /api/jobs/locations/- List user's locations (Employer only)POST /api/jobs/locations/- Create location (Employer only)GET /api/jobs/locations/{id}/- Retrieve location (Employer only)PUT/PATCH /api/jobs/locations/{id}/- Update location (Employer only)DELETE /api/jobs/locations/{id}/- Delete location (Employer only)GET /api/jobs/companies/- List user's companies (Employer only)POST /api/jobs/companies/- Create company (Employer only)GET /api/jobs/companies/{id}/- Retrieve company (Employer only)PUT/PATCH /api/jobs/companies/{id}/- Update company (Employer only)DELETE /api/jobs/companies/{id}/- Delete company (Employer only)GET /api/jobs/postjobs/- List user's posted jobs (Employer only)POST /api/jobs/postjobs/- Create job posting (Employer only)GET /api/jobs/postjobs/{id}/- Retrieve job (Employer only)PUT/PATCH /api/jobs/postjobs/{id}/- Update job (Employer only)DELETE /api/jobs/postjobs/{id}/- Delete job (Employer only)GET /api/jobs/availablejobs/- List all active jobs (Public)GET /api/jobs/availablejobs/{id}/- Retrieve job details (Public)
applications/urls.py:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ApplyJobViewset, MyApplicationHistoryViewset, JobApplicationsHistoryViewset
router = DefaultRouter()
router.register(r'apply-job', ApplyJobViewset, basename='apply-job')
router.register(r'my-applications-history', MyApplicationHistoryViewset, basename='my-applications')
router.register(r'job-applications-history', JobApplicationsHistoryViewset, basename='job-applications')
urlpatterns = [
path('', include(router.urls)),
]Endpoints:
POST /api/applications/apply-job/- Submit job application (Job Seeker only)GET /api/applications/my-applications-history/- View own applications (Job Seeker only)GET /api/applications/my-applications-history/{id}/- View application details (Job Seeker only)GET /api/applications/job-applications-history/- View applications to own jobs (Employer only)GET /api/applications/job-applications-history/{id}/- View application details (Employer only)PUT/PATCH /api/applications/job-applications-history/{id}/- Update application status (Employer only)
Endpoint: POST /api/auth/register/
Request:
{
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"phone_number": "+254712345678",
"role": "job_seeker",
"password": "SecurePass123!",
"confirm_password": "SecurePass123!"
}Response: 201 Created
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"phone_number": "+254712345678",
"role": "job_seeker"
}Endpoint: POST /api/auth/login/
Request:
{
"username": "johndoe",
"password": "SecurePass123!"
}Response: 200 OK
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTczMjM5NjgwMCwiaWF0IjoxNzMyMzEwNDAwLCJqdGkiOiJhYmNkZWYxMjM0NTYiLCJ1c2VyX2lkIjoiYTFiMmMzZDQtZTVmNi03ODkwLWFiY2QtZWYxMjM0NTY3ODkwIn0.xyz123abc456",
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzMyMzE0MDAwLCJpYXQiOjE3MzIzMTA0MDAsImp0aSI6ImFiY2RlZjEyMzQ1NiIsInVzZXJfaWQiOiJhMWIyYzNkNC1lNWY2LTc4OTAtYWJjZC1lZjEyMzQ1Njc4OTAifQ.abc123xyz456",
"user": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"phone_number": "+254712345678",
"role": "job_seeker"
}
}Endpoint: GET /api/jobs/availablejobs/
Response: 200 OK
[
{
"id": "job123-uuid-here",
"title": "Senior Software Engineer",
"slug": "senior-software-engineer-tech-innovations-ltd-a1b2",
"company": "company123-uuid-here",
"industry": "industry123-uuid-here",
"location": ["location123-uuid-here"],
"job_type": "full_time",
"experience_level": "senior",
"description": "We are looking for an experienced software engineer...",
"requirements": "Bachelor's degree in Computer Science, 5+ years of experience...",
"responsibilities": "Design and develop scalable applications, Lead technical projects...",
"skills_required": "Python, Django, REST API, PostgreSQL, Docker",
"salary_min": "100000.00",
"salary_max": "150000.00",
"salary_currency": "KES",
"is_salary_visible": true,
"posted_by": "employer123-uuid-here",
"is_active": true,
"application_deadline": "2025-12-31",
"posted_on": "2025-11-15T10:30:00Z",
"updated_on": "2025-11-15T10:30:00Z"
},
{
"id": "job456-uuid-here",
"title": "Frontend Developer",
"slug": "frontend-developer-creative-agency-x9y8",
"company": "company456-uuid-here",
"industry": "industry456-uuid-here",
"location": ["location456-uuid-here"],
"job_type": "full_time",
"experience_level": "mid_level",
"description": "Join our creative team to build amazing user experiences...",
"requirements": "3+ years experience with React, Strong CSS skills...",
"responsibilities": "Build responsive web applications, Collaborate with designers...",
"skills_required": "React, TypeScript, CSS, HTML, Git",
"salary_min": "70000.00",
"salary_max": "100000.00",
"salary_currency": "KES",
"is_salary_visible": true,
"posted_by": "employer456-uuid-here",
"is_active": true,
"application_deadline": "2025-11-30",
"posted_on": "2025-11-10T14:20:00Z",
"updated_on": "2025-11-10T14:20:00Z"
}
]Endpoint: POST /api/jobs/industries/
Headers:
Authorization: Bearer {access_token}
Request:
{
"name": "Information Technology",
"description": "Technology and software development sector including hardware, software, and IT services"
}Response: 201 Created
{
"id": "industry123-uuid-here",
"name": "Information Technology",
"slug": "information-technology",
"description": "Technology and software development sector including hardware, software, and IT services",
"is_active": true,
"created_at": "2025-11-15T09:00:00Z",
"updated_at": "2025-11-15T09:00:00Z"
}Error Response (Non-Admin User): 403 Forbidden
{
"detail": "You do not have permission to perform this action."
}Endpoint: POST /api/jobs/locations/
Headers:
Authorization: Bearer {access_token}
Request:
{
"country": "Kenya",
"city": "Nairobi",
"region": "Nairobi County",
"is_remote": false
}Response: 201 Created
{
"id": "location123-uuid-here",
"country": "Kenya",
"city": "Nairobi",
"region": "Nairobi County",
"is_remote": false,
"created_at": "2025-11-15T10:00:00Z"
}Endpoint: GET /api/jobs/locations/
Headers:
Authorization: Bearer {access_token}
Response: 200 OK
[
{
"id": "location123-uuid-here",
"country": "Kenya",
"city": "Nairobi",
"region": "Nairobi County",
"is_remote": false,
"created_at": "2025-11-15T10:00:00Z"
},
{
"id": "location456-uuid-here",
"country": "Kenya",
"city": "Mombasa",
"region": "Mombasa County",
"is_remote": false,
"created_at": "2025-11-16T11:00:00Z"
}
]Endpoint: POST /api/jobs/companies/
Headers:
Authorization: Bearer {access_token}
Content-Type: multipart/form-data
Request:
{
"name": "Tech Innovations Ltd",
"description": "Leading technology company specializing in cloud solutions and enterprise software",
"website_url": "https://techinnovations.com",
"industry": "industry123-uuid-here",
"locations": ["location123-uuid-here", "location456-uuid-here"]
}Response: 201 Created
{
"id": "company123-uuid-here",
"name": "Tech Innovations Ltd",
"slug": "tech-innovations-ltd-leading-technology-company-spec-z9x8",
"locations": ["location123-uuid-here", "location456-uuid-here"],
"description": "Leading technology company specializing in cloud solutions and enterprise software",
"logo": null,
"website_url": "https://techinnovations.com",
"industry": "industry123-uuid-here",
"is_verified": false,
"created_at": "2025-11-15T11:00:00Z",
"updated_at": "2025-11-15T11:00:00Z",
"created_by": "employer123-uuid-here"
}Error Response (No Locations Created): 403 Forbidden
{
"detail": "You do not have permission to perform this action."
}Endpoint: POST /api/jobs/postjobs/
Headers:
Authorization: Bearer {access_token}
Request:
{
"title": "Senior Software Engineer",
"company": "company123-uuid-here",
"location": ["location123-uuid-here"],
"job_type": "full_time",
"experience_level": "senior",
"description": "We are looking for an experienced software engineer to join our growing team...",
"requirements": "Bachelor's degree in Computer Science or related field, 5+ years of software development experience, Strong problem-solving skills",
"responsibilities": "Design and develop scalable applications, Lead technical projects, Mentor junior developers, Code review and quality assurance",
"skills_required": "Python, Django, REST API, PostgreSQL, Docker, AWS",
"salary_min": "100000.00",
"salary_max": "150000.00",
"salary_currency": "KES",
"is_salary_visible": true,
"application_deadline": "2025-12-31"
}Response: 201 Created
{
"id": "job123-uuid-here",
"title": "Senior Software Engineer",
"slug": "senior-software-engineer-tech-innovations-ltd-a1b2",
"company": "company123-uuid-here",
"industry": "industry123-uuid-here",
"location": ["location123-uuid-here"],
"job_type": "full_time",
"experience_level": "senior",
"description": "We are looking for an experienced software engineer to join our growing team...",
"requirements": "Bachelor's degree in Computer Science or related field, 5+ years of software development experience, Strong problem-solving skills",
"responsibilities": "Design and develop scalable applications, Lead technical projects, Mentor junior developers, Code review and quality assurance",
"skills_required": "Python, Django, REST API, PostgreSQL, Docker, AWS",
"salary_min": "100000.00",
"salary_max": "150000.00",
"salary_currency": "KES",
"is_salary_visible": true,
"posted_by": "employer123-uuid-here",
"is_active": true,
"application_deadline": "2025-12-31",
"posted_on": "2025-11-15T12:00:00Z",
"updated_on": "2025-11-15T12:00:00Z"
}Error Response (No Company Created): 403 Forbidden
{
"detail": "You do not have permission to perform this action."
}Endpoint: POST /api/applications/apply-job/
Headers:
Authorization: Bearer {access_token}
Content-Type: multipart/form-data
Request:
{
"job": "job123-uuid-here",
"cover_letter": "I am writing to express my strong interest in the Senior Software Engineer position at Tech Innovations Ltd. With over 6 years of experience in software development and a proven track record of delivering high-quality solutions...",
"resume": "file_upload_here.pdf",
"additional_documents": "portfolio_file.pdf",
"experience_years": 6,
"expected_salary": "130000.00",
"availability_date": "2026-01-15"
}Response: 201 Created
{
"id": "application123-uuid-here",
"job": "job123-uuid-here",
"applicant": "jobseeker123-uuid-here",
"status": "pending",
"cover_letter": "I am writing to express my strong interest in the Senior Software Engineer position at Tech Innovations Ltd. With over 6 years of experience in software development and a proven track record of delivering high-quality solutions...",
"resume": "/media/application_documents/user_jobseeker123-uuid-here/resume_john_doe.pdf",
"additional_documents": "/media/application_documents/user_jobseeker123-uuid-here/portfolio.pdf",
"experience_years": 6,
"expected_salary": "130000.00",
"availability_date": "2026-01-15",
"reviewed_by": null,
"reviewed_at": null,
"applied_on": "2025-11-19T14:30:00Z"
}Error Response (Employer Trying to Apply): 403 Forbidden
{
"detail": "You do not have permission to perform this action."
}Endpoint: GET /api/applications/my-applications-history/
Headers:
Authorization: Bearer {access_token}
Response: 200 OK
[
{
"id": "application123-uuid-here",
"job_title": "Senior Software Engineer",
"company_name": "Tech Innovations Ltd",
"job_location": "Kenya, Nairobi, Nairobi County",
"status": "pending"
},
{
"id": "application456-uuid-here",
"job_title": "Frontend Developer",
"company_name": "Creative Agency",
"job_location": "Kenya, Mombasa, Mombasa County",
"status": "reviewed"
},
{
"id": "application789-uuid-here",
"job_title": "DevOps Engineer",
"company_name": "Cloud Solutions Inc",
"job_location": "Kenya, Nairobi, Nairobi County - Remote",
"status": "shortlisted"
}
]Endpoint: GET /api/applications/job-applications-history/
Headers:
Authorization: Bearer {access_token}
Response: 200 OK
[
{
"id": "application123-uuid-here",
"job": "job123-uuid-here",
"job_title": "Senior Software Engineer",
"applicant_name": "John Doe",
"applicant_email": "[email protected]",
"job_location": "Kenya, Nairobi, Nairobi County",
"status": "pending",
"applied_on": "2025-11-19T14:30:00Z",
"experience_years": 6,
"expected_salary": "130000.00",
"cover_letter": "I am writing to express my strong interest in the Senior Software Engineer position...",
"resume": "/media/application_documents/user_jobseeker123-uuid-here/resume_john_doe.pdf"
},
{
"id": "application456-uuid-here",
"job": "job123-uuid-here",
"job_title": "Senior Software Engineer",
"applicant_name": "Jane Smith",
"applicant_email": "[email protected]",
"job_location": "Kenya, Nairobi, Nairobi County",
"status": "reviewed",
"applied_on": "2025-11-18T10:15:00Z",
"experience_years": 7,
"expected_salary": "140000.00",
"cover_letter": "With 7 years of experience in full-stack development...",
"resume": "/media/application_documents/user_jobseeker456-uuid-here/resume_jane_smith.pdf"
}
]Endpoint: PATCH /api/applications/job-applications-history/{application_id}/
Headers:
Authorization: Bearer {access_token}
Request:
{
"status": "shortlisted"
}Response: 200 OK
{
"id": "application123-uuid-here",
"job": "job123-uuid-here",
"job_title": "Senior Software Engineer",
"applicant_name": "John Doe",
"applicant_email": "[email protected]",
"job_location": "Kenya, Nairobi, Nairobi County",
"status": "shortlisted",
"applied_on": "2025-11-19T14:30:00Z",
"experience_years": 6,
"expected_salary": "130000.00",
"cover_letter": "I am writing to express my strong interest in the Senior Software Engineer position...",
"resume": "/media/application_documents/user_jobseeker123-uuid-here/resume_john_doe.pdf"
}Error Response (Job Seeker Trying to Update): 403 Forbidden
{
"detail": "You do not have permission to perform this action."
}Error Response (Employer Updating Another Employer's Job Application): 403 Forbidden
{
"detail": "You do not have permission to perform this action."
}All protected endpoints require a JWT access token in the Authorization header:
Authorization: Bearer {access_token}
When the access token expires, use the refresh token to obtain a new one:
Endpoint: POST /api/token/refresh/
Request:
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}Response: 200 OK
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}- Admin: Manage industries, full platform access
- Employer: Create companies, post jobs, review applications
- Job Seeker: Browse jobs, apply for positions, track applications
- Employers must create a location before creating a company
- Employers must own a company before posting jobs
- Job seekers can only apply to active jobs before the deadline
- Only authenticated job seeker can apply for active jobs
- Job seeks can view only their job application history
- Users can only manage their own resources (locations, companies, jobs, applications)
- Only job owners can update application status
- Job owners can only view history of application made to their jobs
Search functionality is available on multiple endpoints:
GET /api/jobs/availablejobs/?search=python+developer
GET /api/jobs/availablejobs/?search=remote
GET /api/jobs/companies/?search=tech
GET /api/jobs/postjobs/?search=senior+engineer200 OK- Successful GET, PUT, PATCH201 Created- Successful POST400 Bad Request- Validation errors401 Unauthorized- Authentication required or invalid token403 Forbidden- Permission denied404 Not Found- Resource not found500 Internal Server Error- Server error
- JWT token-based authentication
- Password hashing with Django's built-in password validators
- Role-based access control (RBAC)
- Object-level permissions
- CSRF protection
- SQL injection prevention through Django ORM
- File upload validation
Interactive API documentation is available at:
- Swagger UI:
http://localhost:8000/api/docs/ - ReDoc:
http://localhost:8000/redoc/
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Linus Bwana - @LinusBwana
For support, open an issue in the GitHub repository: https://github.com/LinusBwana/alx-project-nexus/issues
Note: This is a backend API. A separate frontend application is required for the complete user interface.