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
| Key | Value |
|---|---|
| Git Remote | https://git.tlab.co.id/tarantula/tarantula-v2/dashboard/raga-license-env.git |
| Branch Aktif | main |
git clone https://git.tlab.co.id/tarantula/tarantula-v2/dashboard/raga-license-env.git
cd raga-license-envTech Stack
| Layer | Teknologi |
|---|---|
| Framework | Laravel 12 (PHP 8.2) |
| Admin Panel | Filament 3.3 |
| RBAC Panel | bezhansalleh/filament-shield |
| Profil & 2FA | jeffgreco13/filament-breezy |
| Activity Log | rmsramos/activitylog + saade/filament-laravel-log (viewer) |
| Export Data | pxlrbt/filament-excel |
| Map Picker | dotswan/filament-map-picker |
| REST API Otomatis | tomatophp/filament-api (API generik dari resource Filament) |
| Database | PostgreSQL |
| Secret Management | Infisical 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)
| Variable | Keterangan |
|---|---|
INFISICAL_ENV | Environment target (dev/staging/prod) |
INFISICAL_PATH | Path secrets di Infisical |
INFISICAL_API_URL | URL Infisical server |
INFISICAL_CLIENT_ID | Client ID Universal Auth |
INFISICAL_CLIENT_SECRET | Client Secret Universal Auth |
INFISICAL_PROJECT_ID | ID project Infisical |
Catatan penting:
.env.exampledi repo ini berisi nilaiAPP_KEYdan 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.exampledi 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:
| Variable | Keterangan |
|---|---|
TELEGRAM_TOKEN | Token bot Telegram untuk notifikasi login (config/services.php). Jika kosong, notifikasi login otomatis dilewati (tidak error) |
TELEGRAM_CHAT_ID | ID chat/grup tujuan notifikasi login Telegram |
TELEGRAM_TOPIC_ID | ID topic/thread Telegram (opsional, hanya dipakai jika grup memakai topics) |
GIT_TOKEN | Personal/project access token GitLab — dipakai create_trigger() untuk membuat pipeline trigger token |
GIT_PROJECT_ID | ID project GitLab (git.tlab.co.id) yang di-trigger pipeline-nya dari halaman Infisical Environment untuk client bertipe frontend |
Model Domain
| Model | Relasi | Keterangan |
|---|---|---|
Client | hasMany License, hasMany InfisicalClient | Data perusahaan/pelanggan (name, company_name, email, phone, address, is_active, max_user) |
License | belongsTo Client | Lisensi (license_name, serial_number, qty, installed_in, binded_in, status, activated_date, expired_date, module) |
InfisicalClient | belongsTo Client | Mapping kredensial Infisical per client (type, infisical_project_id, infisical_client_id, infisical_client_secret, infisical_client_env, path, branch_source) |
User | — | Akun 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 fieldinfisical_client_secretdalamlogOnly(), dan field ini di form Filament (InfisicalClientResource) juga dibuat sebagaiTextInputbiasa 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 darilogOnly()dan formnya diberi->password()atau disembunyikan setelah tersimpan. Hal serupa (tapi dampaknya lebih kecil karena sudah di-hash) juga terjadi padaUser::getActivitylogOptions()yang menyertakan kolompassword.
Middleware & Event Listener
| Komponen | Keterangan |
|---|---|
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)
| Resource | Fungsi |
|---|---|
ClientResource | CRUD data client/perusahaan |
LicenseResource | CRUD lisensi per client |
InfisicalClientResource | CRUD mapping kredensial Infisical per client |
UserResource | CRUD 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:
| Widget | Isi |
|---|---|
DashboardOverview | Stat card jumlah Client aktif, License aktif, dan Infisical Client aktif |
UserOverview | Stat card jumlah total user panel admin |
RecentLicensesWidget | Tabel 5 license dengan activated_date terbaru, beserta nama client dan tanggal expired |
TopClientsWithMostLicensesChart | Chart 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:
- Mengambil seluruh secret Infisical milik client tersebut langsung dari Infisical API (
load_fitur()→GET {INFISICAL_API_URL}/v3/secrets/raw, login pakai kredensialInfisicalClientyang bersangkutan) dan menampilkannya di form. - Saat form disubmit (
POST /save-infisical, didefinisikan diroutes/web.php), setiap pasangan key-value diupdate lewatupdate_secret_value()(PATCH {INFISICAL_API_URL}/v3/secrets/raw/{key}). - Jika
InfisicalClient.type === 'frontend', setelah secret tersimpan otomatis memanggiltrigger_pipeline()— membuat pipeline trigger token lalu memicu pipeline GitLab (git.tlab.co.id) pada branchbranch_sourcemilik client tersebut, lewatGIT_TOKEN/GIT_PROJECT_ID.
Halaman ini tidak muncul di menu navigasi ($shouldRegisterNavigation = false), hanya bisa diakses lewat tombol aksi di tabel InfisicalClientResource.
Endpoints
| Method | Path | Auth | Keterangan |
|---|---|---|---|
GET | /api/licenses/{id_client} | HTTP Basic Auth (auth.basic) | Mengembalikan data client beserta seluruh lisensinya |
GET | /api/health | — | Health 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:
{
"success": true,
"data": {
"id": "uuid-client",
"name": "...",
"company_name": "...",
"licenses": [
{ "id": "uuid-license", "license_name": "...", "status": true, "expired_date": "..." }
]
}
}Response 404:
{ "success": false, "message": "License not found" }Docker
docker-compose.dev.yml
| Container | Image | Port | Keterangan |
|---|---|---|---|
raga-license | docker/Dockerfile | 9000 | Aplikasi Laravel (PHP-FPM), menjalankan composer install lalu script.sh saat start |
raga-postgres | postgres:16.1-alpine | 5001→5432 | Database 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.shdi root — pola login Infisical yang sama, tapi generik (menjalankan"$@", command apa pun yang diberikan) alih-alih hardcodephp artisan serve. Script ini tidak dipanggil olehdocker-compose.dev.yml; kemungkinan dipakai sebagai entrypoint terpisah untuk deployment produksi (imagedocker/Dockerfilesudah menyertakansupervisordan konfigurasi nginx-fpm didocker/nginx/conf/default.conf, mengindikasikan setup produksi berbeda dari dev).
Build & Run
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