# Explore Lumajang Admin Panel

## Struktur Utama

- `app/Models/Kategori.php` dan `app/Models/Wisata.php`: model relasi kategori dan destinasi.
- `app/Http/Controllers/Admin`: controller dashboard, login, CRUD wisata, CRUD kategori, dan user aplikasi.
- `app/Http/Controllers/API`: API auth, destinations, dan kategori untuk Flutter.
- `app/Http/Resources`: format JSON `success`, `message`, dan `data`.
- `resources/views/admin`: Blade admin panel Bootstrap 5.
- `storage/app/public/images`: penyimpanan gambar wisata.
- `storage/app/public/videos`: penyimpanan video wisata.
- `storage/app/public/models`: penyimpanan model GLB/GLTF wisata AR.
- `routes/web.php`: route admin berbasis session dan middleware `auth` + `admin`.
- `routes/api.php`: endpoint JSON untuk aplikasi Flutter.

## Instalasi

```bash
cd website/wisata_web
composer install
cp .env.example .env
php artisan key:generate
```

Atur database MySQL di `.env`:

```env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=explore_lumajang_ar
DB_USERNAME=root
DB_PASSWORD=
```

Jalankan migrasi, seeder admin awal, dan storage link:

```bash
php artisan migrate --seed
php artisan storage:link
php artisan serve
```

Admin panel tersedia di:

```text
http://127.0.0.1:8000/admin/login
```

Akun admin awal:

```text
Email: admin@explorelumajang.test
Password: password
```

Ganti password ini sebelum digunakan untuk produksi.

Seeder juga membuat contoh data demo:

- `Ranu Pani`: wisata normal.
- `Puncak B29`: wisata AR, tombol AR aktif jika `model_path` tersedia.
- `Air Terjun Tumpak Sewu`: wisata video, video player aktif jika `is_video = true`.

## Endpoint API Flutter

Base URL lokal Android emulator:

```text
http://10.0.2.2:8000/api
```

Base URL perangkat fisik:

```text
http://IP_LAPTOP_KAMU:8000/api
```

Endpoint publik:

```text
GET  /health
POST /register
POST /login
POST /forgot-password
GET  /kategori
GET  /destinations
GET  /destinations/{id}
```

Endpoint dengan token Bearer:

```text
GET  /profile
POST /logout
POST /wisata/{id}/gambar
```

Contoh response login:

```json
{
  "success": true,
  "message": "Success",
  "data": {
    "token_type": "Bearer",
    "token": "plain-token",
    "user": {
      "id": 1,
      "name": "User",
      "email": "user@example.com",
      "role": "user",
      "created_at": "2026-05-20T10:00:00.000000Z"
    }
  }
}
```

Contoh response wisata:

```json
{
  "success": true,
  "message": "Success",
  "data": {
    "id": 1,
    "title": "Ranu Pani",
    "category": {
      "id": 1,
      "name": "Wisata Alam",
      "slug": "wisata-alam"
    },
    "location": "Senduro, Lumajang",
    "image": "http://IP_LAPTOP:8000/storage/images/file.jpg",
    "rating": 4.8,
    "distance": "48 km dari pusat kota",
    "elevation": "2.100 mdpl",
    "model_path": "http://IP_LAPTOP:8000/storage/models/file.glb",
    "video_path": "http://IP_LAPTOP:8000/storage/videos/file.mp4",
    "is_video": false,
    "type": "normal",
    "show_ar_button": false,
    "show_video_player": false,
    "latitude": -8.0092,
    "longitude": 112.9446,
    "google_maps_url": "https://www.google.com/maps?q=-8.0092000,112.9446000"
  }
}
```

## Integrasi Flutter

Simpan base URL di `auth_service.dart` atau konfigurasi environment Flutter. Untuk perangkat fisik gunakan IP laptop, bukan localhost:

```dart
const String baseUrl = 'http://IP_LAPTOP:8000/api';
```

Untuk Android emulator boleh memakai:

```dart
const String baseUrl = 'http://10.0.2.2:8000/api';
```

Untuk request login/register gunakan `POST`. Setelah login, simpan token dari `data.token`, lalu kirim pada endpoint protected:

```dart
headers: {
  'Accept': 'application/json',
  'Authorization': 'Bearer $token',
}
```

Untuk memuat destinasi:

```text
GET $baseUrl/wisata
GET $baseUrl/destinations
GET $baseUrl/destinations/{id}
GET $baseUrl/kategori
```

Field URL `image`, `model_path`, dan `video_path` sudah dikirim sebagai URL publik dari Laravel storage sehingga bisa langsung digunakan di Flutter.

Logic Flutter:

```dart
if (destination['show_ar_button'] == true) {
  // tampilkan tombol AR dan buka model_path
}

if (destination['show_video_player'] == true) {
  // tampilkan video player dari video_path
}
```
