Search by

bangsamu / master

BangsaMU

Clay menggunakan master

Package info

github.com/BangsaMU/master

pkg:composer/bangsamu/master

Statistics

Installs: 865

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v2.4.2 2026-10-23 07:43 UTC

This package is auto-updated.

Last update: 2026-10-23 07:43:51 UTC


README

Paket terpusat Master Data untuk ekosistem aplikasi berbasis Laravel.

Fitur Utama

  • Cakupan 15 Tabel Master Data:
    1. master_item_code (item_code)
    2. master_category (category_code)
    3. master_company (company_code)
    4. master_department (department_code)
    5. master_employee (no_ktp sebagai kode identitas utama unik)
    6. master_item_group (item_group_code)
    7. master_job_position (position_code)
    8. master_location (loc_code)
    9. master_pca (pca_code)
    10. master_project (project_code)
    11. master_project_detail (project_code_client)
    12. master_status (kode)
    13. master_uom (uom_code)
    14. master_vendor (vendor_code)
    15. master_vendor_contact (vendor_contact_name)
  • Real-Time WebSocket Broadcasting (Senada Reverb Hub): Setiap perubahan data master (created, updated, deleted) otomatis di-broadcast secara real-time ke channel masterdata.items dengan single unified event MasterDataUpdated (tanpa duplikasi notifikasi).
  • FCM-Like Catch-Up Sync (Tahan Offline/App Mati):
    • Jika aplikasi klien atau browser pengguna sempat offline atau server mati saat broadcast dikirimkan, klien tidak akan kehilangan data.
    • Checkpoint ID broadcast terakhir tersimpan aman di tabel dashboard_settings (key='last_synced_broadcast_id').
    • Paket secara otomatis melakukan validasi dan membuat tabel dashboard_settings jika belum ada di database lokal aplikasi.
    • Begitu koneksi WebSocket tersambung kembali, frontend secara otomatis memanggil /master-sync/catch-up untuk mengambil seluruh update yang terlewat.
    • Tersedia juga CLI command: php artisan master:catch-up.
  • Memory-Safe Data Cloning (MasterDataSyncService): Sinkronisasi data bertahap (chunking 250 rows) dengan MySQL upsert untuk menjaga tabel lokal tetap menjadi clone identik dari database master (db_master).
  • Whitelist Sinkronisasi & Penekanan Notifikasi (Notification Suppression):
    • Filter Tabel Lokal & Prefix master_*: Hanya tabel berawalan master_* yang benar-benar ada di database lokal aplikasi yang memenuhi syarat untuk disinkronkan. Tabel di luar database lokal atau tabel cadangan (*OLD, *dump*) otomatis diabaikan.
    • Penyimpanan di dashboard_settings:
      • key: sync_allowed_master_tables
      • group: senada_sync
      • type: json
      • label: Allowed Master Data Sync Tables
      • value: JSON array daftar tabel master_* yang diizinkan untuk disinkronkan (misal: ["master_category","master_company","master_department","master_employee","master_item_code", ...]).
      • options: JSON array seluruh tabel master_* yang terdeteksi di database lokal.
      • Auto-Discovery: Jika konfigurasi belum ada, sistem secara otomatis memindai database lokal dan menginisialisasi tabel-tabel master_* yang valid ke dashboard_settings.
    • Silent Ignore (Tanpa Popup Toast): Jika event broadcast diterima dari Senada untuk tabel yang tidak ada di database lokal klien atau tidak diaktifkan di dashboard_settings, klien mengabaikan event tersebut secara hening tanpa memunculkan popup toast notifikasi dan tanpa request fetch yang sia-sia karena tidak berdampak pada aplikasi klien.
    • Respon Backend Aman: Endpoint sinkronisasi mengembalikan 200 OK dengan flag skipped: true (bukan error 422).
  • Built-in Endpoints:
    • POST /master-sync/sync (Sinkronisasi universal semua master table)
    • POST /master-sync/sync-items (Alias kompatibel untuk item code)
    • GET|POST /master-sync/catch-up (Catch-up sync event yang terlewat)
    • GET /master-sync/allowed-tables (Daftar whitelist tabel yang diizinkan untuk disinkronkan)
    • POST /master-sync/channel-auth (Otorisasi channel privat browser)

Token Launch Viewer Annotation (opt-in)

Link viewer annotation tanpa token statis md5(email) dan tanpa cek cookie lintas-origin: route GET /annotation/open membuat token terenkripsi yang terikat ke session user, dicek server-side oleh api/getcurrentuser, api/getSignature, dan api/getParaf. Default ANNOTATION_TOKEN_MODE=legacy (perilaku lama). Pakai helper annotation_launch_url($fileUrl, $callback) di app. Detail dan langkah aktivasi: docs/annotation-launch-token.md.

Filter Dropdown Master dari Setting (opt-in)

MASTER_SELECT2_SETTING_FILTER=true (config MasterCrudConfig.SELECT2_SETTING_FILTER, default false) membuat api/getmaster_*byparams (sumber dropdown select2) memakai filter yang sama dengan list master: baris tabel setting dengan category = nama tabel (fallback dashboard_settings.group), name/key = kolom, value = daftar nilai dipisah koma; antar setting digabung OR. Lookup nilai terpilih (?id=) tidak difilter, jadi data lama tetap tampil.

Konfigurasi Database (config/database.php)

Pastikan koneksi db_master telah didaftarkan di aplikasi client:

'db_master' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL_MASTER'),
    'host' => env('DB_HOST_MASTER', '192.168.20.187'),
    'port' => env('DB_PORT_MASTER', '3306'),
    'database' => env('DB_DATABASE_MASTER', 'master'),
    'username' => env('DB_USERNAME_MASTER', 'user'),
    'password' => env('DB_PASSWORD_MASTER', 'pass'),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => false,
],

Konfigurasi Lingkungan (.env)

# ==============================================================================
# SENADA REVERB WEBSOCKET & MASTER SYNC (SISI CLIENT)
# ==============================================================================
# Endpoint Senada Broadcast Hub
SENADA_URL=http://192.168.20.187:9029
SENADA_API_KEY=snd_masterdata_key_secret
SENADA_BROADCAST_ACTIVE=true

# Kredensial Reverb WebSocket (Wajib untuk otorisasi channel private)
REVERB_APP_ID=senada_app
REVERB_APP_KEY=senada_hub_key
REVERB_APP_SECRET=senada_hub_secret
REVERB_HOST="192.168.20.187"
REVERB_PORT=9029
REVERB_SCHEME=http

# ==============================================================================
# JADWAL OTOMATIS & DISTRIBUTED LOCK SINKRONISASI MASTER
# ==============================================================================
# Mengaktifkan/menonaktifkan auto-schedule catch-up di Laravel Scheduler (true/false)
MASTER_SYNC_SCHEDULE_ENABLED=true
# Frekuensi jadwal: hourly (default 1 jam), everyThirtyMinutes, everyTwoHours, daily, atau cron string "0 * * * *"
MASTER_SYNC_SCHEDULE_INTERVAL=hourly
# Maksimal jumlah event broadcast yang disinkronkan per siklus
MASTER_SYNC_SCHEDULE_LIMIT=50
# Durasi masa aktif Central Master Sync Lock (detik, default: 300 = 5 menit, maks 3600 = 1 jam)
MASTER_SYNC_LOCK_TTL=300
# Cooldown pencegah banjir sync saat user login / buka tab baru di browser (detik, default: 300 = 5 menit)
MASTER_SYNC_BROWSER_COOLDOWN=300

Cara Penggunaan di Aplikasi Client

1. Memasang Listener Real-time di View

Cukup tambahkan komponen Blade ini di layout utama aplikasi (seperti di layouts/app.blade.php atau components/layouts/app.blade.php):

<x-master::broadcast-listener />

Komponen ini akan secara otomatis:

  1. Menginisiasi koneksi ke Senada WebSocket Reverb.
  2. Saat koneksi terhubung (connected), otomatis memanggil catch-up ke Senada dengan proteksi Local Cooldown & Multi-Tab Debounce (localStorage), sehingga saat 50 user login bersamaan tidak terjadi banjir request ke database master.
  3. Berlangganan ke channel masterdata.items dan channel privat pengguna (private-user.{email}).
  4. Menampilkan toast notifikasi modern saat master data berubah atau saat catch-up selesai.
  5. Melakukan sinkronisasi database lokal ke db_master via endpoint bawaan paket /master-sync/sync.
  6. Merefresh DataTable aktif secara otomatis jika ada di halaman.
  7. Me-reload halaman jika pengguna sedang membuka formulir/detail dari item yang bersangkutan.

2. Penjadwalan Otomatis & Central Distributed Lock

A. Penjadwalan Otomatis (Auto-Scheduler)

Paket secara otomatis mendaftarkan task php artisan master:catch-up ke Laravel Scheduler tanpa perlu mengedit file app/Console/Kernel.php secara manual. Pastikan cron server aplikasi Anda sudah menjalankan scheduler standar Laravel:

* * * * * cd /path/to/app && php artisan schedule:run >> /dev/null 2>&1

Frekuensi eksekusi dapat diatur bebas via .env:

  • MASTER_SYNC_SCHEDULE_INTERVAL=hourly (Default: setiap 1 jam)
  • MASTER_SYNC_SCHEDULE_INTERVAL=everyThirtyMinutes (Setiap 30 menit)
  • MASTER_SYNC_SCHEDULE_INTERVAL=everyTwoHours (Setiap 2 jam)
  • MASTER_SYNC_SCHEDULE_INTERVAL="0 */4 * * *" (Custom cron: setiap 4 jam)

B. Central Distributed Lock (Perlindungan DB Master Lintas Aplikasi)

Untuk mencegah lonjakan koneksi dan perlambatan pada Database Master ketika banyak aplikasi (Clay, MCU, Warehouse, dll.) menjalankan sync secara bersamaan:

  1. Single-Sync Guarantee: Sebelum melakukan sinkronisasi dari db_master, aplikasi meminta Central Lock ke Senada Hub. Hanya 1 aplikasi yang diizinkan melakukan sinkronisasi dalam satu waktu.
  2. Auto-Postpone yang Ramah: Jika aplikasi lain sedang melakukan sinkronisasi, proses sync ditunda secara elegan tanpa membebani koneksi DB Master.
  3. Anti-Stuck & Auto-Expire: Lock memiliki TTL otomatis (default 5 menit / diset via MASTER_SYNC_LOCK_TTL). Jika aplikasi mati mendadak saat proses sync, lock otomatis kadaluarsa sehingga proses sync berikutnya tidak akan macet selamanya.
  4. Force Override: Tersedia opsi --force-lock untuk memecah lock yang dicurigai macet.

3. Perintah Artisan Catch-Up & Lock Management

A. Catch-Up Sync

# Sinkronkan semua broadcast yang terlewat (dilindungi Central Lock)
php artisan master:catch-up

# Cek ID checkpoint sinkronisasi saat ini
php artisan master:catch-up --info

# Paksa catch-up dan override lock jika lock terindikasi macet
php artisan master:catch-up --force-lock

# Jalankan dengan parameter checkpoint & limit tertentu
php artisan master:catch-up --since=80 --limit=50

B. Inspeksi & Rilis Central Lock (master:sync-lock)

# Cek apakah saat ini ada aplikasi yang sedang mengunci DB Master
php artisan master:sync-lock --status

# Paksa rilis lock yang macet di Senada Hub
php artisan master:sync-lock --release

# Manual lock untuk kebutuhan maintenance khusus
php artisan master:sync-lock --acquire --ttl=600

3. Memanggil Broadcast Secara Manual dari Kode

Setiap Model di bawah namespace Bangsamu\Master\Models\* sudah terpasang trait BroadcastsMasterChanges secara otomatis. Namun jika ingin memanggil secara manual:

use Bangsamu\Master\Services\MasterBroadcastService;

// Broadcast perubahan entitas master apapun
$broadcastService = app(MasterBroadcastService::class);
$broadcastService->broadcastTableChange('master_category', $categoryModel, 'updated');

4. Memanggil Sinkronisasi Manual dari Kode

use Bangsamu\Master\Services\MasterDataSyncService;

$syncService = app(MasterDataSyncService::class);

// 1. Sinkronkan tabel tertentu berdasarkan ID
$result = $syncService->syncTable('master_employee', 12, 450, 'updated');

// 2. Jalankan Catch-Up event terlewat
$catchUpResult = $syncService->catchUpMissedBroadcasts();

5. Optimasi Bulk Import (10.000+ Data) & Single Summary Broadcast

Untuk mencegah Broadcast Storm (di mana pengunggahan 10.000 data memicu 10.000 panggilan HTTP ke Senada, menyebabkan HTTP 429 Rate Limit dan browser freeze):

  1. Suppression Selama Proses Import: Semua per-row broadcast dinonaktifkan sementara via MasterBroadcastService::withoutBroadcasting(...) dan event hook BeforeImport.
  2. 1 Kali Ringkasan Broadcast di Akhir Batch: Setelah seluruh sheet dan chunk selesai dibaca, dikirimkan 1 kali ringkasan event MasterDataUpdated ke Senada:
    {
        "table": "master_item_code",
        "action": "created",
        "id": 26500,
        "max_id": 26500,
        "batch_count": 10000,
        "is_batch": true,
        "identifier": "Batch Import (10.000 data)",
        "item_code": "Batch Import (10.000 data)"
    }
  3. Cloning Otomatis Sisi Klien: Aplikasi klien yang menerima event ini mendeteksi bahwa max_id master (misal: 26.500) melompat melampaui max_id lokal (misal: 16.500). Klien otomatis mengeksekusi syncRange() dengan batch 250 record secara langsung dari db_master via MySQL upsert.
  4. Trait HandlesBatchImportBroadcast: Semua class Import (Item Code, Category, Department, Employee, Item Group, Location, PCA, Project, UoM, Vendor) mengimplementasikan trait HandlesBatchImportBroadcast serta WithChunkReading (chunk 1.000) dan koleksi lookup in-memory (memoized) untuk menghindari N+1 kueri ke database master.

6. API Sinkronisasi Status User (Active / Inactive) Lokal

API ini disediakan untuk menerima webhook/cURL dari aplikasi master (master-data via App\Services\UserStatusSyncService) guna mengubah status user (is_active) menjadi aktif (1) atau inaktif (0) pada database default lokal (tabel master_user), bukan pada koneksi db_master.

Endpoints

Method Endpoint Deskripsi
GET / POST /api/user/status Endpoint Utama Sinkronisasi status user
GET / POST /api/user/set-status Endpoint alias
GET / POST /api/setUser.php Kompatibilitas URL legacy API
GET / POST /setUser.php Kompatibilitas URL legacy root
GET /api/users Daftar user lokal (Cursor Paginated)
GET /api/users/{id} Detail user lokal

Parameter Request

Parameter Tipe Wajib Keterangan
email_id string Ya Alamat email user yang akan disinkronkan. Menerima juga alias: email, person_id, person_email.
status int/string Ya 1 / active / true untuk Aktif, 0 / inactive / false untuk Inaktif. Menerima juga alias: active.
token string Ya Token keamanan HMAC SHA-256 (atau fallback MD5) yang dihasilkan dari api_token($email_id) menggunakan SsoConfig.main.KEY, atau static token. Dapat juga dikirim via header Authorization: Bearer <token>.

Contoh Request (cURL)

A. GET Request (Sesuai cURL UserStatusSyncService di master-data):

curl -X GET "http://clay-domain/api/user/status?email_id=user@example.com&status=1&token=45be95886cd458871369dba552ee3fd9c82bb578ff9863131ab4d2bbe40b52e7"

B. POST Request dengan JSON Body:

curl -X POST "http://clay-domain/api/user/status" \
     -H "Content-Type: application/json" \
     -d '{
       "email_id": "user@example.com",
       "status": 0,
       "token": "45be95886cd458871369dba552ee3fd9c82bb578ff9863131ab4d2bbe40b52e7"
     }'

Format Response

Sukses (HTTP 200 OK)

{
  "status": true,
  "code": 200,
  "message": "User 'user@example.com' status successfully set to active.",
  "data": {
    "id": 12,
    "name": "Bagas Alwi",
    "email": "user@example.com",
    "previous_status": 0,
    "current_status": 1,
    "status_label": "active"
  }
}

Token Tidak Valid (HTTP 401 Unauthorized)

{
  "status": false,
  "code": 401,
  "message": "Unauthorized: Invalid or missing token."
}

User Tidak Ditemukan di DB Lokal (HTTP 404 Not Found)

{
  "status": false,
  "code": 404,
  "message": "User not found for 'unknown@example.com'."
}

Validasi Gagal (HTTP 422 Unprocessable Entity)

{
  "status": false,
  "code": 422,
  "message": "User identifier (email_id) is required.",
  "errors": {
    "email_id": [
      "User identifier (email_id) is required."
    ]
  }
}

Logging & Tracing Aktivitas

Semua aktivitas request hit, penolakan token, validasi gagal, user not found, dan update status berhasil dicatat secara spesifik ke file log harian khusus:

  • Lokasi File: storage/logs/user-sync-YYYY-MM-DD.log (dan terduplikasi di storage/logs/laravel-YYYY-MM-DD.log).
  • Live Trace Command:
    tail -f storage/logs/user-sync-$(date +%Y-%m-%d).log