CMS Blog Starter Laravel Livewire: Starter Kit Blog Modern dengan Laravel 13
Membangun website blog dari nol biasanya membutuhkan banyak pekerjaan yang sifatnya berulang. Mulai dari autentikasi pengguna, manajemen artikel, kategori, role dan permission, dashboard admin, upload gambar, hingga security hardening.
Karena itu, saya membuat CMS Blog Starter Laravel Livewire, sebuah starter kit CMS dan blog sederhana yang dibangun menggunakan Laravel 13, Livewire 4, Tailwind CSS v4, dan MySQL.
Project ini sudah dilengkapi autentikasi, roles & permissions, dashboard admin, manajemen konten, SEO metadata, upload featured image, Docker support, automated testing, serta berbagai lapisan keamanan.
Tujuan utamanya bukan membuat framework admin panel yang menyembunyikan banyak logic di balik abstraksi, tetapi menyediakan fondasi yang mudah dipahami, dibaca, dan dikembangkan. Setiap komponen Livewire, policy, migration, dan service ditulis secara eksplisit sehingga dapat langsung dipelajari dan dimodifikasi.
Fitur Utama
Website Publik
Bagian frontend menyediakan fondasi dasar untuk sebuah website blog:
Beranda editorial dengan hero, post unggulan, post terbaru, serta navigasi kategori.
Halaman blog dengan live search dan filter kategori menggunakan Livewire tanpa full page reload.
Halaman detail post dengan rendering Markdown yang aman, related posts, dan tag.
Dashboard Admin
Dashboard admin tersedia melalui:
/admin
Fitur yang tersedia meliputi:
Dashboard dengan statistik yang disesuaikan berdasarkan permission.
Author hanya dapat melihat data yang berkaitan dengan kontennya sendiri.
CRUD post lengkap.
Markdown editor dengan tab Write dan Preview.
Upload featured image.
Kategori dan tag.
SEO meta title dan meta description.
Status post draft atau published.
CRUD kategori.
Manajemen user.
Pengaturan nama situs, tagline, deskripsi, dan footer.
Manajemen user juga memiliki proteksi agar admin terakhir tidak dapat mengunci dirinya sendiri dari CMS.
Authentication dan Profile
Sistem autentikasi dibangun menggunakan Livewire dengan pola yang serupa dengan Laravel Breeze stack Livewire.
Fitur yang tersedia:
Login
Registrasi
Forgot password
Reset password
Email verification
Password confirmation
Profile management
Halaman profile dapat digunakan oleh semua pengguna, termasuk pengguna yang tidak memiliki role CMS, untuk:
Mengubah nama.
Mengubah email.
Mengubah password.
Menghapus akun.
Roles & Permissions
Project menggunakan spatie/laravel-permission untuk mengelola roles dan permissions.
Tersedia tiga role bawaan:
Admin
Editor
Author
Permission dibagi secara granular:
| Permission | Admin | Editor | Author |
|---|---|---|---|
view dashboard | ✅ | ✅ | ✅ |
manage own posts | ✅ | ✅ | ✅ |
manage all posts | ✅ | ✅ | — |
publish posts | ✅ | ✅ | — |
manage categories | ✅ | ✅ | — |
manage users | ✅ | — | — |
manage settings | ✅ | — | — |
Semua pengecekan authorization berada di app/Policies/*.php dan dipanggil kembali di setiap action method Livewire, bukan hanya saat mount().
Untuk menambahkan role baru, role dapat dibuat menggunakan:
Role::findOrCreate('nama', 'web');
Permission kemudian dapat diberikan menggunakan:
->syncPermissions([...]);
Setelah itu pilihan role dapat ditambahkan ke UserManager.
Tech Stack
| Komponen | Versi | Catatan |
|---|---|---|
| PHP | 8.4 | |
| Laravel | ^13.0 | Skeleton Laravel modern dengan konfigurasi terpusat di bootstrap/app.php |
| Livewire | ^4.0 | Menggunakan format multi-file class + view terpisah |
| Tailwind CSS | ^4.3 | CSS-first configuration melalui @theme |
| Spatie Laravel Permission | ^6.9 | Roles & permissions |
| MySQL | 8.0+ | |
| Vite | ^8.0 | Menggunakan Laravel Vite Plugin dan Tailwind Vite plugin |
Kenapa Livewire Multi-file?
Livewire 4 mendukung single-file component, tetapi starter kit ini memilih format multi-file agar struktur source code lebih mudah dibaca.
Class Livewire berada di:
app/Livewire/
Sedangkan Blade view berada di:
resources/views/livewire/
Pendekatan ini membuat logic PHP dan template Blade tetap terpisah sehingga lebih nyaman dipelajari dan lebih mudah ketika melakukan diff atau maintenance.
Format single-file tetap didukung Livewire 4 apabila dibutuhkan.
Persyaratan
Sebelum menjalankan project, pastikan environment sudah memiliki:
PHP 8.4.
Composer 2.x.
Node.js 20.19+ atau 22.12+.
npm.
MySQL 8.0+, atau MariaDB 10.6+.
PHP juga membutuhkan ekstensi umum seperti:
pdo_mysql
mbstring
xml
curl
gd atau imagick
Instalasi Lokal
Masuk ke directory project:
cd CMS-Blog-Starter-Laravel-Livewire-Starterkit
Install dependency PHP:
composer install
Buat file .env:
cp .env.example .env
php artisan key:generate
Buat database MySQL:
mysql -u root -p -e "CREATE DATABASE cms_blog CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
Kemudian sesuaikan konfigurasi database di .env:
DB_DATABASE=cms_blog
DB_USERNAME=root
DB_PASSWORD=...
Jalankan migration dan seeder:
php artisan migrate --seed
Buat symbolic link storage:
php artisan storage:link
Untuk Linux atau macOS:
chmod -R 775 storage bootstrap/cache
Install dependency frontend:
npm install
Build asset:
npm run build
Terakhir jalankan development server:
php artisan serve
Aplikasi dapat diakses melalui:
http://localhost:8000
Halaman login:
http://localhost:8000/login
Untuk development sehari-hari, gunakan:
npm run dev
agar perubahan asset frontend dapat dipantau menggunakan hot module reload.
Akun Demo
Setelah menjalankan seeder di environment lokal, tersedia akun demo berikut:
| Peran | Password | |
|---|---|---|
| Admin | admin@example.com | AdminPass123! |
| Editor | editor@example.com | EditorPass123! |
| Author | author@example.com | AuthorPass123! |
⚠️ Khusus development lokal. Password tersebut hanya digunakan ketika
APP_ENV=local. Pada environment lain, seeder akan membuat password acak 20 karakter dan menampilkannya satu kali di console, kecualiADMIN_SEED_PASSWORDdiatur sendiri di.env.
Selalu ganti password akun admin sebelum deployment ke environment selain komputer lokal.
Menjalankan dengan Docker
Project juga mendukung Docker sehingga PHP, Composer, Node.js, frontend dependency, dan MySQL dapat dijalankan di dalam container.
Yang dibutuhkan hanya:
Docker
Docker Compose v2
Jalankan:
cd laravel-cms-blog
docker compose up --build
Aplikasi kemudian dapat diakses melalui:
https://localhost
Karena development environment menggunakan sertifikat self-signed, browser akan menampilkan peringatan sertifikat pada saat pertama kali membuka aplikasi.
Proses yang Dilakukan Otomatis
Saat pertama kali dijalankan, Docker akan menangani beberapa proses secara otomatis:
Build frontend menggunakan Node 22.
Menjalankan
npm cidannpm run build.Membuat
.envdari.env.examplejika belum tersedia.Generate
APP_KEY.Membuat symbolic link storage.
Generate sertifikat TLS self-signed.
Menunggu MySQL benar-benar siap.
Menjalankan migration dan seeder pada boot pertama.
Data dibuat persisten menggunakan tiga volume:
dbdata
storage
certs
Dengan demikian database, file upload, log, dan sertifikat tetap tersedia meskipun container direstart.
Perintah Docker yang Sering Digunakan
Masuk ke Tinker:
docker compose exec app php artisan tinker
Jalankan migration:
docker compose exec app php artisan migrate --force
Jalankan seeder:
docker compose exec app php artisan db:seed --force
Lihat log aplikasi:
docker compose logs -f app
Hentikan container:
docker compose down
Hentikan container sekaligus hapus volume:
docker compose down -v
⚠️
docker compose down -vakan menghapus volume database sehingga data database ikut terhapus.
Konfigurasi Docker
Default port yang digunakan:
| Port | Fungsi |
|---|---|
80 | HTTP |
443 | HTTPS |
3306 | MySQL |
HTTP pada port 80 akan mengarahkan pengguna ke HTTPS pada port 443.
MySQL pada port 3306 tersedia agar dapat diakses menggunakan database client seperti TablePlus.
Contoh environment variable:
APP_ENV=local
APP_DEBUG=true
APP_URL=https://localhost
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=cms_blog
DB_USERNAME=cms_user
DB_PASSWORD=secret
DB_ROOT_PASSWORD=root
RUN_MIGRATIONS=true
RUN_SEEDERS=true
ADMIN_SEED_EMAIL=admin@example.com
ADMIN_SEED_PASSWORD=AdminPass123!
Untuk Docker, DB_HOST menggunakan nama service:
DB_HOST=mysql
bukan:
DB_HOST=127.0.0.1
Seeder juga dapat dinonaktifkan:
RUN_SEEDERS=false docker compose up -d
Docker Compose menyediakan healthcheck untuk MySQL dan service aplikasi sehingga aplikasi menunggu database siap sebelum melanjutkan proses boot.
⚠️ Kredensial default hanya untuk development lokal. Jangan gunakan
secret,root, atauAdminPass123!di production. Ganti seluruh credential melalui.envatau environment variable dan pastikanAPP_DEBUG=false.
Struktur Project
Struktur utama project:
app/
├── Enums/
│ └── PostStatus.php
├── Http/
│ ├── Controllers/
│ └── Middleware/
│ ├── SecurityHeaders.php
│ └── EnsureUserIsNotBlocked.php
├── Livewire/
│ ├── Auth/
│ ├── Profile/
│ ├── Blog/
│ └── Admin/
├── Models/
├── Policies/
├── Providers/
└── Services/
├── MarkdownRenderer.php
└── SecurityLog.php
database/
├── migrations/
├── seeders/
└── factories/
resources/
└── views/
├── components/
├── livewire/
├── home.blade.php
├── blog/
└── errors/
tests/
├── Feature/
└── Unit/
app/Policies menjadi lokasi utama untuk aturan authorization.
Sementara itu:
MarkdownRenderermenangani proses Markdown menjadi HTML.SecurityLogmenangani logging untuk event keamanan.Komponen Livewire dikelompokkan berdasarkan area aplikasi.
Test dipisahkan menjadi Feature Test dan Unit Test.
Keamanan
Starter kit ini dirancang dengan perhatian khusus terhadap beberapa kategori vulnerability seperti:
SQL injection
XSS
Malicious file upload
LFI dan path traversal
Authorization bypass
Request tampering
Brute-force authentication
SQL Injection
Query menggunakan Eloquent atau Query Builder dengan parameter binding.
Tidak ada DB::raw() atau whereRaw() yang menyisipkan input pengguna secara langsung.
Pencarian artikel juga menggunakan mekanisme binding dan diuji dengan payload seperti:
' OR '1'='1
'; DROP TABLE posts; --
XSS
Blade menggunakan escaping default:
{{ $value }}
Konten post yang dirender sebagai raw HTML selalu melewati:
App\Services\MarkdownRenderer
Service tersebut menangani sanitasi HTML dan memblokir skema link berbahaya seperti:
javascript:
data:
Test juga mencakup payload seperti:
<script>
<iframe>
<img onerror=...>
Upload File
Featured image divalidasi sebagai image sungguhan dan dibatasi ke:
jpg
jpeg
png
webp
SVG sengaja tidak diizinkan.
Ukuran file maksimum adalah:
2 MB
File disimpan menggunakan nama acak dan ditempatkan pada:
storage/app/public
File kemudian diakses melalui:
public/storage
File upload tidak diperlakukan sebagai executable PHP.
LFI dan Path Traversal
Aplikasi tidak menggunakan include() atau require() berdasarkan input pengguna.
Post dan kategori diambil melalui Eloquent berdasarkan ID atau slug yang tervalidasi.
Authorization dan Request Tampering
Pada aplikasi Livewire, public property dapat menerima nilai dari request client. Karena itu, pengecekan authorization tidak cukup dilakukan hanya ketika component pertama kali di-load.
Setiap action penting melakukan policy check kembali:
save
delete
publish
change role
Property sensitif menggunakan:
#[Locked]
Field status juga diverifikasi kembali pada saat save sehingga Author tidak dapat mem-publish artikel hanya dengan memanipulasi request.
user_id post tidak pernah diambil dari input form. Penulis selalu ditentukan berdasarkan:
Auth::user()
Admin juga tidak dapat menonaktifkan atau mengubah role dirinya sendiri, sementara admin aktif terakhir dilindungi agar CMS tidak kehilangan administrator.
Authentication Security
Password menggunakan bcrypt.
Aturan password menggunakan:
Password::defaults()
Login memiliki rate limiting untuk membatasi brute-force berdasarkan kombinasi email dan IP serta batas tambahan berdasarkan IP.
Akun yang dinonaktifkan akan otomatis logout pada request berikutnya.
Ketika password diganti, session pada perangkat lain juga dicabut melalui:
Auth::logoutOtherDevices()
HTTP Security Headers
Middleware SecurityHeaders menambahkan:
Content-Security-Policy
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy
Permissions-Policy
Strict-Transport-Security
HSTS diterapkan ketika aplikasi berjalan menggunakan HTTPS.
Ada satu trade-off yang disengaja pada konfigurasi CSP: aplikasi mengizinkan 'unsafe-eval' dan 'unsafe-inline' karena kebutuhan Alpine.js yang digunakan oleh Livewire.
CSRF
Proteksi CSRF menggunakan mekanisme bawaan Laravel dan berlaku untuk form serta request Livewire.
Mass Assignment
Semua model menggunakan $fillable secara eksplisit dan tidak menggunakan:
$guarded = [];
Kolom sensitif seperti:
is_active
email_verified_at
user_id
tidak dimasukkan ke $fillable.
Security Logging
Event keamanan penting dicatat pada channel security, termasuk:
Failed login
Lockout
Perubahan role
Aktivasi user
Nonaktifasi user
Penghapusan user
Perubahan settings
File log berada pada:
storage/logs/security-*.log
dengan rotasi harian dan retention 90 hari.
Sebelum Deploy ke Production
Sebelum aplikasi digunakan di production, lakukan beberapa konfigurasi penting.
Set:
APP_DEBUG=false
SESSION_SECURE_COOKIE=true
Gunakan user MySQL dengan hak akses terbatas dan jangan gunakan root.
Pastikan aplikasi berjalan di balik HTTPS, misalnya melalui reverse proxy atau load balancer.
Audit dependency secara berkala:
composer audit
dan:
npm audit
Tidak ada sistem yang dapat dijamin 100% bebas dari serangan. Fokus starter kit ini adalah menerapkan proteksi untuk kelas vulnerability yang ditargetkan dan memverifikasinya melalui automated testing.
Testing
Seluruh test dapat dijalankan menggunakan:
php artisan test
Test mencakup:
Login dan registrasi.
Rate limiting.
Access control berdasarkan role.
IDOR.
Tampering terhadap publish status.
Malicious file upload.
SVG dengan script.
Proteksi admin terakhir.
Stored XSS.
SQL injection pada pencarian.
Testing menggunakan SQLite in-memory sehingga dapat berjalan cepat tanpa menyentuh database MySQL utama.
Pengembangan Selanjutnya
Starter kit ini sengaja dibuat tetap sederhana agar mudah dikembangkan.
Beberapa fitur yang dapat ditambahkan:
Comment System
Menambahkan komentar pada post beserta moderation pada dashboard admin.
Media Library
Saat ini setiap post hanya memiliki satu featured image. Struktur dapat dikembangkan menjadi media library penuh.
Two-Factor Authentication
Two-factor authentication dapat ditambahkan menggunakan Laravel Fortify.
REST API
Project dapat diperluas dengan Laravel Sanctum apabila nantinya konten perlu dikonsumsi oleh aplikasi lain.
About dan Contact
Halaman seperti:
About
Contact
dapat ditambahkan sebagai halaman statis maupun dinamis.
Kesimpulan
CMS Blog Starter Laravel Livewire dibuat sebagai fondasi bagi developer yang ingin membangun blog atau CMS menggunakan Laravel tanpa harus memulai semuanya dari nol.
Stack yang digunakan:
Laravel 13
Livewire 4
Tailwind CSS 4
MySQL
Vite
Spatie Laravel Permission
Project sudah menyediakan kebutuhan fundamental seperti:
Content management
Authentication
Role-based access control
User management
Markdown editor
Image upload
SEO metadata
Docker support
Security hardening
Automated testing
Salah satu fokus utama project ini adalah menjaga source code tetap eksplisit, mudah dibaca, dan mudah dikembangkan, sehingga developer tidak hanya mendapatkan aplikasi yang siap digunakan, tetapi juga struktur yang nyaman untuk dipelajari dan dimodifikasi.
Source code:
https://github.com/gagaltotal/CMS-Blog-Starter-Laravel-Livewire-Starterkit
Lisensi: MIT [Gagaltotal666]

0 Comments