# Dokumentasi — Sistem Manajemen Lisensi jasaSEOterdekat.com

Backend PHP Native 8.4 + MySQL 8.0, full REST API, untuk mengelola lisensi
**VCI Magic Browser Free** (dan software lain di masa depan) berbasis hardware ID.

---

## 1. Arsitektur singkat

```
Aplikasi Electron (VCI Magic Browser)
   │  auto-detect Hardware ID
   │  POST /api/licenses/register   → daftar + auto-generate kode lisensi
   │  POST /api/licenses/activate   → verifikasi kode lisensi
   ▼
Server PHP (project ini) ── MySQL
   ▲
   │  Login Super Admin → Bearer token
   │  GET/POST/PUT/DELETE /api/licenses, /api/users, /api/auth/*
   │
Panel Admin (SPA di public/app.html + assets/js/app.js)
```

Tidak ada fitur "register" untuk publik di panel admin — hanya **Super Admin**
yang login (akun dibuat lewat `database/seed_admin.php` atau oleh Super Admin lain).

---

## 2. Instalasi

### 2.1 Requirement server
- PHP **8.4** dengan ekstensi: `pdo_mysql`, `mbstring`, `openssl` (biasanya sudah aktif default)
- MySQL **8.0**
- Apache (dengan `mod_rewrite`) atau Nginx

### 2.2 Langkah instalasi

```bash
# 1. Upload seluruh folder project ke server, mis. /var/www/lisensi-panel

# 2. Import skema database
mysql -u root -p < database/schema.sql

# 3. Atur koneksi database & base URL
#    Edit config/config.php langsung, ATAU pakai environment variable:
export DB_HOST=127.0.0.1
export DB_NAME=lisensi_jasaseoterdekat
export DB_USER=root
export DB_PASS=rahasia
export APP_BASE_URL=https://lisensi.jasaseoterdekat.com

# 4. Buat akun Super Admin pertama (WAJIB, hash password dibuat oleh PHP sendiri)
php database/seed_admin.php "Nama Anda" admin@jasaseoterdekat.com superadmin PasswordKuatAnda123

# 5. Arahkan document root web server ke folder public/
```

### 2.3 Konfigurasi Apache (contoh vhost)

```apache
<VirtualHost *:443>
    ServerName lisensi.jasaseoterdekat.com
    DocumentRoot /var/www/lisensi-panel/public

    <Directory /var/www/lisensi-panel/public>
        AllowOverride All
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateFile      /path/ke/fullchain.pem
    SSLCertificateKeyFile   /path/ke/privkey.pem
</VirtualHost>
```

### 2.4 Konfigurasi Nginx (contoh, kalau tidak pakai Apache)

```nginx
server {
    listen 443 ssl;
    server_name lisensi.jasaseoterdekat.com;
    root /var/www/lisensi-panel/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.4-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
```

---

## 3. Mengganti Base URL kapan saja

Base URL **tidak di-hardcode** di banyak tempat — cukup ubah satu variabel:

- **Di server (backend + panel admin)**: ubah environment variable `APP_BASE_URL`
  atau langsung edit `define('APP_BASE_URL', ...)` di `config/config.php`.
- **Di aplikasi Electron**: ubah field `"licenseApiBaseUrl"` pada file
  `vci-magic-browser-config.json` (ada di folder yang sama dengan file exe-nya).
  Default-nya sudah `https://lisensi.jasaseoterdekat.com`.
- **Di panel admin (kalau di-deploy terpisah dari API)**: buka console browser lalu
  jalankan `localStorage.setItem('api_base_url', 'https://domain-api-anda.com')`,
  lalu refresh halaman.

---

## 4. Referensi REST API

Semua response berbentuk JSON dengan pola:
```json
{ "success": true, "message": "...", ...data }
```
atau saat gagal:
```json
{ "success": false, "message": "Pesan error" }
```

### 4.1 Auth

| Method | Endpoint             | Body                          | Auth | Keterangan |
|--------|----------------------|--------------------------------|------|------------|
| POST   | `/api/auth/login`    | `{ username, password }`      | ❌   | Login Super Admin, return `token` |
| POST   | `/api/auth/logout`   | —                              | ✅   | Cabut token yang sedang dipakai |
| GET    | `/api/auth/me`       | —                              | ✅   | Data user yang sedang login |
| PUT    | `/api/auth/profile`  | `{ name?, email?, username?, password? }` | ✅ | Update profil sendiri |

Header untuk endpoint ber-auth: `Authorization: Bearer <token>`

**Contoh login:**
```bash
curl -X POST https://lisensi.jasaseoterdekat.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"superadmin","password":"PasswordKuatAnda123"}'
```

### 4.2 Lisensi — endpoint publik (dipanggil dari aplikasi Electron)

| Method | Endpoint                  | Body                                | Keterangan |
|--------|---------------------------|--------------------------------------|------------|
| POST   | `/api/licenses/register`  | `{ hardware_id, wa_number }`         | Daftarkan hardware baru, auto-generate `license_code`, status awal `pending` |
| POST   | `/api/licenses/activate`  | `{ hardware_id, license_code }`      | Verifikasi kode lisensi untuk hardware tsb |

**Contoh register:**
```json
POST /api/licenses/register
{ "hardware_id": "4C4C4544-...", "wa_number": "081234567890" }

Response:
{ "success": true, "message": "Kode lisensi berhasil didaftarkan. Menunggu aktivasi dari Admin.",
  "license_code": "VCI-A1B2-C3D4-E5F6", "status": "pending" }
```

**Contoh activate (belum diaktivasi admin):**
```json
{ "success": false, "message": "Lisensi belum diaktivasi oleh Admin. Silakan tunggu atau hubungi Admin." }
```

### 4.3 Lisensi — endpoint admin (butuh Bearer token)

| Method | Endpoint                                   | Keterangan |
|--------|---------------------------------------------|------------|
| GET    | `/api/licenses?page=1&per_page=10&search=&status=` | List lisensi, paginasi + pencarian + filter status |
| GET    | `/api/licenses/{id}`                        | Detail satu lisensi |
| PUT    | `/api/licenses/{id}`                        | Update `wa_number`, `note`, `expires_at` |
| POST   | `/api/licenses/{id}/activate-by-admin`      | Aktivasi lisensi (status → `active`), return juga `wa_link` siap-kirim |
| POST   | `/api/licenses/{id}/revoke`                 | Cabut lisensi (status → `revoked`) |
| DELETE | `/api/licenses/{id}`                        | Hapus data lisensi permanen |

### 4.4 Users (manajemen akun Super Admin, butuh Bearer token)

| Method | Endpoint                              | Keterangan |
|--------|-----------------------------------------|------------|
| GET    | `/api/users?page=1&per_page=10&search=` | List admin, paginasi + pencarian |
| POST   | `/api/users`                            | `{ name, email, username, password }` — buat admin baru |
| GET    | `/api/users/{id}`                       | Detail satu admin |
| PUT    | `/api/users/{id}`                       | Update data / password admin |
| DELETE | `/api/users/{id}`                       | Hapus admin (tidak bisa hapus diri sendiri) |

---

## 5. Alur bisnis lisensi (ringkasan)

1. User buka **VCI Magic Browser Free** → app auto-deteksi Hardware ID.
2. User isi Nomor WA → klik **"Dapatkan Kode Lisensi"** → app memanggil
   `POST /api/licenses/register` → server generate `license_code` unik,
   status `pending`.
3. Admin login ke panel (`https://lisensi.jasaseoterdekat.com`) → tab **Lisensi**
   → cari hardware ID / nomor WA yang baru masuk → klik **"Aktivasi"**.
4. Setelah aktivasi, panel menawarkan untuk langsung **buka WhatsApp** ke nomor
   user tsb, dengan pesan otomatis berisi Hardware ID + Kode Lisensi.
5. User memasukkan kode lisensi tersebut di app → klik **"Aktifkan Lisensi"** →
   app memanggil `POST /api/licenses/activate` → sukses → app tersimpan
   lisensinya secara lokal (`vci-license.json` di sebelah exe) sehingga
   **tidak perlu input ulang** di pembukaan berikutnya (selama hardware sama).
6. Jika suatu saat Admin **mencabut (revoke)** lisensi, app akan mendeteksinya
   secara diam-diam saat startup berikutnya (validasi ulang online) dan meminta
   aktivasi ulang.

---

## 6. Keamanan

- Password di-hash dengan `password_hash()` (bcrypt) — tidak pernah disimpan plain text.
- Autentikasi API pakai Bearer token acak 64-karakter (`random_bytes(32)`), disimpan
  di tabel `auth_tokens` dengan masa berlaku (`TOKEN_TTL_HOURS`, default 7 hari).
  Token dicabut otomatis saat expired, atau manual lewat logout.
- Semua query pakai **prepared statement PDO** (aman dari SQL Injection).
- Tidak ada endpoint registrasi publik untuk akun admin — hanya Super Admin yang
  sudah login yang bisa membuat Super Admin lain.
- `hardware_id` bersifat **unique** di database — satu hardware = satu lisensi.

## 7. Struktur folder

```
lisensi-panel/
├─ config/config.php          # DB, base URL, WA admin, dsb — semua bisa diganti
├─ database/
│  ├─ schema.sql               # struktur tabel
│  └─ seed_admin.php           # buat akun Super Admin pertama
├─ src/
│  ├─ Core/                    # Database, Router, Request, Response, Auth
│  ├─ Controllers/             # AuthController, LicenseController, UserController
│  └─ Models/                  # User, License
├─ routes/api.php              # daftar semua endpoint
├─ public/
│  ├─ index.php                # front controller (routing + CORS)
│  ├─ app.html                 # shell SPA panel admin
│  ├─ .htaccess                # rewrite rule Apache
│  └─ assets/{css,js}/         # tema iOS-like + logic SPA
└─ docs/DOCUMENTATION.md        # dokumen ini
```

## 8. Login pertama kali

1. Jalankan `php database/seed_admin.php` (lihat §2.2).
2. Buka `https://lisensi.jasaseoterdekat.com` di browser.
3. Login dengan username/password dari hasil seeder.
4. **Segera ganti password** lewat menu **Profil** di panel.
