Creating a comprehensive online job portal involves meticulous planning, structured development, and implementing various functionalities catering to both job seekers and recruiters. This article outlines a modular approach to building such a portal using Laravel, focusing solely on backend development.
Module 1: Initial Setup
1. Install Laravel Framework: Begin by installing the Laravel framework via Composer. Set up your environment configurations in the .env
file and establish a database connection.
composer create-project --prefer-dist laravel/laravel jobportal
2. Install Required Packages: Enhance your Laravel installation with essential packages such as laravel/ui
for authentication scaffolding and passport
for API authentication.
composer require laravel/ui
php artisan ui vue --auth
composer require laravel/passport
php artisan passport:install
3. Setup Version Control: Initialize a Git repository and connect your project to GitHub using Visual Studio Code. This ensures version control and collaboration.
git init
git remote add origin https://github.com/yourusername/jobportal.git
4. Server Configuration: Configure your server environment, including Apache/Nginx and MySQL. You may use Homestead or Valet for local development environments.
5. Documentation: Document the setup process, dependencies, and configurations in a README file for future reference and onboarding new developers.
6. Create App Schema/Diagram: Draft an ER diagram outlining the database schema and relationships between entities. Tools like draw.io can be helpful.
Module 2: User Management
1. Create Migration and Model for Users: Define migrations and models for user_account
and user_type
. Establish relationships in the User model.
php artisan make:model UserAccount -m
php artisan make:model UserType -m
2. Authentication and Authorization: Implement registration, login, and logout functionalities using Laravel Passport for API authentication. Define roles and permissions.
3. Profile Management: Create endpoints for users to view and update their profiles, including profile image upload functionality.
4. Error Handling and Validation: Implement validation for user inputs and custom error messages and handlers to ensure a smooth user experience.
Module 3: Profile Building
1. Job Seeker Profiles: Create migrations and models for seeker_profile
, education_detail
, experience_detail
, and seeker_skill_set
. Implement CRUD operations for job seeker profiles.
2. Company Profiles: Define migrations and models for company
, company_image
, and business_stream
. Implement CRUD operations for company profiles.
3. Resume Builder: Provide functionality to upload resumes and develop forms to build resumes if not uploaded.
Module 4: Job Management
1. Job Posting: Create migrations and models for job_post
, job_post_skill_set
, and job_location
. Implement CRUD operations for job postings.
2. Job Applications: Create migration and model for job_post_activity
. Enable job seekers to apply for jobs.
3. Search and Filter Jobs: Implement robust search functionality with filters for location, skills, salary, etc. Ensure results are paginated for better user experience.
Module 5: Dashboards and Notifications
1. User Dashboards: Develop personalized dashboards for job seekers and recruiters, showing recent activities, applications, and notifications.
2. Notifications: Implement SMS and email notifications for job postings and applications. Allow users to manage their notification preferences.
Module 6: Advanced Features
1. Real-time Updates: Use WebSockets or Pusher to provide real-time updates on job postings and applications.
2. Integration with Social Media: Enable users to link and import data from LinkedIn or other social media profiles for seamless profile building.
3. Salary Reports: Generate reports on salary trends across different roles and locations, providing valuable insights to users.
4. Additional Enhancements: Identify and implement additional features based on user feedback and evolving requirements.
Module 7: Testing and Deployment
1. Testing: Write unit and feature tests to ensure the robustness of the application. Perform end-to-end testing for critical functionalities.
2. Deployment: Set up continuous integration and deployment pipelines. Deploy the application to a production server.
3. Monitoring and Maintenance: Implement application monitoring tools to track performance and errors. Schedule regular maintenance and updates to keep the application running smoothly.
Module 1: Initial Setup
Setting up the initial environment and preparing the foundational elements for your Laravel application is a crucial first step. This module covers the installation of Laravel, configuring the environment, setting up version control, and documenting the setup process.
1. Install Laravel Framework
To start, install the Laravel framework via Composer. This ensures that you have the latest version and all necessary dependencies.
Steps:
- Open your terminal or command prompt.
- Run the following command to create a new Laravel project:
composer create-project --prefer-dist laravel/laravel jobportal
Navigate to your project directory:
cd jobportal
Set up environment configurations by copying the .env.example
file to .env
:
cp .env.example .env
Generate the application key:
php artisan key:generate
- Open the
.env
file and configure your database connection:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=jobportal
DB_USERNAME=root
DB_PASSWORD=your_password
2. Install Required Packages
Enhance your Laravel installation with essential packages such as laravel/ui
for authentication scaffolding and passport
for API authentication.
Steps:
- Install
laravel/ui
package for basic auth scaffolding:
composer require laravel/ui
php artisan ui vue --auth
npm install && npm run dev
Install Laravel Passport for API authentication:
composer require laravel/passport
php artisan passport:install
Add the HasApiTokens
trait to your User
model located in app/Models/User.php
:
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
// ...
}
Configure Passport in AuthServiceProvider
located in app/Providers/AuthServiceProvider.php
:
use Laravel\Passport\Passport;
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
3. Setup Version Control
Initialize a Git repository and connect your project to GitHub using Visual Studio Code. This ensures version control and collaboration.
Steps:
- Initialize a Git repository:
git init
2. Add all files and commit the initial setup:
git add .
git commit -m "Initial commit"
3. Create a new repository on GitHub and follow the instructions to link your local repository:
git remote add origin https://github.com/yourusername/jobportal.git
git push -u origin master
4. Server Configuration
Configure your server environment, including Apache/Nginx and MySQL. You may use tools like Homestead or Valet for local development.
Steps:
Homestead: Follow the official Laravel Homestead documentation for installation and configuration.
Valet: Follow the official Laravel Valet documentation for installation and configuration.
5. Documentation
Document the setup process, dependencies, and configurations in a README file for future reference and onboarding new developers.
Steps:
- Create a
README.md
file in the root of your project. - Document the installation steps, dependencies, and environment setup.
# Job Portal
## Installation
1. Clone the repository:
```bash
git clone https://github.com/yourusername/jobportal.git
cd jobportal
composer install
npm install
Set up environment configurations:
cp .env.example .env
php artisan key:generate
Configure your database in the
.env
file.Run migrations:
php artisan migrate
Install Passport:
php artisan passport:install
Running the Application
- Start the development server:
php artisan serve
Module 2: User Management
The User Management module is pivotal in ensuring that your job portal can handle user registrations, authentication, and profile management efficiently. This module will cover creating user-related tables, implementing authentication, managing user profiles, and handling validations and errors.
1. Create Migration and Model for Users
To manage user registrations and their roles, we will create migrations and models for user_account
and user_type
.
Steps:
- Create Migrations:
php artisan make:model UserAccount -m
php artisan make:model UserType -m
Define UserType Migration:
// database/migrations/xxxx_xx_xx_create_user_types_table.php
public function up()
{
Schema::create('user_types', function (Blueprint $table) {
$table->id();
$table->string('type')->unique();
$table->timestamps();
});
}
Define UserAccount Migration:
// database/migrations/xxxx_xx_xx_create_user_accounts_table.php
public function up()
{
Schema::create('user_accounts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_type_id')->constrained()->onDelete('cascade');
$table->string('email')->unique();
$table->string('password');
$table->date('date_of_birth')->nullable();
$table->string('gender', 10)->nullable();
$table->boolean('is_active')->default(true);
$table->string('contact_number')->nullable();
$table->boolean('sms_notification_active')->default(true);
$table->boolean('email_notification_active')->default(true);
$table->binary('user_image')->nullable();
$table->timestamp('registration_date')->useCurrent();
$table->timestamps();
});
}
Run Migrations:
php artisan migrate
2. Authentication and Authorization
Implementing user authentication using Laravel Passport for API authentication ensures secure user sessions and role-based access control.
Steps:
- Add Passport Traits:
// app/Models/UserAccount.php
use Laravel\Passport\HasApiTokens;
class UserAccount extends Authenticatable
{
use HasApiTokens, Notifiable;
// ...
}
Update AuthServiceProvider:
// app/Providers/AuthServiceProvider.php
use Laravel\Passport\Passport;
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
- Register Passport Service Provider:
Add Laravel\Passport\PassportServiceProvider::class
to the providers
array in config/app.php
.
- Create Auth Controllers:
php artisan make:controller Auth/RegisterController
php artisan make:controller Auth/LoginController
Define Routes:
// routes/api.php
use App\Http\Controllers\Auth\RegisterController;
use App\Http\Controllers\Auth\LoginController;
Route::post('register', [RegisterController::class, 'register']);
Route::post('login', [LoginController::class, 'login']);
Implement Register and Login Methods:
// app/Http/Controllers/Auth/RegisterController.php
public function register(Request $request)
{
$validatedData = $request->validate([
'email' => 'required|email|unique:user_accounts',
'password' => 'required|min:8|confirmed',
'user_type_id' => 'required|exists:user_types,id',
]);
$user = UserAccount::create([
'email' => $validatedData['email'],
'password' => bcrypt($validatedData['password']),
'user_type_id' => $validatedData['user_type_id'],
]);
$token = $user->createToken('authToken')->accessToken;
return response()->json(['user' => $user, 'token' => $token]);
}
// app/Http/Controllers/Auth/LoginController.php
public function login(Request $request)
{
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required',
]);
if (!auth()->attempt($credentials)) {
return response()->json(['message' => 'Invalid credentials'], 401);
}
$token = auth()->user()->createToken('authToken')->accessToken;
return response()->json(['user' => auth()->user(), 'token' => $token]);
}
3. Profile Management
Allow users to view and update their profiles, including uploading profile images.
Steps:
- Create Profile Controller:
php artisan make:controller ProfileController
Define Profile Routes
// routes/api.php
use App\Http\Controllers\ProfileController;
Route::middleware('auth:api')->group(function () {
Route::get('profile', [ProfileController::class, 'show']);
Route::post('profile', [ProfileController::class, 'update']);
});
Implement Profile Methods:
// app/Http/Controllers/ProfileController.php
public function show()
{
return response()->json(['user' => auth()->user()]);
}
public function update(Request $request)
{
$user = auth()->user();
$validatedData = $request->validate([
'date_of_birth' => 'date',
'gender' => 'string|max:10',
'contact_number' => 'string|max:15',
'sms_notification_active' => 'boolean',
'email_notification_active' => 'boolean',
'user_image' => 'image|max:2048',
]);
if ($request->hasFile('user_image')) {
$image = $request->file('user_image')->store('profile_images', 'public');
$validatedData['user_image'] = $image;
}
$user->update($validatedData);
return response()->json(['user' => $user]);
}
4. Error Handling and Validation
Implement comprehensive validation and error handling to ensure data integrity and user-friendly error messages.
Steps:
- Custom Validation Messages:
// app/Http/Controllers/Auth/RegisterController.php
$messages = [
'email.required' => 'Email is required.',
'email.email' => 'Invalid email format.',
'password.required' => 'Password is required.',
'password.confirmed' => 'Passwords do not match.',
];
$validatedData = $request->validate([
'email' => 'required|email|unique:user_accounts',
'password' => 'required|min:8|confirmed',
'user_type_id' => 'required|exists:user_types,id',
], $messages);
- Global Exception Handling:
Update the render
method in app/Exceptions/Handler.php
to handle exceptions and return user-friendly messages.
public function render($request, Exception $exception)
{
if ($exception instanceof ValidationException) {
return response()->json(['errors' => $exception->errors()], 422);
}
return parent::render($request, $exception);
}
By completing Module 2, you have established the core user management functionalities of your job portal. This includes secure user authentication, comprehensive profile management, and robust validation and error handling. These steps provide a strong foundation for building more complex features in subsequent modules.
Next, we will focus on building profiles for both job seekers and companies, implementing CRUD operations, and enhancing profile details.
Module 3: Profile Building
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.
This module focuses on creating and managing profiles for both job seekers and companies. It involves setting up the necessary database tables, models, and controllers to handle profile-related operations, such as viewing and updating profiles, adding educational and professional details, and uploading resumes and images.
1. Job Seeker Profiles
Steps:
- Create Migrations and Models
php artisan make:model SeekerProfile -m
php artisan make:model EducationDetail -m
php artisan make:model ExperienceDetail -m
php artisan make:model SeekerSkillSet -m
- Define Migrations:
SeekerProfile Migration:
// database/migrations/xxxx_xx_xx_create_seeker_profiles_table.php
public function up()
{
Schema::create('seeker_profiles', function (Blueprint $table) {
$table->id();
$table->foreignId('user_account_id')->constrained('user_accounts')->onDelete('cascade');
$table->string('first_name');
$table->string('last_name');
$table->decimal('current_salary', 8, 2)->nullable();
$table->boolean('is_annually_monthly')->nullable();
$table->string('currency', 3)->nullable();
$table->timestamps();
});
}
EducationDetail Migration:
// database/migrations/xxxx_xx_xx_create_education_details_table.php
public function up()
{
Schema::create('education_details', function (Blueprint $table) {
$table->foreignId('user_account_id')->constrained('user_accounts')->onDelete('cascade');
$table->string('certificate_degree_name');
$table->string('major');
$table->string('institute_university_name');
$table->date('start_date');
$table->date('completion_date')->nullable();
$table->decimal('percentage', 5, 2)->nullable();
$table->decimal('cgpa', 4, 2)->nullable();
$table->primary(['user_account_id', 'certificate_degree_name', 'major']);
});
}
ExperienceDetail Migration:
// database/migrations/xxxx_xx_xx_create_experience_details_table.php
public function up()
{
Schema::create('experience_details', function (Blueprint $table) {
$table->foreignId('user_account_id')->constrained('user_accounts')->onDelete('cascade');
$table->boolean('is_current_job');
$table->date('start_date');
$table->date('end_date')->nullable();
$table->string('job_title');
$table->string('company_name');
$table->string('job_location_city');
$table->string('job_location_state');
$table->string('job_location_country');
$table->text('description')->nullable();
$table->primary(['user_account_id', 'job_title', 'company_name']);
});
}
SeekerSkillSet Migration:
// database/migrations/xxxx_xx_xx_create_seeker_skill_sets_table.php
public function up()
{
Schema::create('seeker_skill_sets', function (Blueprint $table) {
$table->foreignId('user_account_id')->constrained('user_accounts')->onDelete('cascade');
$table->foreignId('skill_set_id')->constrained('skill_sets')->onDelete('cascade');
$table->tinyInteger('skill_level')->default(1);
$table->primary(['user_account_id', 'skill_set_id']);
});
}
Run Migrations:
php artisan migrate
- Define Models:
SeekerProfile Model:
// app/Models/SeekerProfile.php
class SeekerProfile extends Model
{
protected $fillable = [
'user_account_id', 'first_name', 'last_name', 'current_salary', 'is_annually_monthly', 'currency'
];
public function userAccount()
{
return $this->belongsTo(UserAccount::class);
}
}
EducationDetail Model:
// app/Models/EducationDetail.php
class EducationDetail extends Model
{
protected $primaryKey = ['user_account_id', 'certificate_degree_name', 'major'];
public $incrementing = false;
protected $fillable = [
'user_account_id', 'certificate_degree_name', 'major', 'institute_university_name', 'start_date', 'completion_date', 'percentage', 'cgpa'
];
public function userAccount()
{
return $this->belongsTo(UserAccount::class);
}
}
ExperienceDetail Model:
// app/Models/ExperienceDetail.php
class ExperienceDetail extends Model
{
protected $primaryKey = ['user_account_id', 'job_title', 'company_name'];
public $incrementing = false;
protected $fillable = [
'user_account_id', 'is_current_job', 'start_date', 'end_date', 'job_title', 'company_name', 'job_location_city', 'job_location_state', 'job_location_country', 'description'
];
public function userAccount()
{
return $this->belongsTo(UserAccount::class);
}
}
SeekerSkillSet Model:
// app/Models/SeekerSkillSet.php
class SeekerSkillSet extends Model
{
protected $primaryKey = ['user_account_id', 'skill_set_id'];
public $incrementing = false;
protected $fillable = [
'user_account_id', 'skill_set_id', 'skill_level'
];
public function userAccount()
{
return $this->belongsTo(UserAccount::class);
}
}
2. Company Profiles
Steps:
- Create Migrations and Models:
php artisan make:model Company -m
php artisan make:model CompanyImage -m
php artisan make:model BusinessStream -m
- Define Migrations:
Company Migration:
// database/migrations/xxxx_xx_xx_create_companies_table.php
public function up()
{
Schema::create('companies', function (Blueprint $table) {
$table->id();
$table->string('company_name');
$table->text('profile_description')->nullable();
$table->foreignId('business_stream_id')->constrained()->onDelete('cascade');
$table->date('establishment_date');
$table->string('company_website_url');
$table->timestamps();
});
}
CompanyImage Migration:
// database/migrations/xxxx_xx_xx_create_company_images_table.php
public function up()
{
Schema::create('company_images', function (Blueprint $table) {
$table->id();
$table->foreignId('company_id')->constrained()->onDelete('cascade');
$table->string('image_path');
$table->timestamps();
});
}
BusinessStream Migration:
// database/migrations/xxxx_xx_xx_create_business_streams_table.php
public function up()
{
Schema::create('business_streams', function (Blueprint $table) {
$table->id();
$table->string('business_stream_name');
$table->timestamps();
});
}
Run Migrations:
php artisan migrate
- Define Models:
Company Model:
// app/Models/Company.php
class Company extends Model
{
protected $fillable = [
'company_name', 'profile_description', 'business_stream_id', 'establishment_date', 'company_website_url'
];
public function businessStream()
{
return $this->belongsTo(BusinessStream::class);
}
public function images()
{
return $this->hasMany(CompanyImage::class);
}
}
CompanyImage Model:
// app/Models/CompanyImage.php
class CompanyImage extends Model
{
protected $fillable = [
'company_id', 'image_path'
];
public function company()
{
return $this->belongsTo(Company::class);
}
}
BusinessStream Model:
// app/Models/BusinessStream.php
class BusinessStream extends Model
{
protected $fillable = [
'business_stream_name'
];
public function companies()
{
return $this->hasMany(Company::class);
}
}
3. Resume Builder
Implement functionality for job seekers to upload resumes or build them using a form.
Steps:
- Create Resume Upload Route:
// routes/api.php
use App\Http\Controllers\ResumeController;
Route::middleware('auth:api')->group(function () {
Route::post('upload-resume', [ResumeController::class, 'upload']);
});
Create Resume Controller:
php artisan make:controller ResumeController
Implement Resume Upload Method:
// app/Http/Controllers/ResumeController.php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class ResumeController extends Controller
{
public function upload(Request $request)
{
$request->validate([
'resume' => 'required|mimes:pdf,doc,docx|max:2048',
]);
$user = auth()->user();
$path = $request->file('resume')->store('resumes', 'public');
$user->resume_path = $path;
$user->save();
return response()->json(['message' => 'Resume uploaded successfully', 'path' => $path]);
}
}
By completing Module 3, you have established the core functionalities for managing profiles for both job seekers and companies. This includes CRUD operations for profiles, managing educational and professional details, and implementing a resume upload feature. These steps provide a comprehensive profile management system that can be further expanded in subsequent modules.
Next, we will focus on job management, including job posting, searching, and application functionalities.
Module 4: Job Management
This module focuses on the core functionality of the job portal: managing job postings, searching for jobs, and handling job applications. We’ll create the necessary database tables, models, and controllers to support these features.
1. Job Posting
Steps:
- Create Migrations and Models:
php artisan make:model JobPost -m
php artisan make:model JobPostSkillSet -m
php artisan make:model JobLocation -m
- Define Migrations:
JobPost Migration
// database/migrations/xxxx_xx_xx_create_job_posts_table.php
public function up()
{
Schema::create('job_posts', function (Blueprint $table) {
$table->id();
$table->foreignId('posted_by_id')->constrained('user_accounts')->onDelete('cascade');
$table->foreignId('company_id')->constrained()->onDelete('cascade');
$table->foreignId('job_type_id')->constrained()->onDelete('cascade');
$table->string('job_title');
$table->text('job_description');
$table->boolean('is_company_name_hidden')->default(false);
$table->foreignId('job_location_id')->constrained()->onDelete('cascade');
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
JobPostSkillSet Migration:
// database/migrations/xxxx_xx_xx_create_job_post_skill_sets_table.php
public function up()
{
Schema::create('job_post_skill_sets', function (Blueprint $table) {
$table->foreignId('job_post_id')->constrained()->onDelete('cascade');
$table->foreignId('skill_set_id')->constrained('skill_sets')->onDelete('cascade');
$table->tinyInteger('skill_level')->default(1);
$table->primary(['job_post_id', 'skill_set_id']);
});
}
JobLocation Migration:
// database/migrations/xxxx_xx_xx_create_job_locations_table.php
public function up()
{
Schema::create('job_locations', function (Blueprint $table) {
$table->id();
$table->string('street_address')->nullable();
$table->string('city');
$table->string('state');
$table->string('country');
$table->string('postal_code');
$table->timestamps();
});
}
Run Migrations:
php artisan migrate
- Define Models:
JobPost Model:
// app/Models/JobPost.php
class JobPost extends Model
{
protected $fillable = [
'posted_by_id', 'company_id', 'job_type_id', 'job_title', 'job_description', 'is_company_name_hidden', 'job_location_id', 'is_active'
];
public function userAccount()
{
return $this->belongsTo(UserAccount::class, 'posted_by_id');
}
public function company()
{
return $this->belongsTo(Company::class);
}
public function jobLocation()
{
return $this->belongsTo(JobLocation::class);
}
public function skillSets()
{
return $this->belongsToMany(SkillSet::class, 'job_post_skill_sets')->withPivot('skill_level');
}
}
JobPostSkillSet Model:
// app/Models/JobPostSkillSet.php
class JobPostSkillSet extends Model
{
protected $primaryKey = ['job_post_id', 'skill_set_id'];
public $incrementing = false;
protected $fillable = [
'job_post_id', 'skill_set_id', 'skill_level'
];
}
JobLocation Model:
// app/Models/JobLocation.php
class JobLocation extends Model
{
protected $fillable = [
'street_address', 'city', 'state', 'country', 'postal_code'
];
public function jobPosts()
{
return $this->hasMany(JobPost::class);
}
}
Create JobPost Controller:
php artisan make:controller JobPostController
Define Routes:
// routes/api.php
use App\Http\Controllers\JobPostController;
Route::middleware('auth:api')->group(function () {
Route::resource('job-posts', JobPostController::class);
});
Implement JobPost Controller Methods:
// app/Http/Controllers/JobPostController.php
use Illuminate\Http\Request;
use App\Models\JobPost;
class JobPostController extends Controller
{
public function index()
{
$jobs = JobPost::with(['company', 'jobLocation', 'skillSets'])->paginate(10);
return response()->json($jobs);
}
public function store(Request $request)
{
$validatedData = $request->validate([
'company_id' => 'required|exists:companies,id',
'job_type_id' => 'required|exists:job_types,id',
'job_title' => 'required|string|max:255',
'job_description' => 'required|string',
'is_company_name_hidden' => 'boolean',
'job_location_id' => 'required|exists:job_locations,id',
'skill_sets' => 'array',
'skill_sets.*.skill_set_id' => 'required|exists:skill_sets,id',
'skill_sets.*.skill_level' => 'required|integer|min:1|max:10',
]);
$jobPost = JobPost::create($validatedData);
$jobPost->skillSets()->sync($request->skill_sets);
return response()->json(['message' => 'Job post created successfully', 'job_post' => $jobPost], 201);
}
public function show($id)
{
$jobPost = JobPost::with(['company', 'jobLocation', 'skillSets'])->findOrFail($id);
return response()->json($jobPost);
}
public function update(Request $request, $id)
{
$jobPost = JobPost::findOrFail($id);
$validatedData = $request->validate([
'company_id' => 'required|exists:companies,id',
'job_type_id' => 'required|exists:job_types,id',
'job_title' => 'required|string|max:255',
'job_description' => 'required|string',
'is_company_name_hidden' => 'boolean',
'job_location_id' => 'required|exists:job_locations,id',
'skill_sets' => 'array',
'skill_sets.*.skill_set_id' => 'required|exists:skill_sets,id',
'skill_sets.*.skill_level' => 'required|integer|min:1|max:10',
]);
$jobPost->update($validatedData);
$jobPost->skillSets()->sync($request->skill_sets);
return response()->json(['message' => 'Job post updated successfully', 'job_post' => $jobPost]);
}
public function destroy($id)
{
$jobPost = JobPost::findOrFail($id);
$jobPost->delete();
return response()->json(['message' => 'Job post deleted successfully']);
}
}
2. Job Applications
Steps:
- Create Migration and Model:
php artisan make:model JobPostActivity -m
- Define Migration:
JobPostActivity Migration:
// database/migrations/xxxx_xx_xx_create_job_post_activities_table.php
public function up()
{
Schema::create('job_post_activities', function (Blueprint $table) {
$table->id();
$table->foreignId('job_post_id')->constrained()->onDelete('cascade');
$table->foreignId('user_account_id')->constrained()->onDelete('cascade');
$table->timestamp('applied_at')->useCurrent();
$table->timestamps();
});
}
Run Migration:
php artisan migrate
- Define Model:
JobPostActivity Model:
// app/Models/JobPostActivity.php
class JobPostActivity extends Model
{
protected $fillable = [
'job_post_id', 'user_account_id', 'applied_at'
];
public function jobPost()
{
return $this->belongsTo(JobPost::class);
}
public function userAccount()
{
return $this->belongsTo(UserAccount::class);
}
}
Create JobPostActivity Controller:
php artisan make:controller JobPostActivityController
Define Routes:
// routes/api.php
use App\Http\Controllers\JobPostActivityController;
Route::middleware('auth:api')->group(function () {
Route::post('job-posts/{job_post}/apply', [JobPostActivityController::class, 'apply']);
});
Implement JobPostActivity Controller Methods:
// app/Http/Controllers/JobPostActivityController.php
use Illuminate\Http\Request;
use App\Models\JobPost;
use App\Models\JobPostActivity;
class JobPostActivityController extends Controller
{
public function apply(Request $request, $jobPostId)
{
$user = auth()->user();
$jobPost = JobPost::findOrFail($jobPostId);
$application = JobPostActivity::create([
'job_post_id' => $jobPost->id,
'user_account_id' => $user->id,
]);
return response()->json(['message' => 'Application submitted successfully', 'application' => $application], 201);
}
}
Search and Filter Jobs
Steps:
- Add Search and Filter Functionality to JobPostController:
// app/Http/Controllers/JobPostController.php
public function index(Request $request)
{
$query = JobPost::with(['company', 'jobLocation', 'skillSets'])->where('is_active', true);
if ($request->has('location')) {
$query->whereHas('jobLocation', function ($q) use ($request) {
$q->where('city', 'like', '%' . $request->location . '%')
->orWhere('state', 'like', '%' . $request->location . '%')
->orWhere('country', 'like', '%' . $request->location . '%');
});
}
if ($request->has('skills')) {
$skills = explode(',', $request->skills);
$query->whereHas('skillSets', function ($q) use ($skills) {
$q->whereIn('skill_set_id', $skills);
});
}
if ($request->has('job_title')) {
$query->where('job_title', 'like', '%' . $request->job_title . '%');
}
if ($request->has('company')) {
$query->whereHas('company', function ($q) use ($request) {
$q->where('company_name', 'like', '%' . $request->company . '%');
});
}
if ($request->has('salary')) {
$query->where('salary', '>=', $request->salary);
}
$jobs = $query->paginate(10);
return response()->json($jobs);
}
Define Search Parameters in Routes:
// routes/api.php
Route::middleware('auth:api')->group(function () {
Route::get('job-posts', [JobPostController::class, 'index']);
});
By completing Module 4, you have established the core functionalities for managing job postings and applications. This includes creating, updating, and deleting job posts, handling job applications, and implementing robust search and filter functionalities. These steps provide a comprehensive job management system that can be further expanded in subsequent modules.
Next, we will focus on user dashboards, notifications, and additional features such as real-time updates and social media integration.
Module 5: Dashboards and Notifications
This module focuses on creating personalized dashboards for job seekers and recruiters, managing notifications, and providing real-time updates on job applications and postings. This will enhance user experience by giving users an overview of their activities and keeping them informed.
1. User Dashboards
Steps:
- Create Dashboard Controller:
php artisan make:controller DashboardController
Define Routes:
// routes/api.php
use App\Http\Controllers\DashboardController;
Route::middleware('auth:api')->group(function () {
Route::get('dashboard', [DashboardController::class, 'index']);
});
Implement Dashboard Method:
// app/Http/Controllers/DashboardController.php
use App\Models\JobPostActivity;
use App\Models\JobPost;
class DashboardController extends Controller
{
public function index()
{
$user = auth()->user();
if ($user->user_type_id == 1) { // Job Seeker
$applications = JobPostActivity::where('user_account_id', $user->id)->with('jobPost')->get();
return response()->json(['applications' => $applications]);
} elseif ($user->user_type_id == 2) { // Recruiter
$jobPosts = JobPost::where('posted_by_id', $user->id)->with('jobPostActivities')->get();
return response()->json(['job_posts' => $jobPosts]);
}
}
}
2. Notifications
Steps:
- Install Laravel Notifications:
Laravel provides a built-in notification system that can be used to send notifications via different channels, such as email and SMS.
composer require laravel-notifications
Create Notification for Job Applications:
php artisan make:notification JobApplicationNotification
Implement Notification Logic:
// app/Notifications/JobApplicationNotification.php
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class JobApplicationNotification extends Notification
{
use Queueable;
protected $application;
public function __construct($application)
{
$this->application = $application;
}
public function via($notifiable)
{
return ['mail', 'database'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->line('You have a new job application.')
->action('View Application', url('/job-posts/' . $this->application->job_post_id))
->line('Thank you for using our application!');
}
public function toArray($notifiable)
{
return [
'job_post_id' => $this->application->job_post_id,
'user_account_id' => $this->application->user_account_id,
];
}
}
- Trigger Notification on Job Application:
Modify the apply
method in JobPostActivityController
to send a notification when a job application is created.
// app/Http/Controllers/JobPostActivityController.php
use App\Notifications\JobApplicationNotification;
public function apply(Request $request, $jobPostId)
{
$user = auth()->user();
$jobPost = JobPost::findOrFail($jobPostId);
$application = JobPostActivity::create([
'job_post_id' => $jobPost->id,
'user_account_id' => $user->id,
]);
// Send notification to the recruiter
$jobPost->userAccount->notify(new JobApplicationNotification($application));
return response()->json(['message' => 'Application submitted successfully', 'application' => $application], 201);
}
- Retrieve Notifications in Dashboard:
Update the index
method in DashboardController
to include notifications.
// app/Http/Controllers/DashboardController.php
public function index()
{
$user = auth()->user();
if ($user->user_type_id == 1) { // Job Seeker
$applications = JobPostActivity::where('user_account_id', $user->id)->with('jobPost')->get();
$notifications = $user->notifications;
return response()->json(['applications' => $applications, 'notifications' => $notifications]);
} elseif ($user->user_type_id == 2) { // Recruiter
$jobPosts = JobPost::where('posted_by_id', $user->id)->with('jobPostActivities')->get();
$notifications = $user->notifications;
return response()->json(['job_posts' => $jobPosts, 'notifications' => $notifications]);
}
}
3. Real-time Updates
Steps:
- Install Laravel Echo and Pusher:
Laravel Echo is a JavaScript library that makes it easy to work with WebSockets in Laravel. Pusher is a WebSocket service.
composer require pusher/pusher-php-server
npm install --save laravel-echo pusher-js
- Configure Pusher:
Update the .env
file with your Pusher credentials.
PUSHER_APP_ID=your-pusher-app-id
PUSHER_APP_KEY=your-pusher-app-key
PUSHER_APP_SECRET=your-pusher-app-secret
PUSHER_APP_CLUSTER=mt1
Update config/broadcasting.php
to include Pusher configuration.
// config/broadcasting.php
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true,
],
],
],
Create Event for Real-time Updates:
php artisan make:event JobApplicationCreated
- Broadcast Event:
Update the apply
method in JobPostActivityController
to broadcast an event.
// app/Http/Controllers/JobPostActivityController.php
use App\Events\JobApplicationCreated;
public function apply(Request $request, $jobPostId)
{
$user = auth()->user();
$jobPost = JobPost::findOrFail($jobPostId);
$application = JobPostActivity::create([
'job_post_id' => $jobPost->id,
'user_account_id' => $user->id,
]);
// Send notification to the recruiter
$jobPost->userAccount->notify(new JobApplicationNotification($application));
// Broadcast event
broadcast(new JobApplicationCreated($application))->toOthers();
return response()->json(['message' => 'Application submitted successfully', 'application' => $application], 201);
}
- Listen for Event in Frontend:
Set up Laravel Echo in your frontend to listen for the JobApplicationCreated
event.
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true
});
Echo.channel('job-post')
.listen('JobApplicationCreated', (e) => {
console.log('Job application created:', e);
});
By completing Module 5, you have established personalized dashboards, implemented notification systems, and added real-time updates for job applications. These features significantly enhance user engagement and ensure users stay informed about their activities on the portal.
Next, we will focus on advanced features such as social media integration, salary reports, and any additional enhancements based on user feedback.
Module 6: Advanced Features
This module focuses on adding advanced features to your job portal, such as social media integration, salary reports, and additional enhancements based on user feedback. These features aim to provide a more comprehensive and user-friendly experience for both job seekers and recruiters.
1. Social Media Integration
Steps:
- Install Socialite:
Laravel Socialite provides a simple and convenient way to authenticate with various social media platforms.
composer require laravel/socialite
- Configure Socialite:
Update the config/services.php
file with your social media credentials.
// config/services.php
return [
'github' => [
'client_id' => env('GITHUB_CLIENT_ID'),
'client_secret' => env('GITHUB_CLIENT_SECRET'),
'redirect' => env('GITHUB_REDIRECT_URI'),
],
// Add other social media services like LinkedIn, Google, etc.
];
Update your .env
file with the necessary environment variables.
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
GITHUB_REDIRECT_URI=https://your-app-url/callback/github
Create Socialite Controller:
php artisan make:controller SocialAuthController
Implement Socialite Methods:
// app/Http/Controllers/SocialAuthController.php
use Laravel\Socialite\Facades\Socialite;
use App\Models\UserAccount;
class SocialAuthController extends Controller
{
public function redirectToProvider($provider)
{
return Socialite::driver($provider)->redirect();
}
public function handleProviderCallback($provider)
{
$user = Socialite::driver($provider)->user();
$existingUser = UserAccount::where('email', $user->getEmail())->first();
if ($existingUser) {
auth()->login($existingUser, true);
} else {
$newUser = UserAccount::create([
'email' => $user->getEmail(),
'name' => $user->getName(),
'provider_id' => $user->getId(),
'provider' => $provider,
]);
auth()->login($newUser, true);
}
return redirect()->intended('dashboard');
}
}
Define Routes:
// routes/web.php
use App\Http\Controllers\SocialAuthController;
Route::get('login/{provider}', [SocialAuthController::class, 'redirectToProvider']);
Route::get('callback/{provider}', [SocialAuthController::class, 'handleProviderCallback']);
2. Salary Reports
Steps:
- Create SalaryReport Controller
php artisan make:controller SalaryReportController
Define Routes:
// routes/api.php
use App\Http\Controllers\SalaryReportController;
Route::middleware('auth:api')->group(function () {
Route::get('salary-reports', [SalaryReportController::class, 'index']);
});
Implement SalaryReport Controller Methods
// app/Http/Controllers/SalaryReportController.php
use Illuminate\Http\Request;
use App\Models\JobPost;
use DB;
class SalaryReportController extends Controller
{
public function index(Request $request)
{
$query = JobPost::query();
if ($request->has('role')) {
$query->where('job_title', 'like', '%' . $request->role . '%');
}
if ($request->has('company')) {
$query->whereHas('company', function ($q) use ($request) {
$q->where('company_name', 'like', '%' . $request->company . '%');
});
}
if ($request->has('location')) {
$query->whereHas('jobLocation', function ($q) use ($request) {
$q->where('city', 'like', '%' . $request->location . '%')
->orWhere('state', 'like', '%' . $request->location . '%')
->orWhere('country', 'like', '%' . $request->location . '%');
});
}
$reports = $query->select(
'job_title',
DB::raw('AVG(salary) as average_salary'),
DB::raw('MIN(salary) as minimum_salary'),
DB::raw('MAX(salary) as maximum_salary')
)->groupBy('job_title')->get();
return response()->json($reports);
}
}
3. Additional Enhancements
Steps:
- Feedback Collection:
Create a system to collect user feedback to continuously improve the platform.
php artisan make:model Feedback -m
php artisan make:controller FeedbackController
Define the migration for the feedback table:
// database/migrations/xxxx_xx_xx_create_feedback_table.php
public function up()
{
Schema::create('feedback', function (Blueprint $table) {
$table->id();
$table->foreignId('user_account_id')->constrained()->onDelete('cascade');
$table->text('message');
$table->timestamps();
});
}
Run the migration:
php artisan migrate
Implement the Feedback model:
// app/Models/Feedback.php
class Feedback extends Model
{
protected $fillable = ['user_account_id', 'message'];
public function user()
{
return $this->belongsTo(UserAccount::class);
}
}
Define routes for feedback:
// routes/api.php
use App\Http\Controllers\FeedbackController;
Route::middleware('auth:api')->group(function () {
Route::post('feedback', [FeedbackController::class, 'store']);
Route::get('feedback', [FeedbackController::class, 'index']);
});
Implement FeedbackController methods:
// app/Http/Controllers/FeedbackController.php
use Illuminate\Http\Request;
use App\Models\Feedback;
class FeedbackController extends Controller
{
public function store(Request $request)
{
$validatedData = $request->validate([
'message' => 'required|string',
]);
$feedback = Feedback::create([
'user_account_id' => auth()->id(),
'message' => $validatedData['message'],
]);
return response()->json(['message' => 'Feedback submitted successfully', 'feedback' => $feedback], 201);
}
public function index()
{
$feedback = Feedback::with('user')->get();
return response()->json($feedback);
}
}
- Performance Monitoring:
Integrate performance monitoring tools such as Laravel Telescope or New Relic to monitor and optimize application performance.
composer require laravel/telescope
php artisan telescope:install
php artisan migrate
Register Telescope in app/Providers/AppServiceProvider.php
:
use Laravel\Telescope\Telescope;
public function register()
{
Telescope::night();
}
By completing Module 6, you have added advanced features to your job portal, including social media integration, salary reports, user feedback collection, and performance monitoring. These enhancements will provide a more comprehensive and engaging experience for your users.
Next, we will focus on testing, deployment, and monitoring to ensure your application is robust, scalable, and ready for production.
Module 7: Testing, Deployment, and Monitoring
In this module, we will focus on ensuring the robustness and reliability of the application through comprehensive testing. We will then deploy the application to a production environment and set up monitoring to track performance and issues in real-time.
1. Testing
Steps:
- Set Up Testing Environment:
Ensure your testing environment is configured correctly in your .env.testing
file.
APP_ENV=testing
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=jobportal_test
DB_USERNAME=root
DB_PASSWORD=your_password
- Create Test Cases:
Create test cases for various functionalities, including user management, job postings, applications, and notifications.
php artisan make:test UserManagementTest
php artisan make:test JobPostTest
php artisan make:test JobApplicationTest
Implement User Management Test:
// tests/Feature/UserManagementTest.php
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UserManagementTest extends TestCase
{
use RefreshDatabase;
public function test_user_can_register()
{
$response = $this->post('/api/register', [
'email' => 'test@example.com',
'password' => 'password',
'password_confirmation' => 'password',
'user_type_id' => 1,
]);
$response->assertStatus(201);
$this->assertDatabaseHas('user_accounts', ['email' => 'test@example.com']);
}
public function test_user_can_login()
{
$user = UserAccount::factory()->create([
'email' => 'test@example.com',
'password' => bcrypt('password'),
]);
$response = $this->post('/api/login', [
'email' => 'test@example.com',
'password' => 'password',
]);
$response->assertStatus(200);
$response->assertJsonStructure(['token']);
}
}
Implement Job Post Test:
// tests/Feature/JobPostTest.php
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class JobPostTest extends TestCase
{
use RefreshDatabase;
public function test_job_post_creation()
{
$user = UserAccount::factory()->create(['user_type_id' => 2]);
$response = $this->actingAs($user, 'api')->post('/api/job-posts', [
'company_id' => 1,
'job_type_id' => 1,
'job_title' => 'Software Developer',
'job_description' => 'Develop and maintain software applications.',
'job_location_id' => 1,
]);
$response->assertStatus(201);
$this->assertDatabaseHas('job_posts', ['job_title' => 'Software Developer']);
}
public function test_job_post_deletion()
{
$user = UserAccount::factory()->create(['user_type_id' => 2]);
$jobPost = JobPost::factory()->create(['posted_by_id' => $user->id]);
$response = $this->actingAs($user, 'api')->delete('/api/job-posts/' . $jobPost->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('job_posts', ['id' => $jobPost->id]);
}
}
- Run Tests:
Execute the test suite to ensure all functionalities are working as expected.
php artisan test
2. Deployment
Steps:
- Set Up Server:
Prepare your production server with necessary software such as Apache/Nginx, MySQL, and PHP.
- Configure Environment Variables:
Update the .env
file on your production server with the correct environment variables.
- Deploy Code:
Use a deployment tool such as Git, Envoyer, or Deployer to deploy your code to the production server.
git pull origin master
composer install --optimize-autoloader --no-dev
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
- Set Up Supervisor:
Use Supervisor to manage the Laravel queue worker for handling job applications and notifications.
sudo apt-get install supervisor
Create a Supervisor configuration file for the Laravel queue worker:
[program:jobportal-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/your/project/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=your_username
numprocs=1
redirect_stderr=true
stdout_logfile=/path/to/your/project/storage/logs/worker.log
Reload Supervisor to apply the configuration:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start jobportal-worker:*
3. Monitoring
Steps:
- Set Up Monitoring Tools:
Integrate monitoring tools like Laravel Telescope, Sentry, or New Relic to monitor your application’s performance and catch errors in real-time.
- Configure Laravel Telescope:
Install and configure Laravel Telescope:
composer require laravel/telescope
php artisan telescope:install
php artisan migrate
Register Telescope in your AppServiceProvider
:
use Laravel\Telescope\Telescope;
public function register()
{
Telescope::night();
}
- Set Up Sentry for Error Tracking:
Install and configure Sentry:
composer require sentry/sentry-laravel
Add Sentry configuration to your .env
file:
SENTRY_LARAVEL_DSN=your-sentry-dsn
Configure Sentry in config/sentry.php
:
return [
'dsn' => env('SENTRY_LARAVEL_DSN'),
// capture release as git sha
'release' => trim(exec('git log --pretty="%h" -n1 HEAD')),
'breadcrumbs' => [
// Capture Laravel logs
'logs' => true,
],
'tracing' => [
'enabled' => true,
'views' => true,
'sql_queries' => true,
'queue_jobs' => true,
],
];
- Set Up New Relic for Performance Monitoring:
Follow the New Relic documentation to install and configure the New Relic PHP agent on your server.
By completing Module 7, you have ensured the robustness, reliability, and performance of your job portal. This includes comprehensive testing, deployment to a production environment, and setting up monitoring tools to track performance and errors in real-time. These steps are crucial for maintaining a high-quality application that meets user needs and expectations.
Module 8: Additional Enhancements and Best Practices
In this module, we will incorporate additional enhancements and best practices to improve the security, performance, and maintainability of your job portal. This includes implementing security measures, optimizing the database, enhancing code quality, and setting up CI/CD pipelines.
1. Security Enhancements
Steps:
Rate Limiting: Implement rate limiting to prevent abuse of your API endpoints.
// app/Http/Kernel.php
protected $middlewareGroups = [
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
HTTPS: Ensure your application is served over HTTPS. This can be enforced at the server level (Apache/Nginx) and by redirecting HTTP to HTTPS in Laravel.
// app/Http/Middleware/RedirectIfAuthenticated.php
if (!$request->secure() && env('APP_ENV') === 'production') {
return redirect()->secure($request->getRequestUri());
}
Input Sanitization: Always sanitize and validate user inputs to prevent SQL injection and XSS attacks.
CSRF Protection: Laravel has CSRF protection enabled by default for all POST, PUT, PATCH, and DELETE requests. Ensure it’s correctly implemented by using
@csrf
in forms.
2. Database Optimization
Steps:
Indexes: Add indexes to columns that are frequently used in queries.
// database/migrations/xxxx_xx_xx_create_some_table.php
public function up()
{
Schema::create('some_table', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->index();
$table->string('title')->index();
$table->timestamps();
});
}
Database Caching: Use Laravel’s caching mechanisms to cache frequently accessed data.
$jobs = Cache::remember('jobs', 60, function () {
return JobPost::all();
});
Database Backups: Regularly back up your database using tools like Laravel Backup.
composer require spatie/laravel-backup
php artisan vendor:publish --provider="Spatie\Backup\BackupServiceProvider"
php artisan backup:run
3. Code Quality
Steps:
Code Review: Implement a code review process using GitHub pull requests to ensure code quality and consistency.
Static Analysis: Use PHPStan or Larastan for static analysis.
composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse
Linting: Use PHP-CS-Fixer or similar tools to enforce coding standards.
composer require --dev friendsofphp/php-cs-fixer
vendor/bin/php-cs-fixer fix
Automated Testing: Continuously add unit and feature tests to cover new functionalities and edge cases.
4. Performance Enhancements
Steps:
Queue Jobs: Offload time-consuming tasks to queues.
$job = new SendNotification($details);
dispatch($job);
Load Balancing: Use load balancers to distribute traffic across multiple servers.
Asset Optimization: Minify and combine CSS and JavaScript files.
npm run production
CDN: Use a Content Delivery Network (CDN) to serve static assets faster.
5. Documentation
Steps:
API Documentation: Document your API endpoints using tools like Swagger or Laravel API Documentation Generator.
composer require mpociot/laravel-apidoc-generator
php artisan apidoc:generate
Code Documentation: Use PHPDoc to document your code.
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}
6. Continuous Integration and Deployment (CI/CD)
Steps:
Set Up CI/CD: Use GitHub Actions, Travis CI, or Jenkins for CI/CD.
7. User Experience Enhancements
Steps:
Improved Search:
Implement full-text search using tools like Elasticsearch or Algolia.
User Analytics:
Integrate user analytics to track user behavior.
Feedback Mechanism:
Continuously collect feedback and iterate on the application.
Implementation Example for CI/CD with GitHub Actions
Steps:
Create a GitHub Actions Workflow:
7. User Experience Enhancements
Steps:
Improved Search: Implement full-text search using tools like Elasticsearch or Algolia.
User Analytics: Integrate user analytics to track user behavior.
Feedback Mechanism: Continuously collect feedback and iterate on the application.
Implementation Example for CI/CD with GitHub Actions
Steps:
- Create a GitHub Actions Workflow:
# .github/workflows/laravel.yml
name: Laravel CI
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
laravel-tests:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: jobportal_test
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping --silent" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@2.10.0
with:
php-version: 7.4
extensions: mbstring, pdo, mysql
coverage: none
- name: Install Composer dependencies
run: composer install
- name: Copy .env.example to .env
run: cp .env.example .env
- name: Generate application key
run: php artisan key:generate
- name: Run migrations
run: php artisan migrate --env=testing --force
- name: Run tests
run: php artisan test
This workflow will automatically run your tests whenever code is pushed to the master branch or a pull request is opened.
By completing Module 8, you have enhanced your job portal with additional security measures, optimized database performance, improved code quality, implemented CI/CD pipelines, and added user experience improvements. These best practices will help maintain a high-quality, secure, and efficient application that meets user needs and expectations.
Your job portal is now not only robust and functional but also optimized for security, performance, and maintainability. Continue to gather feedback, monitor performance, and iterate on the application to keep it up-to-date and user-friendly.
Welcome to DevTechTutor.com, your ultimate resource for mastering web development and technology! Whether you're a beginner eager to dive into coding or an experienced developer looking to sharpen your skills, DevTechTutor.com is here to guide you every step of the way. Our mission is to make learning web development accessible, engaging, and effective.