# Deployment Guide

Panduan instalasi aplikasi di server produksi **Ubuntu 22.04+**.

---

## Spesifikasi Server

| Komponen | Minimum | Rekomendasi |
|----------|---------|-------------|
| CPU | 2 core | 4 core |
| RAM | 4 GB | 8 GB |
| Storage | 40 GB SSD | 100 GB SSD |
| OS | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |

---

## Langkah 1 — Install Dependensi

```bash
sudo apt update && sudo apt upgrade -y

# PHP 8.3 + ekstensi
sudo add-apt-repository ppa:ondrej/php -y
sudo apt install -y php8.3 php8.3-fpm php8.3-pgsql php8.3-redis \
    php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip php8.3-gd \
    php8.3-bcmath php8.3-intl php8.3-readline

# PostgreSQL, Redis, Nginx, Supervisor
sudo apt install -y postgresql postgresql-contrib redis-server nginx supervisor
sudo systemctl enable redis-server

# Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
```

---

## Langkah 2 — Setup Database

```bash
sudo -u postgres psql
```

```sql
CREATE USER biiproject WITH PASSWORD 'password_kuat_anda';
CREATE DATABASE biiproject_db OWNER biiproject;
GRANT ALL PRIVILEGES ON DATABASE biiproject_db TO biiproject;
\q
```

---

## Langkah 3 — Deploy Aplikasi

```bash
cd /var/www
sudo git clone <repo-url> html
sudo chown -R $USER:www-data html
cd html

composer install --no-dev --optimize-autoloader
npm install && npm run build

cp .env.example .env
php artisan key:generate
```

### Edit `.env`

```env
APP_NAME="biiproject"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://domain.com

DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=biiproject_db
DB_USERNAME=biiproject
DB_PASSWORD=password_kuat_anda

CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
BROADCAST_CONNECTION=reverb

REDIS_HOST=127.0.0.1
REDIS_PORT=6379

REVERB_APP_ID=your-app-id
REVERB_APP_KEY=your-app-key
REVERB_APP_SECRET=your-app-secret
REVERB_HOST=domain.com
REVERB_PORT=8080
REVERB_SCHEME=https

BCRYPT_ROUNDS=12

# Opsional — Error monitoring
SENTRY_LARAVEL_DSN=https://xxxx@sentry.io/xxxx
SENTRY_TRACES_SAMPLE_RATE=0.1
SENTRY_PROFILES_SAMPLE_RATE=0.1
```

### Migrasi, Seed & Optimisasi

```bash
php artisan migrate --force
php artisan db:seed --force
php artisan cache:clear          # wajib setelah seeder
php artisan storage:link
php artisan optimize
php artisan l5-swagger:generate  # regen API docs
```

### Post-Deploy Verification

```bash
# Quality gate — pastikan tidak ada regresi
./vendor/bin/phpstan analyse --memory-limit=1G
./vendor/bin/pint --test
composer audit --no-dev

# Health check
curl -sf https://domain.com/api/health | jq .
# expect: {"status":"healthy","timestamp":"...","checks":{...}}
```

---

## Langkah 4 — Konfigurasi Nginx

`/etc/nginx/sites-available/biiproject`:

```nginx
server {
    listen 80;
    server_name domain.com;
    root /var/www/html/public;
    index index.php;

    client_max_body_size 50M;

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

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # WebSocket Reverb
    location /app {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 60s;
    }

    location ~ /\.(?!well-known) { deny all; }
}
```

> **Catatan keamanan:** Laravel mengirim header `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, dan `Permissions-Policy` dari middleware `SecurityHeaders`. Tidak perlu duplikasi di Nginx — biarkan aplikasi yang kontrol (lebih mudah di-update via setting).

```bash
sudo ln -s /etc/nginx/sites-available/biiproject /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```

---

## Langkah 5 — SSL (Let's Encrypt)

```bash
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d domain.com
```

Setelah HTTPS aktif, **aktifkan HSTS** dari admin panel: Global Settings → Login Security → `HSTS Enabled`. Aplikasi akan mengirim header `Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`.

---

## Langkah 6 — Background Workers (Supervisor)

### Queue Worker

`/etc/supervisor/conf.d/biiproject-worker.conf`:

```ini
[program:biiproject-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/worker.log
```

### Reverb (WebSocket)

`/etc/supervisor/conf.d/biiproject-reverb.conf`:

```ini
[program:biiproject-reverb]
command=php /var/www/html/artisan reverb:start --host=0.0.0.0 --port=8080
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/reverb.log
```

### Scheduler (Cron)

```bash
echo "* * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1" \
  | sudo crontab -u www-data -
```

> Scheduler menjalankan `dashboard:broadcast-stats` setiap menit — membutuhkan queue worker dan Reverb **sudah berjalan** agar broadcast terkirim ke browser. Pastikan keduanya distart via Supervisor sebelum mengaktifkan cron.

### Aktifkan

```bash
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start all
```

---

## Langkah 7 — Permission File

```bash
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache
```

---

## Langkah 8 — Konfigurasi Pasca-Deploy

### A. Global Settings

Login sebagai Super Admin → System Settings → Global Settings. Pastikan:

- [ ] `Password Policy`: min 12, charset mixed-case + digit + symbol, expiry & history sesuai kebijakan
- [ ] `Login Security`: max attempts 5, lockout duration, 2FA toggle, captcha jika perlu
- [ ] `IP & Access`: whitelist admin (IP kantor/VPN), auto-block on burst
- [ ] `HSTS Enabled`: ON (setelah SSL aktif)
- [ ] `Single Session`: ON jika kebijakan satu-device-per-akun

### B. Verifikasi Quality Gate

```bash
# Pastikan dependencies aman
composer audit --no-dev --abandoned=ignore

# Pastikan tidak ada regresi
php artisan test --parallel
```

---

## Layanan Eksternal (Opsional)

Sebagian besar bisa diatur via **Global Settings** di admin panel — tidak perlu edit `.env`.

### Email SMTP

```env
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=postmaster@domain.com
MAIL_PASSWORD=xxxxxxxx
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@domain.com
MAIL_FROM_NAME="biiproject"
```

### Sentry (Error Monitoring)

```env
SENTRY_LARAVEL_DSN=https://xxxx@o0.ingest.sentry.io/xxxx
SENTRY_TRACES_SAMPLE_RATE=0.1
```

Buat project di [sentry.io](https://sentry.io), pilih platform **Laravel**, dan salin DSN-nya.

### Telegram Bot

1. Chat `@BotFather` → `/newbot` → simpan **Token**
2. Kirim pesan ke bot, buka `https://api.telegram.org/bot<TOKEN>/getUpdates` → simpan **Chat ID**
3. Masukkan via Global Settings → Notifications

> **Catatan:** `IpAccessControl` middleware mengirim alert otomatis ke Telegram saat sebuah IP di-auto-block karena burst — pastikan token + chat id valid.

### Google Drive Backup

1. Google Cloud Console → buat project → enable **Google Drive API**
2. Buat **OAuth 2.0 Client ID** (Desktop app)
3. Dapatkan **Refresh Token** via OAuth Playground
4. Masukkan Client ID, Client Secret, Refresh Token, dan nama folder via Global Settings → Backup

### Amazon S3

1. Buat IAM user dengan policy `AmazonS3FullAccess`
2. Buat S3 bucket
3. Masukkan Access Key, Secret, Bucket, Region (dan endpoint opsional) via Global Settings → Backup

### Firebase Cloud Messaging (Push Notification Mobile)

1. Buat project di Firebase Console → Project Settings → Cloud Messaging
2. Unduh `google-services.json` (Android) atau `GoogleService-Info.plist` (iOS)
3. Letakkan di direktori mobile app sesuai panduan Expo
4. Device token diregistrasikan otomatis via API `/api/v1/devices/register`

---

## CI/CD

Workflow di `.github/workflows/ci.yml`. Setiap push ke `main`/`develop`/`config`/`advanced` dan setiap PR ke `main`/`develop` menjalankan:

1. **Test** — `php artisan test --parallel` (Postgres 15 + Redis 7 service containers)
2. **Lint** — `pint --test` + `composer audit --abandoned=ignore` + `permissions:audit`
3. **Static Analysis** — `phpstan analyse --memory-limit=1G`

Branch protection: PR tidak bisa di-merge kalau salah satu job gagal.

---

## Update Aplikasi

Cara tercepat dan teraman untuk memperbarui aplikasi adalah menggunakan skrip deployment otomatis yang sudah disediakan:

```bash
cd /var/www/html
sudo chmod +x deploy.sh
./deploy.sh
```

Skrip ini akan melakukan:

1. Masuk ke Maintenance Mode.
2. Update dependencies (Composer & NPM).
3. Build assets (Vite).
4. Run migrations.
5. Optimasi cache & pembersihan log.
6. Restart background workers (Queue & Reverb).
7. Verifikasi kesehatan sistem.
8. Keluar dari Maintenance Mode.

### Update Manual

```bash
cd /var/www/html
git pull origin main
php artisan down --secret="your-bypass-key"

composer install --no-dev --optimize-autoloader
npm ci && npm run build

php artisan migrate --force
php artisan cache:clear
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
php artisan l5-swagger:generate

sudo supervisorctl restart biiproject-worker:*
sudo supervisorctl restart biiproject-reverb

# Verifikasi
curl -sf https://domain.com/api/health | jq -e '.checks.database.status == "ok"'

php artisan up
```

---

## Deployment via Docker (alternatif)

```bash
git clone <repo-url> Project
cd Project
cp .env.example .env

# Edit .env:
# DB_HOST=pgsql       (nama service Docker, bukan 127.0.0.1)
# REDIS_HOST=redis

./vendor/bin/sail up -d
./vendor/bin/sail artisan migrate --seed --force
./vendor/bin/sail artisan cache:clear
./vendor/bin/sail artisan optimize
```

> **Penting:** Semua perintah `php artisan` di lingkungan Docker **harus** dijalankan via `./vendor/bin/sail artisan`, bukan langsung. Host `pgsql` hanya bisa di-resolve dari dalam Docker network.

---

## Troubleshooting

| Masalah | Solusi |
|---------|--------|
| 502 Bad Gateway | `sudo systemctl status php8.3-fpm` |
| Queue tidak jalan | `sudo supervisorctl status` |
| Permission denied | `sudo chown -R www-data:www-data storage bootstrap/cache` |
| Cache error setelah update | `php artisan optimize:clear && php artisan optimize` |
| Settings tidak muncul setelah seeder | `php artisan cache:clear` (settings di-cache 60 menit) |
| WebSocket gagal connect | `sudo supervisorctl status biiproject-reverb` + cek port 8080 di firewall |
| `pgsql` host tidak resolve | Pastikan `DB_HOST=127.0.0.1` (bukan `pgsql`) di server non-Docker |
| Telescope/log tidak ditemukan | Cek `storage/logs/laravel.log` & menu System Monitoring → Logs |
| Error monitoring tidak aktif | Pastikan `SENTRY_LARAVEL_DSN` sudah diset di `.env` |
| `/api/health` return 503 | Cek setiap field `checks.*.status` — yang `fail` mengindikasikan masalah. `warn` (storage >90%) tetap 200 by design. |
| OAuth callback 404 | Pastikan route order: `/auth/callback` HARUS sebelum `/auth/{provider}` di `routes/web.php`. |
| `column "google_id" does not exist` | Pastikan migrasi `2026_05_12_120000_add_social_columns_to_users_table` sudah jalan. |
| Dashboard stats tidak update real-time | Cek Reverb berjalan (`supervisorctl status biiproject-reverb`), queue worker aktif, dan `BROADCAST_CONNECTION=reverb` di `.env`. |
| Dashboard widget tidak tersimpan | Pastikan migrasi `2026_05_16_220000_create_dashboard_widget_preferences_table` sudah dijalankan. |

---

## Performance Tuning

### PHP-FPM

`/etc/php/8.3/fpm/pool.d/www.conf`:

```ini
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
```

### OPcache

`/etc/php/8.3/fpm/php.ini`:

```ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; production only
opcache.preload=/var/www/html/bootstrap/cache/preload.php
opcache.preload_user=www-data
```

### Redis Tuning

`/etc/redis/redis.conf`:

```
maxmemory 1gb
maxmemory-policy allkeys-lru
```

### PostgreSQL

Tambah index recommendation: sudah ada (lihat migrasi `2026_05_14_100000_add_performance_indexes`). Untuk dataset besar (>10M rows pada `activity_log`), pertimbangkan `pg_partman` untuk partisi bulanan.
