Technical — Raga License Env
A Laravel + Filament admin dashboard for managing clients and licenses for the RAGA platform. Besides the admin panel, this service exposes a single API endpoint (Basic Auth) used by other services for license validation.
Repository
| Key | Value |
|---|---|
| Git Remote | https://git.tlab.co.id/tarantula/tarantula-v2/dashboard/raga-license-env.git |
| Active Branch | main |
git clone https://git.tlab.co.id/tarantula/tarantula-v2/dashboard/raga-license-env.git
cd raga-license-envTech Stack
| Layer | Technology |
|---|---|
| Framework | Laravel 12 (PHP 8.2) |
| Admin Panel | Filament 3.3 |
| RBAC Panel | bezhansalleh/filament-shield |
| Profile & 2FA | jeffgreco13/filament-breezy |
| Activity Log | rmsramos/activitylog + saade/filament-laravel-log (viewer) |
| Data Export | pxlrbt/filament-excel |
| Map Picker | dotswan/filament-map-picker |
| Auto-Generated REST API | tomatophp/filament-api (generic API from Filament resources) |
| Database | PostgreSQL |
| Secret Management | Infisical CLI (infisical run --watch) |
Folder Structure
raga-license-env/
├── app/
│ ├── Models/
│ │ ├── Client.php # Client/company data
│ │ ├── License.php # Licenses owned by a client
│ │ ├── InfisicalClient.php # Per-client Infisical credentials
│ │ └── User.php # Admin panel login account (Filament)
│ ├── Filament/
│ │ ├── Resources/
│ │ │ ├── ClientResource/
│ │ │ ├── LicenseResource/
│ │ │ ├── InfisicalClientResource/
│ │ │ └── UserResource/
│ │ ├── Pages/
│ │ └── Widgets/
│ ├── Services/
│ │ └── CustomFilamentAPIServices.php # filament-api customization
│ ├── Policies/ # Filament Shield authorization policies
│ ├── Http/Middleware/
│ │ └── BlockFileUpload.php # Blocks Livewire upload/preview-file endpoints (global middleware)
│ ├── Listeners/
│ │ └── SendTelegramLoginNotification.php # Sends a Telegram notification on every successful panel login
│ ├── Console/Commands/
│ │ └── SyncEnvToInfisical.php # `sync:infisical` command — pushes local `.env` contents to 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 (form action for the Infisical Environment page)
├── database/migrations/
├── docker/
│ ├── Dockerfile
│ ├── nginx/
│ └── php.ini
├── docker-compose.dev.yml
├── docker-compose.dev.yml
├── script.sh # Used by docker-compose.dev.yml: Infisical login -> `php artisan serve`
└── infisical.sh # Similar generic wrapper, not used by docker-compose.dev.yml (see Docker section)Environment Variables
Application & Database
Standard Laravel base config (APP_KEY, APP_URL, etc.) plus two database connections in config/database.php: pgsql (active, DB_HOST/DB_PORT/DB_DATABASE/DB_USERNAME/DB_PASSWORD) and mariadb (DB_HOST_2/DB_PORT_2/DB_DATABASE_2/DB_USERNAME_2/DB_PASSWORD_2) — this second connection appears to be leftover Laravel boilerplate; it isn't referenced anywhere in the application code.
Infisical (Bootstrap)
| Variable | Description |
|---|---|
INFISICAL_ENV | Target environment (dev/staging/prod) |
INFISICAL_PATH | Secrets path in Infisical |
INFISICAL_API_URL | Infisical server URL |
INFISICAL_CLIENT_ID | Universal Auth Client ID |
INFISICAL_CLIENT_SECRET | Universal Auth Client Secret |
INFISICAL_PROJECT_ID | Infisical project ID |
Important note: this repo's
.env.examplecontainsAPP_KEYand Infisical credential values (INFISICAL_CLIENT_ID,INFISICAL_CLIENT_SECRET,INFISICAL_PROJECT_ID) formatted like real, working values rather than empty placeholders as seen in other services'.env.examplefiles. Since Infisical is the primary secret store for the entire platform, these credentials — if genuine — should be rotated promptly and the example file replaced with plain placeholders.
Additional Integrations (not in .env.example)
The following variables are read via env()/config('services.telegram.*') in the code but are not listed in .env.example:
| Variable | Description |
|---|---|
TELEGRAM_TOKEN | Telegram bot token for login notifications (config/services.php). If empty, the login notification is silently skipped |
TELEGRAM_CHAT_ID | Target chat/group ID for the login notification |
TELEGRAM_TOPIC_ID | Telegram topic/thread ID (optional, only used if the group uses topics) |
GIT_TOKEN | GitLab personal/project access token — used by create_trigger() to create a pipeline trigger token |
GIT_PROJECT_ID | GitLab project ID (git.tlab.co.id) whose pipeline is triggered from the Infisical Environment page for clients of type frontend |
Domain Model
| Model | Relation | Description |
|---|---|---|
Client | hasMany License, hasMany InfisicalClient | Company/customer data (name, company_name, email, phone, address, is_active, max_user) |
License | belongsTo Client | License (license_name, serial_number, qty, installed_in, binded_in, status, activated_date, expired_date, module) |
InfisicalClient | belongsTo Client | Per-client Infisical credential mapping (type, infisical_project_id, infisical_client_id, infisical_client_secret, infisical_client_env, path, branch_source) |
User | — | Filament admin panel login account (also used for Basic Auth on the license API endpoint) |
All three main models (Client, License, InfisicalClient) use Spatie\Activitylog\Traits\LogsActivity — every field listed in getActivitylogOptions() is recorded to the activity log table on change.
Security note:
InfisicalClient::getActivitylogOptions()includes theinfisical_client_secretfield inlogOnly(), and that field's Filament form input (InfisicalClientResource) is a plainTextInputwithout->password()(not masked). As a result, each client's Infisical secret is recorded in plaintext to the activity log table every time the record is created/updated, in addition to being stored in plaintext in its own column. This field should be excluded fromlogOnly()and the form input given->password()or hidden after saving. A similar (though lower-impact, since it's already hashed) issue exists onUser::getActivitylogOptions(), which includes thepasswordcolumn.
Middleware & Event Listener
| Component | Description |
|---|---|
BlockFileUpload (middleware, registered globally in bootstrap/app.php) | Blocks requests to livewire/upload-file and livewire/preview-file/* with an HTTP 403 — effectively disabling every Filament file-upload component (FileUpload) across the panel, regardless of resource |
SendTelegramLoginNotification (listener, wired up in AppServiceProvider::boot() for the Illuminate\Auth\Events\Login event) | On every successful admin panel login, sends a Telegram message (TELEGRAM_TOKEN/TELEGRAM_CHAT_ID) with the user's name, email, IP, time (WIB), and user agent. A failed send (e.g. Telegram is down) is only logged and does not interrupt the login flow |
Admin Panel (Filament Resources)
| Resource | Function |
|---|---|
ClientResource | CRUD for client/company data |
LicenseResource | CRUD for licenses per client |
InfisicalClientResource | CRUD for per-client Infisical credential mappings |
UserResource | CRUD for admin accounts (protected by Filament Shield RBAC) |
Authorization across resources is handled via bezhansalleh/filament-shield (Spatie Permission-based roles & permissions), separate from the User Service RBAC system used across RAGA in general — this dashboard has its own access system for TLab's internal team.
Dashboard Widgets
The panel's home page (/) shows 4 stat/analytics widgets:
| Widget | Content |
|---|---|
DashboardOverview | Stat cards for active Client, active License, and active Infisical Client counts |
UserOverview | Stat card for the total number of admin panel users |
RecentLicensesWidget | Table of the 5 most recently activated_date licenses, with client name and expiry date |
TopClientsWithMostLicensesChart | Chart of the top 5 clients by license count |
Infisical Environment Page
The "Environment" table action on InfisicalClientResource opens /infisical-env?id={id} (new tab) — a custom page (App\Filament\Pages\InfisicalEnv, outside the standard CRUD resources) that:
- Fetches all of that client's Infisical secrets directly from the Infisical API (
load_fitur()→GET {INFISICAL_API_URL}/v3/secrets/raw, authenticated with thatInfisicalClientrecord's credentials) and displays them in a form. - On form submit (
POST /save-infisical, defined inroutes/web.php), each key-value pair is updated viaupdate_secret_value()(PATCH {INFISICAL_API_URL}/v3/secrets/raw/{key}). - If
InfisicalClient.type === 'frontend', after the secrets are saved it automatically callstrigger_pipeline()— creating a pipeline trigger token and triggering a GitLab pipeline (git.tlab.co.id) on that client'sbranch_source, usingGIT_TOKEN/GIT_PROJECT_ID.
This page does not appear in the navigation menu ($shouldRegisterNavigation = false) — it's only reachable via the table action on InfisicalClientResource.
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /api/licenses/{id_client} | HTTP Basic Auth (auth.basic) | Returns a client's data along with all of its licenses |
GET | /api/health | — | Simple health check |
GET /api/licenses/{id_client}
Authenticated via Laravel's built-in auth.basic middleware, which checks credentials against the same users table used to log into the admin panel — so the LICENSE_API_EMAIL/LICENSE_API_PASSWORD configured in User Service and API Tarantula are actually a Filament admin account's credentials, not a separate service account.
200 Response:
{
"success": true,
"data": {
"id": "client-uuid",
"name": "...",
"company_name": "...",
"licenses": [
{ "id": "license-uuid", "license_name": "...", "status": true, "expired_date": "..." }
]
}
}404 Response:
{ "success": false, "message": "License not found" }Docker
docker-compose.dev.yml
| Container | Image | Port | Description |
|---|---|---|---|
raga-license | docker/Dockerfile | 9000 | Laravel app (PHP-FPM), runs composer install then script.sh on start |
raga-postgres | postgres:16.1-alpine | 5001→5432 | Main database (filament) |
Startup (script.sh)
The app container's command in docker-compose.dev.yml runs composer install && script.sh. Same pattern as opa-config and other Node/Python services: script.sh logs in to Infisical via Universal Auth, then runs php artisan serve --host=0.0.0.0 --port=9000 through infisical run --watch so secrets are injected as environment variables.
The repo also has an
infisical.shat its root — the same Infisical login pattern, but generic (runs"$@", whatever command is passed) instead of hardcodingphp artisan serve. This script is not called bydocker-compose.dev.yml; it's likely used as a separate entrypoint for production deployment (thedocker/Dockerfileimage already installssupervisorand there's an nginx-fpm config atdocker/nginx/conf/default.conf, suggesting a different setup for production than for 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 local .env to Infisical (dev/staging/prod at once)
php artisan sync:infisical