Tutorial Portal Berita - Level 1: Persiapan Proyek

Selamat datang di tutorial membangun portal berita lengkap menggunakan Laravel 12 dan Laravolt! Di level pertama ini, kita akan fokus pada persiapan dasar proyek kita. Ini adalah langkah fundamental yang akan memastikan kelancaran pengembangan fitur-fitur berikutnya.

Tujuan Level 1:

  1. Membuat proyek Laravel baru.
  2. Menginstal dan mengkonfigurasi Laravolt secara "plug and play".
  3. Menyiapkan lingkungan pengembangan dengan database SQLite.
  4. Memahami struktur proyek yang akan kita bangun.
  5. Menerapkan praktik kualitas kode sejak awal menggunakan Laravel Pint dan PHPStan.

Mari kita mulai!


1. Membuat Proyek Laravel Baru

Langkah pertama adalah membuat instalasi Laravel yang baru. Pastikan Anda sudah memiliki Composer terinstal di sistem Anda. Buka terminal atau command prompt, lalu jalankan perintah berikut:

composer create-project --prefer-dist laravel/laravel news-portal "12.*"

Perintah di atas akan membuat direktori baru bernama news-portal yang berisi instalasi Laravel 12. Setelah proses instalasi selesai, masuk ke direktori proyek:

cd news-portal

2. Menginstal dan Mengkonfigurasi Laravolt

Laravolt adalah kumpulan paket yang akan sangat membantu kita dalam membangun panel admin dengan cepat.

a. Instalasi Paket Laravolt:

Jalankan perintah berikut di terminal untuk menambahkan Laravolt ke proyek kita:

composer require laravolt/laravolt

Perintah ini akan mengunduh paket inti Laravolt beserta dependensinya.

b. Instalasi Laravolt (Plug and Play):

Setelah paket Composer terinstal, jalankan perintah laravolt:install. Perintah ini akan menangani sebagian besar konfigurasi awal yang dibutuhkan secara otomatis.

php artisan laravolt:install

Perintah ini akan melakukan beberapa hal penting:

  • Mempublikasikan file konfigurasi Laravolt ke direktori config/laravolt.
  • Mempublikasikan aset Laravolt (seperti CSS, JS) ke direktori public/laravolt.
  • Mempublikasikan file migrasi database yang dibutuhkan oleh Laravolt.
  • Menambahkan rute Laravolt ke file routes/web.php.

(Kita akan menjalankan php artisan migrate setelah kita selesai mengatur file .env dan database SQLite kita di langkah berikutnya.)


3. Menyiapkan Lingkungan Pengembangan

a. Konfigurasi Database (Menggunakan SQLite):

Untuk kemudahan dan kesederhanaan, kita akan menggunakan SQLite sebagai database kita. SQLite menyimpan seluruh database dalam satu file di dalam direktori proyek kita, sehingga tidak memerlukan instalasi server database terpisah.

  1. Buat File Database SQLite:

    Buat sebuah file kosong bernama database.sqlite di dalam direktori database/ proyek Anda. Anda bisa melakukannya melalui file explorer atau menggunakan terminal:

    touch database/database.sqlite
    
  2. Perbarui File .env:

    Buka file .env di root proyek Laravel Anda. Hapus atau komentari (dengan menambahkan # di awal baris) variabel koneksi database yang ada (seperti DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD), dan pastikan DB_CONNECTION diatur ke sqlite.

    File .env Anda seharusnya terlihat seperti ini untuk bagian database:

    DB_CONNECTION=sqlite
    # DB_HOST=127.0.0.1
    # DB_PORT=3306
    # DB_DATABASE=laravel # Bisa nama apa saja jika tidak SQLite
    # DB_USERNAME=root
    # DB_PASSWORD=
    
    # Laravel akan otomatis menggunakan database/database.sqlite saat DB_CONNECTION=sqlite.
    # Jika Anda ingin menempatkan file SQLite di lokasi lain, Anda bisa mengatur
    # variabel DB_DATABASE dengan path absolut ke file tersebut.
    # Contoh: DB_DATABASE=/absolute/path/to/your/other_database.sqlite
    

    Untuk tutorial ini, kita akan menggunakan lokasi default database/database.sqlite.

b. Konfigurasi Aplikasi Lainnya:

Masih di file .env, pastikan beberapa konfigurasi dasar sudah sesuai:

Cuplikan kode

APP_NAME="News Portal"
APP_ENV=local
APP_KEY= # Seharusnya sudah terisi otomatis saat instalasi Laravel
APP_DEBUG=true
APP_URL=http://localhost:8000 # Sesuaikan jika menggunakan port berbeda

Jika APP_KEY kosong (biasanya tidak terjadi pada instalasi baru), jalankan perintah berikut untuk membuatnya:

php artisan key:generate

c. Menjalankan Migrasi Database:

Sekarang setelah file .env dikonfigurasi untuk menggunakan SQLite dan file database.sqlite sudah ada, kita bisa menjalankan migrasi database. Perintah ini akan membuat semua tabel yang dibutuhkan oleh Laravel dan Laravolt di dalam file database.sqlite kita.

php artisan migrate

Jika berhasil, Anda akan melihat output di terminal yang menandakan tabel-tabel telah dibuat.

d. Menjalankan Development Server:

Untuk melihat apakah instalasi berjalan lancar, jalankan development server Laravel:

composer dev

Buka browser dan akses http://localhost:8000 (atau URL yang tampil di terminal). Anda seharusnya melihat halaman selamat datang Laravel.

Untuk mengakses panel admin Laravolt, buka http://localhost:8000/admin. Anda akan melihat halaman login Laravolt. Karena kita baru saja melakukan migrasi, belum ada user yang terdaftar. Kita akan menangani pembuatan user dan peran di level berikutnya. Untuk saat ini, cukup pastikan halaman login Laravolt tampil tanpa error database.


4. Gambaran Struktur Proyek

Setelah instalasi Laravel dan Laravolt, struktur direktori utama proyek kita akan terlihat seperti ini (beberapa direktori umum Laravel disertakan untuk konteks):

news-portal/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ Http/
β”‚   β”‚   └── Controllers/ # Controller aplikasi akan ada di sini (jika diperlukan kustomisasi)
β”‚   β”œβ”€β”€ Models/
β”‚   β”‚   └── User.php     # Model User kita
β”‚   └── Providers/
β”œβ”€β”€ bootstrap/
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ laravolt/        # Direktori konfigurasi Laravolt
β”‚   └── ...              # File konfigurasi Laravel lainnya
β”œβ”€β”€ database/
β”‚   β”œβ”€β”€ factories/
β”‚   β”œβ”€β”€ migrations/      # File migrasi, termasuk dari Laravolt
β”‚   β”œβ”€β”€ seeders/
β”‚   └── database.sqlite  # File database SQLite kita
β”œβ”€β”€ public/
β”‚   β”œβ”€β”€ laravolt/        # Aset publik Laravolt (CSS, JS), bukan folder sebenarnya (symlink dari folder vendor)
β”‚   └── index.php
β”œβ”€β”€ resources/
β”‚   β”œβ”€β”€ js/
β”‚   β”œβ”€β”€ lang/
β”‚   └── views/           # View default aplikasi (bisa di-override)
β”‚       └── welcome.blade.php
β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ web.php          # Rute aplikasi akan ditambahkan di sini
β”‚   └── ...
β”œβ”€β”€ storage/
β”œβ”€β”€ tests/
β”œβ”€β”€ vendor/              # Dependensi Composer, termasuk Laravolt
β”œβ”€β”€ .env                 # File konfigurasi lingkungan
└── composer.json        # Definisi proyek dan dependensi

Poin Penting:

  • config/laravolt: Di sini Anda bisa menyesuaikan berbagai aspek Laravolt.
  • database/database.sqlite: Ini adalah file database kita yang ringan dan portabel.
  • Dengan laravolt:install, banyak konfigurasi dasar sudah ditangani, memungkinkan kita untuk lebih cepat masuk ke pengembangan fitur.

5. Tips Kualitas Kode: Membangun untuk Kemudahan Perawatan Sejak Awal πŸ› οΈ

Sebelum kita mulai menambahkan banyak fitur, sangat penting untuk menyiapkan alat bantu kualitas kode otomatis. Ini akan memastikan kode kita tetap bersih, konsisten, dan andal seiring berkembangnya proyek.

a. Laravel Pint (untuk Standar Coding):

Laravel Pint adalah zero-dependency PHP code style fixer yang sudah termasuk dalam instalasi Laravel 12. Pint secara otomatis memastikan kode Anda mengikuti standar coding Laravel (PSR-12 secara default).

  • Untuk memperbaiki style kode secara otomatis:
    ./vendor/bin/pint
    
  • Untuk mengecek style kode tanpa melakukan perubahan (mode --test):
    ./vendor/bin/pint --test
    
    Anda dapat menyesuaikan konfigurasi Pint dengan membuat file pint.json di root proyek jika diperlukan.

b. PHPStan (untuk Analisis Statis):

PHPStan membantu menemukan bug dalam kode tanpa menjalankannya.

  1. Instalasi:

    composer require --dev phpstan/phpstan larastan/larastan --with-all-dependencies
    
  2. Buat file konfigurasi phpstan.neon di root proyek:

    Cuplikan kode

    includes:
        - vendor/larastan/larastan/extension.neon
        - vendor/nesbot/carbon/extension.neon
    
    parameters:
        paths:
            - app/
    
        # Level 10 is the highest level
        level: 10
    
    #    ignoreErrors:
    #        - '#PHPDoc tag @var#'
    #
    #    excludePaths:
    #        - ./*/*/FileToBeExcluded.php
    
  3. Jalankan analisis:

    ./vendor/bin/phpstan analyse
    

Menggunakan Baseline untuk Proyek Lama:

Jika Anda bekerja dengan codebase lama yang memiliki banyak error PHPStan, sangat sulit untuk memperbaiki semua kode sekaligus agar memenuhi level PHPStan yang tinggi. Untuk mengatasi hal ini, Anda dapat menggunakan baseline file.

Baseline file akan membuat file konfigurasi dengan semua error yang ada saat ini, sehingga kode baru dapat ditulis dengan standar yang lebih tinggi dibandingkan kode lama (berdasarkan dokumentasi resmi PHPStan).

  1. Generate Baseline:

    Jalankan perintah berikut untuk membuat file baseline:

    ./vendor/bin/phpstan analyse --generate-baseline
    

    Perintah ini akan:

    • Menjalankan analisis PHPStan pada kode yang ada
    • Membuat file phpstan-baseline.neon yang berisi semua error yang ditemukan
    • Error-error yang tercatat dalam baseline tidak akan ditampilkan lagi pada analisis berikutnya
  2. Update Konfigurasi PHPStan:

    Setelah baseline dibuat, perbarui file phpstan.neon Anda untuk menyertakan baseline:

    includes:
        - vendor/larastan/larastan/extension.neon
        - vendor/nesbot/carbon/extension.neon
        - phpstan-baseline.neon
    
    parameters:
        paths:
            - app/
    
        # Level 10 is the highest level
        level: 10
    
        ignoreErrors:
            # - '#PHPDoc tag @var for variable \$user is missing type#'
        checkMissingIterableValueType: false
        checkGenericClassInNonGenericObjectType: false
    
  3. Cara Kerja Baseline:

    • Error lama: Error yang sudah ada dalam baseline akan diabaikan
    • Error baru: Error baru yang muncul setelah baseline dibuat akan tetap ditampilkan
    • Kode baru: Kode baru harus memenuhi level PHPStan yang ditetapkan
  4. Regenerate Baseline (Opsional):

    Jika Anda telah memperbaiki beberapa error lama dan ingin memperbarui baseline:

    ./vendor/bin/phpstan analyse --generate-baseline
    

    Catatan: Regenerasi baseline akan menggantikan file baseline yang lama dengan yang baru.

  5. Best Practices:

    • Gunakan baseline hanya sebagai langkah transisi, bukan solusi permanen
    • Tetapkan target untuk secara bertahap memperbaiki error dalam baseline
    • Pantau progres dengan menjalankan analisis tanpa baseline sesekali:
      ./vendor/bin/phpstan analyse --no-baseline
      
    • Tingkatkan level PHPStan secara bertahap seiring perbaikan kode

c. Skrip composer.json (Rekomendasi):

Untuk mempermudah penggunaan alat-alat ini, tambahkan skrip ke file composer.json:

"scripts": {
    // ... skrip lain
    "format": [
        "./vendor/bin/pint"
    ],
    "lint": [
        "./vendor/bin/pint --test"
    ],
    "analyse": [
        "./vendor/bin/phpstan analyse"
    ]
}

Sekarang Anda bisa menjalankan composer format, composer lint, dan composer analyse.

d. Menyiapkan Test Coverage dengan PCOV atau Xdebug:

Laravel sudah terintegrasi dengan PHPUnit untuk testing. Untuk melihat test coverage:

  1. Pastikan PCOV atau Xdebug terinstal dan aktif di lingkungan PHP Anda. PCOV lebih ringan untuk coverage.

    • Jika menggunakan PCOV: pecl install pcov dan tambahkan extension=pcov.so ke php.ini.
  2. Edit file phpunit.xml di root proyek.

    • Pastikan di dalam tag <source> (atau <coverage> di versi lama phpunit.xml), direktori app sudah di-include:
      <source>
          <include>
              <directory>app</directory>
          </include>
      </source>
      
    • Atur driver coverage di tag <php>:
      <coverage>
          <report>
              <html outputDirectory="build/coverage"/>
              <text outputFile="build/coverage.txt"/>
              <clover outputFile="build/logs/clover.xml"/>
          </report>
      </coverage>
      <php>
          <!-- ... -->
          <env name="PCOV_ENABLED" value="1"/>
          <env name="XDEBUG_MODE" value="coverage" force="true"/>
      </php>
      
      Untuk Laravel 11+, phpunit.xml mungkin sudah menyertakan <env name=" standaard. PastikanXDEBUG_MODEdiset kecoverage`.
  3. Jalankan tes dengan coverage:

    php artisan test --coverage
    

    Laporan coverage HTML akan ada di direktori build/coverage (atau sesuai konfigurasi di phpunit.xml).

    Catatan: Jika Anda menggunakan Xdebug, pastikan XDEBUG_MODE diatur ke coverage sebelum menjalankan tes. Atau bisa dengan set XDEBUG_MODE=coverage di terminal sebelum menjalankan tes, jadi:

    XDEBUG_MODE=coverage php artisan test --coverage
    

e. Menjalankan Tes Awal dan Praktik Baik:

  • Jalankan tes bawaan Laravel: php artisan test.
  • Dengan konfigurasi coverage di atas, Anda sudah bisa melihat coverage awal. Target kita adalah menjaga coverage tetap tinggi untuk kode bisnis yang kita tulis.
  • Praktik Baik: Jalankan composer format, composer lint, dan composer analyse secara berkala, idealnya sebelum setiap commit. Integrasikan alat ini dengan CI/CD pipeline (seperti GitHub Actions) untuk otomatisasi. Tentu, mengintegrasikan GitHub Actions untuk Continuous Integration/Continuous Delivery (CI/CD) adalah praktik yang sangat baik. Ini akan membantu mengotomatiskan pengecekan kualitas kode dan menjalankan tes setiap kali ada perubahan.

f. Integrasi dengan GitHub Actions (CI/CD Otomatis):

Untuk lebih meningkatkan kualitas dan konsistensi kode, kita dapat mengotomatiskan proses linting dan testing menggunakan GitHub Actions. Ini memastikan bahwa setiap push atau pull request ke branch utama akan diperiksa secara otomatis.

Buat direktori .github/workflows/ di root proyek Anda. Kemudian, tambahkan dua file workflow berikut:

1. Workflow untuk Linting Otomatis (.github/workflows/lint.yml):

Workflow ini akan menjalankan Laravel Pint secara otomatis pada setiap pull request ke branch develop atau main. Jika ada perubahan code style yang dilakukan oleh Pint, workflow ini juga akan otomatis meng-commit perubahan tersebut kembali ke branch pull request.

# .github/workflows/lint.yml
name: Linting

on:
  pull_request:
    branches:
      - develop
      - main

permissions:
  contents: write # Diperlukan agar action bisa melakukan commit

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Kode dari Pull Request
        uses: actions/checkout@v4
        with:
          ref: ${{ github.head_ref }} # Mengambil referensi head dari PR

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.4" # Sesuaikan dengan versi PHP proyek Anda
          extensions: mbstring, xml, bcmath, intl, gd, zip, pdo_sqlite # Ekstensi dasar yang mungkin dibutuhkan composer
          coverage: none # Tidak perlu coverage di workflow linting

      - name: Install Dependencies
        run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

      - name: Jalankan Laravel Pint
        run: ./vendor/bin/pint # Atau ./vendor/bin/pint

      - name: Commit Perubahan Code Style (jika ada)
        uses: stefanzweifel/git-auto-commit-action@v5
        with:
          commit_message: "fix: code style (otomatis oleh CI)"
          commit_options: "--no-verify" # Lewati git hooks jika ada
          branch: ${{ github.head_ref }} # Commit ke branch asal pull request

Penjelasan lint.yml:

  • name: Linting: Nama workflow yang akan tampil di tab Actions GitHub.
  • on: pull_request: ...: Memicu workflow ini setiap kali ada pull request yang ditujukan ke branch develop atau main.
  • permissions: contents: write: Memberikan izin kepada workflow untuk menulis ke repositori (diperlukan oleh git-auto-commit-action).
  • jobs: quality: ...: Mendefinisikan sebuah job bernama quality yang berjalan di lingkungan ubuntu-latest.
  • steps::
    • actions/checkout@v4: Mengunduh salinan kode dari branch pull request.
    • shivammathur/setup-php@v2: Menyiapkan lingkungan PHP versi 8.4 (sesuaikan jika Anda menggunakan versi lain).
    • Install Dependencies: Menginstal dependensi proyek menggunakan Composer. Opsi -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist digunakan untuk instalasi yang cepat dan non-interaktif, cocok untuk CI.
    • Jalankan Laravel Pint: Menjalankan Pint untuk memformat kode.
    • stefanzweifel/git-auto-commit-action@v5: Jika Pint membuat perubahan pada file, action ini akan secara otomatis membuat commit baru dengan pesan "fix: code style (otomatis oleh CI)" ke branch pull request.

2. Workflow untuk Pengujian dan Analisis Kualitas Kode (.github/workflows/tests.yml):

Workflow ini akan menjalankan tes otomatis (PHPUnit) dan analisis kode dengan SonarQube setiap kali ada push atau pull request ke branch develop atau main.

# .github/workflows/tests.yml
name: Code Quality

on:
  push:
    branches:
      - develop
      - main
  pull_request:
    branches:
      - develop
      - main

jobs:
  ci:
    runs-on: ubuntu-latest
    container:
      image: ramaid/image:php8.4-fullstack-cli-v2.5.0 # Image Docker kustom
      options: --user root # Menjalankan sebagai root di dalam container
      volumes: # Volume mapping jika diperlukan oleh image/proses
        - /run/docker:/run/docker

    steps:
      - name: Checkout Kode
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Mengambil semua history, penting untuk SonarQube

      - name: Install Dependencies
        run: composer install --no-interaction --prefer-dist --optimize-autoloader

      - name: Setup Environment Laravolt
        run: |
          cp .env.example .env
          php artisan key:generate
          php artisan migrate --force # Menjalankan migrasi untuk tes (biasanya dengan DB in-memory atau tes)
          php artisan laravolt:link # Contoh, verifikasi perintah ini

      - name: Jalankan Tes dengan Coverage
        run: |
          # Pastikan Xdebug atau PCOV sudah aktif di container untuk coverage
          XDEBUG_MODE=coverage php artisan test --coverage --coverage-clover=test-coverage.xml --log-junit=test-results.xml

      - name: Analisis SonarQube (Self Hosted)
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_MC_TOKEN }} # Ambil token dari GitHub Secrets
        run: |
          # Pastikan sonar-scanner terinstal di container atau instal manual
          # Contoh instalasi jika belum ada:
          # apt-get update && apt-get install -y openjdk-17-jre wget unzip
          # wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip
          # unzip sonar-scanner-cli-5.0.1.3006-linux.zip
          # export PATH=$PATH:./sonar-scanner-5.0.1.3006-linux/bin
          sonar-scanner \
            -Dsonar.projectKey=nama_proyek_anda_di_sonarqube \
            -Dsonar.sources=. \
            -Dsonar.host.url=https://sonar.malescast.tech/ \
            -Dsonar.token=$SONAR_TOKEN \
            -Dsonar.php.coverage.reportPaths=coverage.xml \
            -Dsonar.php.tests.reportPath=results.xml \
            -Dsonar.scm.provider=git

Penjelasan tests.yml:

  • name: Code Quality: Nama workflow.
  • on: push: ..., pull_request: ...: Memicu workflow ini setiap kali ada push atau pull request yang ditujukan ke branch develop atau main.
  • jobs: ci: ...: Mendefinisikan job bernama ci.
  • container: image: ramaid/image:php8.4-fullstack-cli-v2.5.0 ...: Job ini berjalan di dalam sebuah Docker container kustom (ramaid/image:php8.4-fullstack-cli-v2.5.0). Container ini diasumsikan sudah memiliki PHP 8.4, Composer, ekstensi PHP yang dibutuhkan, Xdebug/PCOV untuk coverage, dan sonar-scanner. Jika sonar-scanner belum ada, Anda perlu menambah langkah instalasi.
  • steps::
    • actions/checkout@v4: Mengunduh kode. fetch-depth: 0 mengambil seluruh history Git, yang berguna untuk analisis SonarQube.
    • Install Dependencies: Menginstal dependensi proyek.
    • Setup Environment Laravolt:
      • Menyalin .env.example ke .env.
      • Menghasilkan APP_KEY.
      • Menjalankan php artisan migrate --force (penting jika tes Anda memerlukan interaksi database).
      • php artisan laravolt:link: Perintah ini spesifik. Jika ini adalah perintah php artisan storage:link yang diganti nama atau perintah kustom Laravolt untuk setup di CI, pastikan itu valid. Jika tidak, sesuaikan atau hapus.
    • Jalankan Tes dengan Coverage: Menjalankan php artisan test dengan mode coverage diaktifkan (melalui XDEBUG_MODE=coverage). Menghasilkan coverage.xml untuk laporan coverage (digunakan SonarQube) dan results.xml untuk laporan hasil tes format JUnit.
    • Analisis SonarQube (Self Hosted):
      • env: SONAR_TOKEN: ${{ secrets.SONAR_MC_TOKEN }}: Menggunakan secret bernama SONAR_MC_TOKEN yang harus Anda konfigurasikan di Pengaturan Repositori GitHub Anda (Settings > Secrets and variables > Actions).
      • sonar-scanner ...: Menjalankan sonar-scanner untuk mengirimkan hasil analisis kode dan coverage ke server SonarQube Anda (https://sonar.malescast.tech/). Pastikan untuk mengganti nama_proyek_anda_di_sonarqube dengan project key yang sesuai di SonarQube.

Penting:

  • Pastikan image Docker (ramaid/image:php8.4-fullstack-cli-v2.5.0) sudah memiliki semua dependensi yang diperlukan (PHP, ekstensi, Composer, Xdebug/PCOV, Java untuk SonarScanner, dan SonarScanner itu sendiri). Jika tidak, Anda perlu menambahkan langkah instalasi manual di dalam workflow.
  • Simpan SONAR_MC_TOKEN Anda sebagai secret di repositori GitHub Anda. Jangan pernah menaruh token atau kredensial sensitif langsung di dalam file workflow.
  • Sesuaikan php-version dan project key SonarQube sesuai dengan proyek Anda.

Dengan mengimplementasikan kedua workflow ini, Anda telah membuat langkah besar dalam mengotomatisasi jaminan kualitas kode proyek Anda!


Selamat! πŸŽ‰ Anda telah berhasil menyelesaikan Level 1. Proyek Laravel kita sudah berdiri, Laravolt sudah terpasang dan siap digunakan dengan database SQLite secara "plug and play", dan kita juga sudah menyiapkan fondasi untuk kualitas kode yang baik.

Di Level 2, kita akan fokus pada membangun struktur data aplikasi kita, yaitu membuat migrasi database (selain yang sudah dibuat oleh Laravolt) dan model untuk Post, Topic, dan Comment, serta mendefinisikan relasi antar model tersebut. Sampai jumpa di level berikutnya!