Bagian 1 dari seri
Persiapan Project TOPSIS Laravel, Bootstrap, Login, dan Database
Diterbitkan 21 September 2026
Ikuti langkah berikut secara berurutan. Setelah selesai, project harus bisa login dan menampilkan dashboard.
Buat Project Laravel
composer create-project laravel/laravel topsis-laravel
cd topsis-laravel
php artisan key:generate
Konfigurasi Database
Buat database:
topsis_laravel
Atur .env:
APP_NAME="TOPSIS Laravel"
APP_URL=http://127.0.0.1:8000
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=topsis_laravel
DB_USERNAME=root
DB_PASSWORD=
Buat Model dan Migration
php artisan make:model Kriteria -m
php artisan make:model Alternatif -m
php artisan make:model Penilaian -m
php artisan make:controller AuthController
php artisan make:controller DashboardController
Migration Kriteria
Buka migration tabel kriteria:
Schema::create('kriteria', function (Blueprint $table) {
$table->id();
$table->string('kode', 10)->unique();
$table->string('nama');
$table->decimal('bobot', 12, 6);
$table->enum('atribut', ['benefit', 'cost']);
$table->timestamps();
});
Migration Alternatif
Schema::create('alternatif', function (Blueprint $table) {
$table->id();
$table->string('kode', 10)->unique();
$table->string('nama');
$table->decimal('nilai_preferensi', 14, 10)->nullable();
$table->unsignedInteger('ranking')->nullable();
$table->timestamps();
});
Migration Penilaian
Schema::create('penilaian', function (Blueprint $table) {
$table->id();
$table->foreignId('alternatif_id')
->constrained('alternatif')
->cascadeOnDelete();
$table->foreignId('kriteria_id')
->constrained('kriteria')
->cascadeOnDelete();
$table->decimal('nilai', 14, 6);
$table->timestamps();
$table->unique(
['alternatif_id', 'kriteria_id'],
'penilaian_alternatif_kriteria_unique'
);
});
Model Kriteria
app/Models/Kriteria.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Kriteria extends Model
{
protected $table = 'kriteria';
protected $fillable = [
'kode',
'nama',
'bobot',
'atribut',
];
protected $casts = [
'bobot' => 'float',
];
public function penilaian()
{
return $this->hasMany(Penilaian::class);
}
}
Model Alternatif
app/Models/Alternatif.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Alternatif extends Model
{
protected $table = 'alternatif';
protected $fillable = [
'kode',
'nama',
'nilai_preferensi',
'ranking',
];
protected $casts = [
'nilai_preferensi' => 'float',
];
public function penilaian()
{
return $this->hasMany(Penilaian::class);
}
}
Model Penilaian
app/Models/Penilaian.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Penilaian extends Model
{
protected $table = 'penilaian';
protected $fillable = [
'alternatif_id',
'kriteria_id',
'nilai',
];
protected $casts = [
'nilai' => 'float',
];
public function alternatif()
{
return $this->belongsTo(Alternatif::class);
}
public function kriteria()
{
return $this->belongsTo(Kriteria::class);
}
}
Buat Seeder
php artisan make:seeder TopsisSeeder
Isi database/seeders/TopsisSeeder.php:
<?php
namespace Database\Seeders;
use App\Models\Alternatif;
use App\Models\Kriteria;
use App\Models\Penilaian;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class TopsisSeeder extends Seeder
{
public function run(): void
{
User::updateOrCreate(
['email' => 'admin@example.com'],
[
'name' => 'Administrator',
'password' => Hash::make('admin12345'),
]
);
$dataKriteria = [
[
'kode' => 'C1',
'nama' => 'Harga',
'bobot' => 30,
'atribut' => 'cost',
],
[
'kode' => 'C2',
'nama' => 'Kualitas',
'bobot' => 40,
'atribut' => 'benefit',
],
[
'kode' => 'C3',
'nama' => 'Pelayanan',
'bobot' => 30,
'atribut' => 'benefit',
],
];
foreach ($dataKriteria as $item) {
Kriteria::updateOrCreate(
['kode' => $item['kode']],
$item
);
}
$dataAlternatif = [
['kode' => 'A1', 'nama' => 'Supplier A'],
['kode' => 'A2', 'nama' => 'Supplier B'],
['kode' => 'A3', 'nama' => 'Supplier C'],
];
foreach ($dataAlternatif as $item) {
Alternatif::updateOrCreate(
['kode' => $item['kode']],
[
'nama' => $item['nama'],
'nilai_preferensi' => null,
'ranking' => null,
]
);
}
$nilaiAwal = [
'A1' => ['C1' => 80, 'C2' => 8, 'C3' => 9],
'A2' => ['C1' => 70, 'C2' => 9, 'C3' => 8],
'A3' => ['C1' => 75, 'C2' => 7, 'C3' => 9],
];
$kriteria = Kriteria::all()->keyBy('kode');
$alternatif = Alternatif::all()->keyBy('kode');
foreach ($nilaiAwal as $kodeAlternatif => $nilaiKriteria) {
foreach ($nilaiKriteria as $kodeKriteria => $nilai) {
Penilaian::updateOrCreate(
[
'alternatif_id' => $alternatif[$kodeAlternatif]->id,
'kriteria_id' => $kriteria[$kodeKriteria]->id,
],
[
'nilai' => $nilai,
]
);
}
}
}
}
Daftarkan pada database/seeders/DatabaseSeeder.php:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call(TopsisSeeder::class);
}
}
Jalankan:
php artisan migrate:fresh --seed
Data Login
Email : admin@example.com
Password : admin12345
AuthController
app/Http/Controllers/AuthController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
public function create()
{
return view('auth.login');
}
public function store(Request $request)
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt(
$credentials,
$request->boolean('remember')
)) {
$request->session()->regenerate();
return redirect()->intended(route('dashboard'));
}
return back()
->withErrors([
'email' => 'Email atau password salah.',
])
->onlyInput('email');
}
public function destroy(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('login');
}
}
DashboardController
app/Http/Controllers/DashboardController.php:
<?php
namespace App\Http\Controllers;
class DashboardController extends Controller
{
public function index()
{
return view('dashboard');
}
}
Route Dasar
routes/web.php:
<?php
use App\Http\Controllers\AuthController;
use App\Http\Controllers\DashboardController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return redirect()->route('dashboard');
});
Route::middleware('guest')->group(function () {
Route::get(
'/login',
[AuthController::class, 'create']
)->name('login');
Route::post(
'/login',
[AuthController::class, 'store']
)
->middleware('throttle:5,1')
->name('login.store');
});
Route::middleware('auth')->group(function () {
Route::get(
'/dashboard',
[DashboardController::class, 'index']
)->name('dashboard');
Route::post(
'/logout',
[AuthController::class, 'destroy']
)->name('logout');
});
Layout Bootstrap
Buat resources/views/layouts/app.blade.php:
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('title', 'TOPSIS Laravel')</title>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet">
</head>
<body class="bg-light">
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand fw-bold"
href="{{ route('dashboard') }}">
TOPSIS Laravel
</a>
@auth
<div class="d-flex align-items-center gap-3 text-white">
<span>{{ auth()->user()->name }}</span>
<form method="POST" action="{{ route('logout') }}">
@csrf
<button class="btn btn-outline-light btn-sm">
Logout
</button>
</form>
</div>
@endauth
</div>
</nav>
<main class="container py-4">
@if(session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
@if($errors->any())
<div class="alert alert-danger">
<ul class="mb-0">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@yield('content')
</main>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js">
</script>
</body>
</html>
Halaman Login
Buat resources/views/auth/login.blade.php:
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login TOPSIS Laravel</title>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet">
</head>
<body class="bg-light">
<div class="container min-vh-100 d-flex align-items-center justify-content-center">
<div class="card border-0 shadow-sm"
style="width:100%;max-width:420px">
<div class="card-body p-4">
<h1 class="h4 mb-4">Login TOPSIS Laravel</h1>
<form method="POST" action="{{ route('login.store') }}">
@csrf
<div class="mb-3">
<label class="form-label">Email</label>
<input
type="email"
name="email"
value="{{ old('email') }}"
class="form-control"
required
autofocus>
</div>
<div class="mb-3">
<label class="form-label">Password</label>
<input
type="password"
name="password"
class="form-control"
required>
</div>
<div class="form-check mb-3">
<input
class="form-check-input"
type="checkbox"
name="remember"
value="1"
id="remember">
<label
class="form-check-label"
for="remember">
Ingat saya
</label>
</div>
<button class="btn btn-primary w-100">
Login
</button>
</form>
</div>
</div>
</div>
</body>
</html>
Dashboard
Buat resources/views/dashboard.blade.php:
@extends('layouts.app')
@section('title', 'Dashboard')
@section('content')
<div class="card border-0 shadow-sm">
<div class="card-body">
<h1 class="h4">Dashboard TOPSIS</h1>
<p class="mb-0">
Project Laravel dan autentikasi berhasil dibuat.
</p>
</div>
</div>
@endsection
Menjalankan Project
Pastikan MySQL sudah aktif.
Jalankan:
php artisan serve
Buka:
http://127.0.0.1:8000
Halaman login:
http://127.0.0.1:8000/login


File yang Harus Sudah Ada
app/Models/Kriteria.php
app/Models/Alternatif.php
app/Models/Penilaian.php
app/Http/Controllers/AuthController.php
app/Http/Controllers/DashboardController.php
database/seeders/TopsisSeeder.php
resources/views/layouts/app.blade.php
resources/views/auth/login.blade.php
resources/views/dashboard.blade.php
routes/web.php
Checkpoint
Pastikan:
- project Laravel berjalan melalui
php artisan serve; - koneksi database berhasil;
- migration berhasil;
- seeder berhasil;
- login berhasil;
- logout berhasil;
- pengunjung yang belum login diarahkan ke halaman login;
- Bootstrap tampil normal;
- tabel
kriteria,alternatif, danpenilaiantersedia.




