web-based Helpdesk Ticketing Solution from scratch for a small/medium organization with simple hosting using PHP + Laravel,
web-based Helpdesk Ticketing Solution from scratch for a small/medium organization with simple hosting using PHP + Laravel,
1. System Overview
Goal: Build a web-based system to manage support requests (tickets) with user login, ticket creation, assignment, tracking, and reporting.
Stack:
-
Backend: PHP with Laravel framework
-
Frontend: Blade templates (Laravel’s default) + optional JS for interactivity
-
Database: MySQL or MariaDB
-
Hosting: Shared hosting or VPS with PHP and MySQL support
Users / Roles:
-
Admin: Manage users, categories, view reports, assign tickets
-
Support Agent: View assigned tickets, update status, communicate with users
-
End User: Create tickets, view their own tickets, receive updates
2. Core Features
Ticket Management:
-
Create, view, edit, and close tickets
-
Assign tickets to support agents
-
Categorize tickets (IT, HR, Facilities, etc.)
-
Priority levels (Low, Medium, High, Critical)
User Management:
-
Register / Login system for users
-
Admin can add/edit agents and users
Communication / Updates:
-
Add comments or replies to tickets
-
Notify users via email on ticket creation/updates (optional SMTP integration)
Dashboard / Reporting:
-
Admin/agent dashboard showing open, pending, and resolved tickets
-
Filter tickets by category, priority, or status
-
Simple charts or tables for ticket statistics
Optional / Advanced Features:
-
SLA management (track response/resolution time)
-
Knowledge base for FAQs
-
Attachments (e.g., screenshots of issues)
3. Database Design
Here’s a simple schema:
Tables:
-
users
| Column | Type | Description |
|--------|------|-------------|
| id | INT (PK) | User ID |
| name | VARCHAR | Full name |
| email | VARCHAR | Login email |
| password | VARCHAR | Hashed password |
| role | ENUM('admin','agent','user') | User role |
| created_at, updated_at | TIMESTAMP | Laravel timestamps | -
tickets
| Column | Type | Description |
|--------|------|-------------|
| id | INT (PK) | Ticket ID |
| user_id | INT (FK) | Who created the ticket |
| agent_id | INT (FK) | Assigned agent |
| category | VARCHAR | Ticket category |
| priority | ENUM('Low','Medium','High','Critical') | Priority |
| status | ENUM('Open','In Progress','Resolved','Closed') | Ticket status |
| subject | VARCHAR | Ticket subject |
| description | TEXT | Detailed description |
| created_at, updated_at | TIMESTAMP | Laravel timestamps | -
ticket_comments
| Column | Type | Description |
|--------|------|-------------|
| id | INT (PK) | Comment ID |
| ticket_id | INT (FK) | Associated ticket |
| user_id | INT (FK) | Who commented |
| comment | TEXT | Comment text |
| created_at | TIMESTAMP | Timestamp | -
categories (optional for dynamic categories)
| Column | Type | Description |
|--------|------|-------------|
| id | INT (PK) | Category ID |
| name | VARCHAR | Category name |
4. Laravel Implementation Plan
-
Setup Laravel
composer create-project laravel/laravel helpdesk
cd helpdesk
php artisan serve
-
Database Configuration
-
Configure
.envfor MySQL:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=helpdesk
DB_USERNAME=root
DB_PASSWORD=
-
Create Models & Migrations
php artisan make:model Ticket -m
php artisan make:model TicketComment -m
php artisan make:model Category -m
php artisan make:model User -m
-
Add relationships in models:
-
User→ hasMany Tickets, hasMany TicketComments -
Ticket→ belongsTo User, belongsTo Agent, hasMany TicketComments -
TicketComment→ belongsTo Ticket, belongsTo User
-
-
Authentication
-
Use Laravel Breeze or Jetstream for login/register functionality:
composer require laravel/breeze --dev
php artisan breeze:install
npm install && npm run dev
php artisan migrate
-
Ticket CRUD
-
Create controllers:
TicketController,TicketCommentController,CategoryController -
Define routes in
web.php:
Route::resource('tickets', TicketController::class);
Route::post('tickets/{ticket}/comments', [TicketCommentController::class, 'store']);
-
Dashboard & Views
-
Blade templates for:
-
Ticket list (all tickets for admin/assigned tickets for agents)
-
Ticket creation form
-
Ticket detail view with comments
-
-
Optional Features
-
Email notifications via Laravel’s Mail system
-
File uploads for attachments
-
Filters and reports using Laravel Eloquent queries
5. Deployment & Hosting
-
Shared hosting (cPanel) or VPS with PHP >= 8, MySQL, Apache/Nginx
-
Upload Laravel files, set up
.env, run migrations:
php artisan migrate --force
-
Set folder permissions for
storageandbootstrap/cache -
Use Laravel scheduler for automated tasks (like email reminders)
6. Scaling / Future Enhancements
-
Add roles & permissions using
spatie/laravel-permissionpackage -
API endpoints for mobile app integration
-
Integrate real-time notifications with Laravel Echo & Pusher
-
Analytics dashboard with charts (Chart.js or ApexCharts)
+---------------------+
| End Users |
| (Employees/Clients)|
+----------+----------+
|
| Create Ticket
v
+---------------------+
| Web Frontend |
| (Blade Templates / |
| JS Interactivity) |
+----------+----------+
|
| Submit / View Tickets
v
+---------------------+
| Laravel Backend |
| (Controllers, |
| Models, Services) |
+----------+----------+
|
+-------------------------+--------------------------+
| | |
v v v
+----------------+ +----------------+ +----------------+
| Ticket System | | User System | | Notification/ |
| (Tickets, | | (Users & | | Email System |
| Categories, | | Roles/Agents) | | (Optional) |
| Priority, | +----------------+ +----------------+
| Status, |
| Comments) |
+--------+-------+
|
| Read/Write
v
+---------------------------+
| Database |
| MySQL / MariaDB |
|---------------------------|
| Tables: |
| - users |
| - tickets |
| - ticket_comments |
| - categories |
+---------------------------+
^
|
| Query/Update
v
+---------------------------+
| Admin / Support Agents |
| - View Tickets |
| - Assign Tickets |
| - Update Status / Reply |
| - Generate Reports |
+---------------------------+
-----------------------------------------------------------------------
+-------------------+
| Ticket Created |
| (by End User) |
+---------+---------+
|
v
+-------------------+
| Ticket Assigned |
| (to Support Agent)|
+---------+---------+
|
v
+-------------------+
| Ticket In Progress|
| (Investigation / |
| Updates / Replies)|
+---------+---------+
|
+---------+---------+
| |
v v
+-------------------+ +-------------------+
| Resolved | | Escalated / Pending|
| (Issue Fixed) | | (Further Action) |
+---------+---------+ +---------+---------+
| |
v |
+-------------------+ |
| Ticket Closed | <-------+
| (User Informed) |
+-------------------+
1. Ticket Lifecycle Flowchart with Statuses
+-------------------+
| Ticket Created |
| status = 'open' |
| (by End User) |
+---------+---------+
|
v
+-------------------+
| Ticket Assigned |
| status = 'assigned'|
| (to Support Agent)|
+---------+---------+
|
v
+-------------------+
| In Progress |
| status = 'in_progress' |
| (Agent working / |
| adding comments) |
+---------+---------+
|
+---------+---------+
| |
v v
+-------------------+ +-------------------+
| Resolved | | Escalated / Pending|
| status='resolved' | | status='pending' |
| (Issue fixed) | | (Need more action)|
+---------+---------+ +---------+---------+
| |
v |
+-------------------+ |
| Ticket Closed | <-------+
| status='closed' |
| (User Informed) |
+-------------------+
2. Ticket Status Table
| Status Code | Description | Laravel Enum / DB Value |
|---|---|---|
| open | Ticket created, not yet assigned | 'open' |
| assigned | Assigned to an agent | 'assigned' |
| in_progress | Agent is working on ticket | 'in_progress' |
| resolved | Issue resolved by agent | 'resolved' |
| pending | Needs more info / escalated | 'pending' |
| closed | Ticket confirmed resolved and closed | 'closed' |
3. Suggested Database Table Design (tickets)
Table: tickets
+-------------------+---------------------+--------------------------+
| Column Name | Type | Description |
+-------------------+---------------------+--------------------------+
| id | INT (PK, auto_inc) | Ticket ID |
| user_id | INT (FK) | Who created the ticket |
| agent_id | INT (FK, nullable) | Assigned agent |
| category | VARCHAR(50) | Ticket category (IT/HR) |
| priority | ENUM('Low','Med','High','Critical') | Priority level |
| status | ENUM('open','assigned','in_progress','resolved','pending','closed') | Current status |
| subject | VARCHAR(255) | Ticket subject |
| description | TEXT | Detailed issue |
| created_at | TIMESTAMP | Auto timestamp |
| updated_at | TIMESTAMP | Auto timestamp |
+-------------------+---------------------+--------------------------+
4. Laravel Model Example (Ticket.php)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Ticket extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'agent_id',
'category',
'priority',
'status',
'subject',
'description',
];
// Relationships
public function user() {
return $this->belongsTo(User::class, 'user_id');
}
public function agent() {
return $this->belongsTo(User::class, 'agent_id');
}
public function comments() {
return $this->hasMany(TicketComment::class);
}
// Status check helper functions
public function isOpen() {
return $this->status === 'open';
}
public function isAssigned() {
return $this->status === 'assigned';
}
public function isInProgress() {
return $this->status === 'in_progress';
}
public function isResolved() {
return $this->status === 'resolved';
}
public function isPending() {
return $this->status === 'pending';
}
public function isClosed() {
return $this->status === 'closed';
}
}
5. Laravel Migration Example (tickets table)
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTicketsTable extends Migration
{
public function up()
{
Schema::create('tickets', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained('users');
$table->foreignId('agent_id')->nullable()->constrained('users');
$table->string('category', 50);
$table->enum('priority', ['Low','Medium','High','Critical'])->default('Low');
$table->enum('status', ['open','assigned','in_progress','resolved','pending','closed'])->default('open');
$table->string('subject');
$table->text('description');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('tickets');
}
}
Ticket → TicketComment relationship, including Users, Agents, database tables, ticket lifecycle, and Laravel model interactions. This will give you a full picture of the system architecture for coding.
+---------------------+
| Users |
|---------------------|
| id (PK) |
| name |
| email |
| password |
| role ('user','agent','admin') |
+---------+-----------+
|
| Creates / Comments
v
+---------------------+
| Tickets |
|---------------------|
| id (PK) |
| user_id (FK -> users.id) |
| agent_id (FK -> users.id, nullable) |
| category |
| priority |
| status |
| subject |
| description |
| created_at |
| updated_at |
+---------+-----------+
|
| Has Many
v
+---------------------+
| TicketComments |
|---------------------|
| id (PK) |
| ticket_id (FK -> tickets.id) |
| user_id (FK -> users.id) |
| comment |
| created_at |
+---------------------+
Explanation of the Diagram
-
Users Table
-
Stores all users (end users, agents, admin).
-
The
rolefield determines what permissions each user has.
-
-
Tickets Table
-
Each ticket is created by a user (
user_id). -
Each ticket can be assigned to an agent (
agent_id) or remain unassigned. -
Tracks
statusthrough the ticket lifecycle (open,assigned,in_progress,resolved,pending,closed). -
Ticket belongs to a user (creator) and optionally to an agent (assignee).
-
-
TicketComments Table
-
Each comment belongs to a ticket (
ticket_id) and is made by a user (user_id). -
Allows conversation/history between the user and the agent on a ticket.
-
How Laravel Models Interact
-
User.php
public function ticketsCreated() { return $this->hasMany(Ticket::class, 'user_id'); }
public function ticketsAssigned() { return $this->hasMany(Ticket::class, 'agent_id'); }
public function comments() { return $this->hasMany(TicketComment::class); }
-
Ticket.php
public function user() { return $this->belongsTo(User::class, 'user_id'); }
public function agent() { return $this->belongsTo(User::class, 'agent_id'); }
public function comments() { return $this->hasMany(TicketComment::class); }
-
TicketComment.php
public function ticket() { return $this->belongsTo(Ticket::class); }
public function user() { return $this->belongsTo(User::class); }
Ticket Lifecycle Integration
Ticket Status Field → Lifecycle
--------------------------------
open → Ticket just created
assigned → Ticket assigned to an agent
in_progress → Agent is working / adding comments
resolved → Issue resolved by agent
pending → Waiting for more info or escalation
closed → Ticket confirmed closed by user/admin
Flow:
-
UserscreateTickets→Ticketsassigned toAgents→TicketCommentsallow conversation → Status updates change lifecycle → Final closure.
This diagram, combined with the Laravel relationships, gives a complete blueprint for implementation:
-
Database tables and foreign keys
-
Relationships in Laravel models
-
Ticket lifecycle management
-
Commenting system

Comments
Post a Comment