Loading
Please wait...

Laravel E-Learning Rebuild

1

Part 1: Introduction & Why I'm Upgrading

2

Part 2: Setting Up Laravel 11 + Filament

3

Part 3: Database Schema Design

4

Part 4: Authentication & User Roles

5

Part 5: Building the Exam System

6

Part 6: Real-Time Features

7

Part 7: Testing Strategy

8

Part 8: Deployment

2 Januari 2026

Rebuilding My Laravel E-Learning App: A Journey from 5.2 to Modern Laravel

The story of upgrading a legacy Laravel 5.2 e-learning platform to modern Laravel with Filament, Livewire, and best practices. Plus, a sneak peek at the upcoming tutorial series.

5 min read


The Problem: A 7-Year-Old Codebase

Back in 2017, I built an e-learning platform for online examinations at a junior high school. It was written in Laravel 5.2 with PHP 5.6β€”the standard stack at the time.

Fast forward to 2026, and that codebase is still being used. It works, but:

  • πŸ”΄ Security vulnerabilities β€” Laravel 5.2 hasn't received security patches in years
  • πŸ”΄ PHP 5.6 is dead β€” Most hosting providers don't support it anymore
  • πŸ”΄ Modern features missing β€” No real-time updates, poor mobile experience
  • πŸ”΄ Maintenance nightmare β€” Dependencies are outdated, documentation is scarce

It was time for a complete rebuild.

What the Original System Does

Before diving into the upgrade, let me explain what this e-learning platform does:

For Students

  • πŸ“Š Dashboard β€” View enrolled courses and upcoming exams
  • πŸ“ Online Examinations β€” Take timed exams with multiple choice questions
  • πŸ“ˆ Grade Reports β€” View exam results and overall progress
  • πŸ’¬ Discussion Forums β€” Interact with teachers and classmates

For Teachers

  • πŸ“š Exam Management β€” Create, edit, and schedule online exams
  • ❓ Question Bank β€” Manage questions with different difficulty levels
  • πŸ“Š Analytics β€” View student performance and identify struggling areas
  • πŸ“‹ Assignment Grading β€” Review and grade student submissions

The Upgrade Strategy

I considered two approaches:

ApproachProsCons
Incremental UpgradeLess risky, keep existing code5.2 β†’ 5.3 β†’ 5.4 β†’ ... β†’ 11 (painful)
Full RebuildClean slate, modern architectureMore effort upfront, migration needed

I chose the full rebuild. Here's why:

  1. The jump is too big β€” Laravel 5.2 to 11 spans 9 major versions
  2. Architecture has evolved β€” Modern Laravel uses different patterns
  3. Better tools exist now β€” Filament, Livewire, and Inertia didn't exist in 2017
  4. Learning opportunity β€” Building from scratch means understanding every line

The New Tech Stack

Here's what I'm using for the rebuilt version:

ComponentOld (2017)New (2026)
FrameworkLaravel 5.2Laravel 11
PHP5.68.3
Admin PanelCustom BladeFilament 3
FrontendjQuery + BootstrapLivewire 3 + Tailwind
AuthenticationCustomLaravel Breeze
DatabaseMySQL 5.6MySQL 8 / PostgreSQL
TestingNone πŸ˜…Pest PHP
DeploymentFTP (yes, really)GitHub Actions + VPS

Key Architectural Decisions

1. Filament for Admin Panel

Instead of building custom admin CRUD from scratch, I'm using Filament 3. It provides:

// This is all you need for a complete CRUD
class ExamResource extends Resource
{
    protected static ?string $model = Exam::class;
    
    public static function form(Form $form): Form
    {
        return $form->schema([
            TextInput::make('title')->required(),
            DateTimePicker::make('start_time'),
            DateTimePicker::make('end_time'),
            Select::make('subject_id')
                ->relationship('subject', 'name'),
        ]);
    }
}

What took 500+ lines of custom code in 2017 now takes 50 lines with Filament.

2. Livewire for Real-Time Exam

The old exam system used JavaScript polling to check time remaining. Now with Livewire:

class TakeExam extends Component
{
    public Exam $exam;
    public int $timeRemaining;
    
    public function mount(Exam $exam)
    {
        $this->exam = $exam;
        $this->timeRemaining = $exam->duration_minutes * 60;
    }
    
    #[Computed]
    public function isTimeUp(): bool
    {
        return $this->timeRemaining <= 0;
    }
}

Real-time updates without writing custom WebSocket code.

3. Proper Testing from Day One

The original codebase had zero tests. The new version uses Pest PHP:

it('prevents students from taking expired exams', function () {
    $exam = Exam::factory()->expired()->create();
    $student = User::factory()->student()->create();
    
    actingAs($student)
        ->get(route('exams.take', $exam))
        ->assertForbidden();
});

Every feature is tested before it's considered "done."

Migration Strategy

The trickiest part is migrating data from the old system. Here's my approach:

Step 1: Export Old Data

-- Export from old MySQL database
SELECT * FROM siswa INTO OUTFILE '/tmp/students.csv';
SELECT * FROM guru INTO OUTFILE '/tmp/teachers.csv';
SELECT * FROM ujian INTO OUTFILE '/tmp/exams.csv';

Step 2: Transform to New Schema

// Laravel Seeder for migration
class MigrateOldDataSeeder extends Seeder
{
    public function run(): void
    {
        $oldStudents = json_decode(
            file_get_contents(database_path('legacy/students.json'))
        );
        
        foreach ($oldStudents as $old) {
            User::create([
                'name' => $old->nama_siswa,
                'email' => $old->email ?? $old->nis . '@school.local',
                'role' => 'student',
                'legacy_id' => $old->id,
            ]);
        }
    }
}

Step 3: Validate & Test

Run both systems in parallel, compare outputs, and verify data integrity.

Lessons Learned (So Far)

1. Don't Fear the Rebuild

Sometimes, the best refactor is a rewrite. The old codebase served its purpose, but clinging to it would have caused more pain long-term.

2. Modern Laravel is a Joy

The developer experience in Laravel 11 is incredible. Artisan commands, Tinker, Laravel Herdβ€”everything just works.

3. Document As You Build

I'm writing this article as I build. It forces me to explain my decisions, which often reveals flaws in my thinking.

Complete Tutorial Series

This article is Part 1 of a complete series documenting the entire rebuild:

PartTopicLink
1Introduction & Why I'm Upgradingβœ… This article
2Setting Up Laravel 11 + FilamentRead β†’
3Database Schema DesignRead β†’
4User Authentication & RolesRead β†’
5Building the Exam SystemRead β†’
6Real-Time Features with LivewireRead β†’
7Testing StrategyRead β†’
8Deployment to ProductionRead β†’

The Repository

The original legacy codebase is available on GitHub:

πŸ”— mfarim/laravel-elearning β€” 42 ⭐ | 15 Forks

The new version will be released as a separate repository once it's ready for production.

Conclusion

Upgrading a 7-year-old Laravel application isn't just about changing version numbersβ€”it's about rethinking architecture, adopting modern tools, and building something that will last another 7 years.

If you're facing a similar legacy upgrade challenge, I hope this series helps you navigate the process. Feel free to reach out with questions or share your own upgrade stories!


Have a legacy Laravel app that needs upgrading? I offer consultation services for Laravel modernization. Get in touch.

Continue Reading

Previous article

← Previous Article

Why I Deploy Next.js on a VPS Without Docker (And You Should Consider It Too)

Next Article β†’

Building an Event Management System for a Developer Community

Next article