Initial commit - lms-v2 + CLAUDE.md

This commit is contained in:
Iwit
2026-05-30 22:15:16 +07:00
commit 5811409e2d
183 changed files with 23225 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
<?php
use App\Http\Controllers\Auth\VerifyEmailController;
use Illuminate\Support\Facades\Route;
use Livewire\Volt\Volt;
Route::middleware('guest')->group(function () {
Volt::route('register', 'pages.auth.register')
->name('register');
Volt::route('login', 'pages.auth.login')
->name('login');
Volt::route('forgot-password', 'pages.auth.forgot-password')
->name('password.request');
Volt::route('reset-password/{token}', 'pages.auth.reset-password')
->name('password.reset');
});
Route::middleware('auth')->group(function () {
Volt::route('verify-email', 'pages.auth.verify-email')
->name('verification.notice');
Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
->middleware(['signed', 'throttle:6,1'])
->name('verification.verify');
Volt::route('confirm-password', 'pages.auth.confirm-password')
->name('password.confirm');
});
+8
View File
@@ -0,0 +1,8 @@
<?php
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');
+142
View File
@@ -0,0 +1,142 @@
<?php
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
// Import Controllers agar penulisan Route lebih bersih
use App\Http\Controllers\Admin\DashboardController;
use App\Http\Controllers\Admin\ExamManagementController;
use App\Http\Controllers\Admin\ReportController;
use App\Http\Controllers\Admin\DepartmentController;
use App\Http\Controllers\Admin\PositionController;
use App\Http\Controllers\Admin\EmployeeController;
use App\Http\Controllers\Cbt\UserDashboardController;
/*
|--------------------------------------------------------------------------
| 1. ALUR PENGALIHAN UTAMA (ROOT REDIRECT)
|--------------------------------------------------------------------------
*/
Route::get('/', function () {
return redirect()->route('login');
});
/*
|--------------------------------------------------------------------------
| 2. AREA PROTEKSI AKSES UTAMA (AUTH & AUTENTIKASI)
|--------------------------------------------------------------------------
*/
Route::middleware(['auth'])->group(function () {
// GLOBAL LOGOUT HANDLER
Route::post('/logout', function (Request $request) {
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('login');
})->name('logout');
/*
* ====================================================================
* RUTE PAKSA GANTI PASSWORD (Diakses saat first login)
* ====================================================================
*/
Route::get('/force-change-password', function () {
return view('livewire.pages.auth.force-change-password');
})->name('password.force-change');
Route::post('/force-change-password', function (Request $request) {
$request->validate([
'password' => 'required|string|min:8|confirmed',
]);
$user = $request->user();
$user->password = Hash::make($request->password);
$user->must_change_password = false; // Cabut status wajib ganti
$user->save();
// Redirect cerdas berdasarkan role setelah ganti password
if ($user->hasRole(['admin', 'trainer'])) {
return redirect()->route('admin.dashboard')->with('success', 'Password default berhasil diganti!');
}
return redirect()->route('cbt.dashboard')->with('success', 'Password berhasil diganti. Selamat datang!');
})->name('password.force-update');
/*
* ====================================================================
* AREA APLIKASI UTAMA
* (Hanya bisa diakses jika user SUDAH mengganti password default)
* ====================================================================
*/
Route::middleware(['force.password'])->group(function () {
/*
* A. AREA PANEL ADMIN & TRAINER (PREFIX: /admin)
* Dilindungi oleh Spatie: Hanya admin atau trainer
*/
Route::prefix('admin')->name('admin.')->middleware(['role:admin|trainer'])->group(function () {
// Dashboard Utama Admin
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
// Modul Ujian & Bank Soal
Route::get('/question-bank', [ExamManagementController::class, 'questionBank'])->name('exams.questions');
Route::get('/exams', [ExamManagementController::class, 'index'])->name('exams.index');
// ----------------------------------------------------------------
// PERBAIKAN: Rute Export & Import Karyawan (Disesuaikan dengan Prefix Grup)
// ----------------------------------------------------------------
Route::get('employees/export/excel', [EmployeeController::class, 'exportExcel'])->name('employees.export.excel');
Route::get('employees/export/pdf', [EmployeeController::class, 'exportPdf'])->name('employees.export.pdf');
Route::get('employees/import', [EmployeeController::class, 'importView'])->name('employees.import');
Route::get('employees/import/template', [EmployeeController::class, 'downloadTemplate'])->name('employees.import.template');
Route::post('employees/import/preview', [EmployeeController::class, 'importPreview'])->name('employees.import.preview');
Route::post('employees/import/process', [EmployeeController::class, 'importProcess'])->name('employees.import.process');
// Rute Export Master Data
Route::get('departments/export/excel', [DepartmentController::class, 'exportExcel'])->name('departments.export.excel');
Route::get('departments/export/pdf', [DepartmentController::class, 'exportPdf'])->name('departments.export.pdf');
Route::get('positions/export/excel', [PositionController::class, 'exportExcel'])->name('positions.export.excel');
Route::get('positions/export/pdf', [PositionController::class, 'exportPdf'])->name('positions.export.pdf');
// Master Data & Karyawan (Resources harus diletakkan di bawah rute custom export/import)
Route::resource('departments', DepartmentController::class);
Route::resource('positions', PositionController::class);
Route::resource('employees', EmployeeController::class);
Route::get('/sops', [DashboardController::class, 'sopIndex'])->name('sops.index');
});
/*
* B. AREA PANEL REPORT TRAINING
* Dilindungi oleh Spatie: Hanya admin atau trainer
*/
Route::prefix('reports')->name('reports.')->middleware(['role:admin|trainer'])->group(function () {
Route::get('/training', [ReportController::class, 'training'])->name('training');
Route::get('/training/{user}', [ReportController::class, 'showTraining'])->name('training.show');
});
/*
* C. AREA PORTAL KARYAWAN / TRAINEE (PREFIX: /portal)
* Dilindungi oleh Spatie: Hanya karyawan
*/
Route::prefix('portal')->name('cbt.')->middleware(['role:karyawan'])->group(function () {
Route::get('/dashboard', [UserDashboardController::class, 'index'])->name('dashboard');
});
}); // End of force.password middleware
}); // End of auth middleware
/*
|--------------------------------------------------------------------------
| 3. FILE AUTENTIKASI BAWAAN (LARAVEL BREEZE / VOLT)
|--------------------------------------------------------------------------
*/
require __DIR__.'/auth.php';