Skip to content

Teknis — Raga License Env

Dashboard admin Laravel + Filament untuk mengelola client dan lisensi platform RAGA. Selain panel admin, service ini mengekspos satu endpoint API (Basic Auth) yang dipakai service lain untuk validasi lisensi.

Repository

KeyValue
Git Remotehttps://git.tlab.co.id/tarantula/tarantula-v2/dashboard/raga-license-env.git
Branch Aktifmain
bash
git clone https://git.tlab.co.id/tarantula/tarantula-v2/dashboard/raga-license-env.git
cd raga-license-env

Tech Stack

LayerTeknologi
FrameworkLaravel 12 (PHP 8.2)
Admin PanelFilament 3.3
RBAC Panelbezhansalleh/filament-shield
Profil & 2FAjeffgreco13/filament-breezy
Activity Logrmsramos/activitylog + saade/filament-laravel-log (viewer)
Export Datapxlrbt/filament-excel
Map Pickerdotswan/filament-map-picker
REST API Otomatistomatophp/filament-api (API generik dari resource Filament)
DatabasePostgreSQL
Secret ManagementInfisical CLI (infisical run --watch)

Struktur Folder

raga-license-env/
├── app/
│   ├── Models/
│   │   ├── Client.php              # Data klien/perusahaan
│   │   ├── License.php              # Lisensi milik client
│   │   ├── InfisicalClient.php      # Kredensial Infisical per client
│   │   └── User.php                 # Akun login panel admin (Filament)
│   ├── Filament/
│   │   ├── Resources/
│   │   │   ├── ClientResource/
│   │   │   ├── LicenseResource/
│   │   │   ├── InfisicalClientResource/
│   │   │   └── UserResource/
│   │   ├── Pages/
│   │   └── Widgets/
│   ├── Services/
│   │   └── CustomFilamentAPIServices.php  # Kustomisasi filament-api
│   ├── Policies/                    # Policy otorisasi Filament Shield
│   ├── Http/Middleware/
│   │   └── BlockFileUpload.php      # Blokir endpoint upload/preview file Livewire (global middleware)
│   ├── Listeners/
│   │   └── SendTelegramLoginNotification.php  # Kirim notifikasi Telegram tiap ada login sukses ke panel
│   ├── Console/Commands/
│   │   └── SyncEnvToInfisical.php   # Command `sync:infisical` — push isi `.env` lokal ke Infisical
│   └── Helpers/
│       └── helper.php               # login_infisical(), update_secret_value(), load_fitur(), trigger_pipeline()
├── routes/
│   ├── api.php                      # GET /api/licenses/{id_client}, GET /api/health
│   └── web.php                      # POST /save-infisical (aksi form halaman Infisical Environment)
├── database/migrations/
├── docker/
│   ├── Dockerfile
│   ├── nginx/
│   └── php.ini
├── docker-compose.dev.yml
├── script.sh                        # Dipakai docker-compose.dev.yml: login Infisical -> `php artisan serve`
└── infisical.sh                     # Wrapper generik serupa, tidak dipakai docker-compose.dev.yml (lihat bagian Docker)

Environment Variables

Aplikasi & Database

Konfigurasi dasar Laravel standar (APP_KEY, APP_URL, dll) plus dua koneksi database di config/database.php: pgsql (aktif, DB_HOST/DB_PORT/DB_DATABASE/DB_USERNAME/DB_PASSWORD) dan mariadb (DB_HOST_2/DB_PORT_2/DB_DATABASE_2/DB_USERNAME_2/DB_PASSWORD_2) — koneksi kedua ini tampaknya sisa boilerplate Laravel, tidak terlihat dipakai di kode aplikasi.

Infisical (Bootstrap)

VariableKeterangan
INFISICAL_ENVEnvironment target (dev/staging/prod)
INFISICAL_PATHPath secrets di Infisical
INFISICAL_API_URLURL Infisical server
INFISICAL_CLIENT_IDClient ID Universal Auth
INFISICAL_CLIENT_SECRETClient Secret Universal Auth
INFISICAL_PROJECT_IDID project Infisical

Catatan penting: .env.example di repo ini berisi nilai APP_KEY dan kredensial Infisical (INFISICAL_CLIENT_ID, INFISICAL_CLIENT_SECRET, INFISICAL_PROJECT_ID) yang formatnya terlihat seperti nilai asli yang berfungsi, bukan placeholder kosong seperti file .env.example di service lain. Karena Infisical adalah penyimpan secret utama untuk seluruh platform, kredensial ini — kalau memang nyata — sebaiknya dirotasi segera dan file contoh diganti jadi placeholder murni.

Integrasi Tambahan (tidak ada di .env.example)

Variable berikut dibaca lewat env()/config('services.telegram.*') di kode tapi tidak dicantumkan di .env.example:

VariableKeterangan
TELEGRAM_TOKENToken bot Telegram untuk notifikasi login (config/services.php). Jika kosong, notifikasi login otomatis dilewati (tidak error)
TELEGRAM_CHAT_IDID chat/grup tujuan notifikasi login Telegram
TELEGRAM_TOPIC_IDID topic/thread Telegram (opsional, hanya dipakai jika grup memakai topics)
GIT_TOKENPersonal/project access token GitLab — dipakai create_trigger() untuk membuat pipeline trigger token
GIT_PROJECT_IDID project GitLab (git.tlab.co.id) yang di-trigger pipeline-nya dari halaman Infisical Environment untuk client bertipe frontend

Model Domain

ModelRelasiKeterangan
ClienthasMany License, hasMany InfisicalClientData perusahaan/pelanggan (name, company_name, email, phone, address, is_active, max_user)
LicensebelongsTo ClientLisensi (license_name, serial_number, qty, installed_in, binded_in, status, activated_date, expired_date, module)
InfisicalClientbelongsTo ClientMapping kredensial Infisical per client (type, infisical_project_id, infisical_client_id, infisical_client_secret, infisical_client_env, path, branch_source)
UserAkun login panel admin Filament (dipakai juga untuk autentikasi Basic Auth di endpoint API lisensi)

Ketiga model utama (Client, License, InfisicalClient) memakai Spatie\Activitylog\Traits\LogsActivity — setiap perubahan field yang terdaftar di getActivitylogOptions() dicatat ke tabel activity log.

Catatan keamanan: InfisicalClient::getActivitylogOptions() menyertakan field infisical_client_secret dalam logOnly(), dan field ini di form Filament (InfisicalClientResource) juga dibuat sebagai TextInput biasa tanpa ->password() (tidak disamarkan). Akibatnya, secret Infisical milik tiap client tercatat plaintext di tabel activity log setiap kali record dibuat/diubah, selain tersimpan plaintext di kolom aslinya. Field ini sebaiknya dikeluarkan dari logOnly() dan formnya diberi ->password() atau disembunyikan setelah tersimpan. Hal serupa (tapi dampaknya lebih kecil karena sudah di-hash) juga terjadi pada User::getActivitylogOptions() yang menyertakan kolom password.

Middleware & Event Listener

KomponenKeterangan
BlockFileUpload (middleware, global via bootstrap/app.php)Mem-block request ke livewire/upload-file dan livewire/preview-file/* dengan HTTP 403 — efektif menonaktifkan seluruh komponen upload file Filament (FileUpload) di panel ini, apa pun resource-nya
SendTelegramLoginNotification (listener, terpasang di AppServiceProvider::boot() untuk event Illuminate\Auth\Events\Login)Setiap ada login sukses ke panel admin, kirim pesan ke Telegram (TELEGRAM_TOKEN/TELEGRAM_CHAT_ID) berisi nama, email, IP, waktu (WIB), dan user-agent user yang login. Gagal kirim (mis. Telegram down) hanya dicatat ke log, tidak mengganggu proses login

Panel Admin (Filament Resources)

ResourceFungsi
ClientResourceCRUD data client/perusahaan
LicenseResourceCRUD lisensi per client
InfisicalClientResourceCRUD mapping kredensial Infisical per client
UserResourceCRUD akun admin (dilindungi Filament Shield RBAC)

Otorisasi antar-resource diatur lewat bezhansalleh/filament-shield (role & permission berbasis Spatie Permission), terpisah dari sistem RBAC User Service yang dipakai RAGA secara umum — dashboard ini punya sistem akses sendiri untuk tim internal TLab.

Widget Dashboard

Halaman utama panel (/) menampilkan 4 widget statistik/analitik:

WidgetIsi
DashboardOverviewStat card jumlah Client aktif, License aktif, dan Infisical Client aktif
UserOverviewStat card jumlah total user panel admin
RecentLicensesWidgetTabel 5 license dengan activated_date terbaru, beserta nama client dan tanggal expired
TopClientsWithMostLicensesChartChart top 5 client dengan jumlah license terbanyak

Halaman Infisical Environment

Aksi tabel "Environment" pada InfisicalClientResource membuka /infisical-env?id={id} (tab baru) — halaman kustom (App\Filament\Pages\InfisicalEnv, di luar resource CRUD standar) yang:

  1. Mengambil seluruh secret Infisical milik client tersebut langsung dari Infisical API (load_fitur()GET {INFISICAL_API_URL}/v3/secrets/raw, login pakai kredensial InfisicalClient yang bersangkutan) dan menampilkannya di form.
  2. Saat form disubmit (POST /save-infisical, didefinisikan di routes/web.php), setiap pasangan key-value diupdate lewat update_secret_value() (PATCH {INFISICAL_API_URL}/v3/secrets/raw/{key}).
  3. Jika InfisicalClient.type === 'frontend', setelah secret tersimpan otomatis memanggil trigger_pipeline() — membuat pipeline trigger token lalu memicu pipeline GitLab (git.tlab.co.id) pada branch branch_source milik client tersebut, lewat GIT_TOKEN/GIT_PROJECT_ID.

Halaman ini tidak muncul di menu navigasi ($shouldRegisterNavigation = false), hanya bisa diakses lewat tombol aksi di tabel InfisicalClientResource.

Endpoints

MethodPathAuthKeterangan
GET/api/licenses/{id_client}HTTP Basic Auth (auth.basic)Mengembalikan data client beserta seluruh lisensinya
GET/api/healthHealth check sederhana

GET /api/licenses/{id_client}

Divalidasi lewat middleware bawaan Laravel auth.basic, yang memeriksa kredensial terhadap tabel users yang sama dipakai untuk login panel admin — jadi LICENSE_API_EMAIL/LICENSE_API_PASSWORD yang dikonfigurasi di User Service dan API Tarantula sebenarnya adalah kredensial akun admin Filament, bukan service-account terpisah.

Response 200:

json
{
  "success": true,
  "data": {
    "id": "uuid-client",
    "name": "...",
    "company_name": "...",
    "licenses": [
      { "id": "uuid-license", "license_name": "...", "status": true, "expired_date": "..." }
    ]
  }
}

Response 404:

json
{ "success": false, "message": "License not found" }

Docker

docker-compose.dev.yml

ContainerImagePortKeterangan
raga-licensedocker/Dockerfile9000Aplikasi Laravel (PHP-FPM), menjalankan composer install lalu script.sh saat start
raga-postgrespostgres:16.1-alpine5001→5432Database utama (filament)

Startup (script.sh)

Perintah container app di docker-compose.dev.yml menjalankan composer install && script.sh. Sama seperti pola di opa-config dan service Node/Python lain: script.sh login ke Infisical via Universal Auth, lalu menjalankan php artisan serve --host=0.0.0.0 --port=9000 lewat infisical run --watch supaya secret ter-inject sebagai environment variable.

Repo ini juga punya infisical.sh di root — pola login Infisical yang sama, tapi generik (menjalankan "$@", command apa pun yang diberikan) alih-alih hardcode php artisan serve. Script ini tidak dipanggil oleh docker-compose.dev.yml; kemungkinan dipakai sebagai entrypoint terpisah untuk deployment produksi (image docker/Dockerfile sudah menyertakan supervisor dan konfigurasi nginx-fpm di docker/nginx/conf/default.conf, mengindikasikan setup produksi berbeda dari dev).

Build & Run

bash
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate

# Development
php artisan serve

# Docker Compose (dev)
docker compose -f docker-compose.dev.yml up --build

# Sync isi .env lokal ke Infisical (dev/staging/prod sekaligus)
php artisan sync:infisical