Versi 0.1.15 · Kembali ke License management
Tampilan memakai teks isi 16 px, tabel 14 px, judul lebih besar, dan formulir responsif. Tabel tetap dapat digeser horizontal pada layar kecil tanpa memperkecil teks.
Data kontak customer disimpan pada License Server dan tidak dimasukkan ke entitlement yang diterima Console. Lisensi lama tetap berlaku; detail profil lama yang belum direkam ditandai sebagai data legacy.
Pilih customer yang sama, buat kode baru dengan total kapasitas yang diinginkan, lalu ganti lisensi pada Console. Contoh: lisensi 20 seat diganti 30 seat berarti kapasitas menjadi 30, bukan 50. Penggantian atomik memensiunkan kode sebelumnya, mempertahankan identitas Agent, dan menolak penurunan kapasitas. Retry penggantian yang sama mengembalikan entitlement yang sama.
Lisensi baru adalah subscription 12 bulan. Masa aktif mulai saat Console mengaktifkan kode, bukan saat kode diterbitkan. Kode yang belum diaktifkan belum memakai masa berlangganan. Tidak ada grace period; pada waktu kedaluwarsa yang ditandatangani, Console menandai lisensi expired dan menahan operasi yang memerlukan entitlement.
Renewal sebelum masa berakhir menambah 12 bulan dari tanggal expiry lama, sehingga sisa masa yang sudah dibayar tidak hilang. Renewal setelah expiry mulai pada tanggal aktivasi baru. Tanggal dan status renewal tampil di daftar lisensi; filter tersedia untuk yang akan berakhir dalam 30 hari dan yang sudah expired. Lisensi yang diterbitkan sebelum pembaruan ini tetap tanpa tanggal kedaluwarsa dan tidak berubah.
Owner mengatur harga dari panel Annual seat pricing di License Server. Portal pricing tidak memiliki pengaturan terpisah; slider meminta estimasi langsung dari License Server, sedangkan Checkout memakai angka yang sama. Setiap order menyimpan harga dan revisi algoritma saat Checkout dibuat, jadi perubahan selanjutnya hanya memengaruhi order baru.
Rumus awal tahunan memakai harga dasar S$14.40 per seat dan harga bertingkat graduated. Rasio band awal adalah 100%, 90.28%, 83.33%, 76.39%, 69.44%, dan 65.97% untuk batas 25, 50, 100, 250, 500, dan 1,000 seat. Harga satu seat di band dihitung dari harga dasar dikali rasio; pembulatan dilakukan ke sen terdekat. Setiap band hanya menghitung seat yang masuk band itu.
Harga Checkout juga menambahkan allowance variabel Stripe 3.9%, uplift kampanye 0.8%, dan biaya tetap S$0.50. Total dihitung dengan gross-up agar persentase berlaku pada jumlah yang dibayar. Uplift kampanye adalah bagian dari harga dan bukan donasi otomatis ke Stripe Climate. Pajak tidak termasuk rumus ini; bila pajak wajib dipungut, jumlahnya ditampilkan terpisah saat Checkout.
Ubah harga dasar, rasio setiap band, allowance Stripe, uplift kampanye, atau biaya tetap, lalu tinjau harga per seat yang dihitung di tabel sebelum menyimpan. Rasio harus berurutan menurun dan band pertama tetap 100%. Panel hanya dapat diubah oleh Owner dan perubahan masuk ke Recent activity.
PortGuard mengirim email kode aktivasi. Untuk transaksi live yang terkonfirmasi, License Server meminta Stripe mengirim receipt pembayaran tersendiri ke alamat email yang dimasukkan saat Checkout. Receipt Stripe memuat total aktual yang dibayar; receipt bukan email aktivasi. Stripe tidak mengirim receipt untuk transaksi test mode. Jika pengiriman receipt live gagal, License Server mencoba ulang otomatis.
Licenses dan Recent activity memiliki tombol Previous/Next terpisah dan pilihan 10, 25, atau 50 baris. Cari nama perusahaan/Console instance dan filter status. Tombol View customer menampilkan profil lengkap, seat, dan Console terkait. Ringkasan atas tetap menghitung seluruh lisensi, tidak mengikuti filter.
Licensed seat capacity adalah total kapasitas lisensi yang sudah diaktifkan. Penggunaan seat dan perangkat online berada di Console. Revocation mencegah aktivasi berikutnya; entitlement offline yang sudah dimiliki Console tidak langsung ditarik dari jarak jauh.
Tampilan awal Current · Issued & Active menyembunyikan lisensi revoked. Setiap lisensi yang di-revoke, termasuk lisensi lama yang diganti saat penambahan seat, otomatis masuk ke Archive · Revoked. Pilih filter tersebut untuk melihat arsip; pilih All licenses untuk menampilkan semuanya.
Untuk menghapus lisensi testing, buka Archive · Revoked, pilih Delete pada lisensi yang dimaksud, periksa nama perusahaan, seat dan ID, centang persetujuan lalu pilih Delete permanently. Hanya lisensi revoked yang dapat dihapus. Penghapusan permanen menghapus record lisensi dari database; profil customer dan audit tetap tersimpan. Tidak ada penghapusan massal otomatis. Kode yang dihapus tidak dapat diaktifkan lagi. Entitlement offline yang sudah dipegang Console tidak otomatis ditarik. Gunakan backup bila record mungkin perlu dipulihkan.
Login menggunakan Google Workspace yang sama. Owner dapat menambahkan pengguna berdasarkan alamat email perusahaan dan memilih role: Owner mengelola pengguna, Admin mengelola customer/lisensi, dan Read-only hanya melihat data. Pengguna baru bisa masuk setelah memilih akun Google yang cocok. Menonaktifkan pengguna memutus aksesnya pada request berikutnya; audit tetap mencatat perubahan. Role Owner awal berasal dari daftar bootstrap LICENSING_GOOGLE_ADMIN_EMAILS. Minimal satu Owner aktif harus dipertahankan.
Di halaman admin, buka Backup & restore. Masukkan password minimal 12 karakter, ulangi password, lalu pilih Download encrypted backup. Simpan file .pgbackup di penyimpanan terpisah dari server dan simpan password secara terpisah. Tidak ada mekanisme untuk memulihkan password backup yang hilang.
Arsip mencakup database SQLite yang konsisten, profil customer, lisensi, riwayat, administrator token, dan private signing key Ed25519. Sesi login tidak disertakan. Enkripsi menggunakan AES-256-GCM dengan salt acak 16 byte, nonce acak 12 byte, dan scrypt N=32768/r=8/p=1. Perubahan isi atau password salah akan ditolak. Batas arsip 100 MiB.
Kunci penandatangan harus ikut dipulihkan: Console yang sudah terpasang mempercayai public key pasangannya. Restore database saja dengan kunci baru akan membuat lisensi baru tidak cocok dengan Console tersebut. Jangan menjalankan dua salinan License Server aktif dari backup yang sama.
cd /opt/kamindo-licensing/releases/0.1.6 /opt/kamindo-licensing/venvs/0.1.6/bin/python -m app.recovery backup \ --data-dir /var/lib/kamindo-licensing/data \ --output /root/portguard-license.pgbackup
Password diminta secara interaktif; jangan menaruhnya dalam command line. Pembuatan backup boleh saat layanan berjalan. Untuk deployment yang memakai override LICENSING_ADMIN_TOKEN, jalankan perintah dengan environment layanan yang sama atau gunakan tombol backup di GUI.
cd /opt/kamindo-licensing/releases/0.1.6 /opt/kamindo-licensing/venvs/0.1.6/bin/python -m app.recovery verify \ /root/portguard-license.pgbackup
Perintah memeriksa autentikasi arsip, struktur/integritas database, hubungan record, dan semua entitlement terhadap signing key. Catat key ID dan jumlah lisensi yang ditampilkan.
cd /opt/kamindo-licensing/releases/0.1.6 /opt/kamindo-licensing/venvs/0.1.6/bin/python -m app.recovery restore \ /root/portguard-license.pgbackup \ --destination /var/lib/kamindo-licensing/data-restored chown -R kamindo-licensing:kamindo-licensing /var/lib/kamindo-licensing/data-restored chmod 700 /var/lib/kamindo-licensing/data-restored
Selanjutnya, pada maintenance window, hentikan layanan dan pindahkan data lama ke nama yang belum dipakai. Contoh berikut mempertahankan data lama untuk rollback:
systemctl stop kamindo-licensing mv /var/lib/kamindo-licensing/data /var/lib/kamindo-licensing/data-before-restore-$(date +%Y%m%d-%H%M%S) mv /var/lib/kamindo-licensing/data-restored /var/lib/kamindo-licensing/data systemctl start kamindo-licensing curl --fail http://127.0.0.1:8200/api/v1/health
Pada server baru yang belum memiliki direktori data, lewati perintah pertama mv. Jika stop atau pemindahan gagal, jangan lanjutkan. Pastikan key ID sesuai, masuk kembali, dan periksa jumlah lisensi/customer. Restore kembali ke waktu backup: perubahan setelah backup tidak ada pada snapshot. Simpan direktori lama hingga validasi selesai. Pemulihan melalui web tidak menimpa database yang sedang aktif; langkah terminal diperlukan agar pemindahan data terkendali.
Konfigurasi HTTPS/nginx, DNS, unit layanan, dan environment Google berada di luar data directory dan harus dicadangkan terpisah secara aman. Arsip tidak berisi Client Secret Google. Untuk kehilangan seluruh server, pulihkan konfigurasi tersebut, gunakan domain HTTPS yang sama, dan pastikan callback OAuth tetap sama. Sesi admin lama tidak berlaku setelah restore. Signing key tidak boleh diganti.
Akun Owner awal: joseph@kamindo.co.id, domain Workspace kamindo.co.id. Daftar konfigurasi ini membentuk Owner awal. Setelah masuk, Owner dapat menambahkan pengguna dari domain yang sama dan menetapkan role; karyawan lain tidak otomatis mendapat akses.
openid, email, dan profile. Aplikasi tidak meminta akses Gmail, Drive, atau Calendar.https://licensing.kamindo.co/auth/google/callback. Alur backend tidak memerlukan Authorized JavaScript origins.# /etc/kamindo-licensing/google.env — root:root, mode 600 LICENSING_PUBLIC_ORIGIN=https://licensing.kamindo.co LICENSING_GOOGLE_DOMAIN=kamindo.co.id LICENSING_GOOGLE_ADMIN_EMAILS=joseph@kamindo.co.id LICENSING_GOOGLE_CLIENT_ID=ISI_CLIENT_ID_DARI_GOOGLE LICENSING_GOOGLE_CLIENT_SECRET=ISI_CLIENT_SECRET_DARI_GOOGLE LICENSING_ALLOW_TOKEN_LOGIN=0
File konfigurasi di server disiapkan dengan Client ID/Secret kosong sampai Anda mengisinya. Setelah diisi, restart layanan dan buka halaman login:
sudoedit /etc/kamindo-licensing/google.env systemctl restart kamindo-licensing curl --fail http://127.0.0.1:8200/api/v1/auth/config
Hasil yang diharapkan: google_enabled: true, token_enabled: false. Klik Sign in with company Google account dan pilih akun admin. Server memverifikasi signature Google, issuer, audience, expiry, nonce, state, email terverifikasi, hosted domain, dan status akun aktif pada database user. Alur memakai PKCE; sesi admin memakai cookie Secure/HttpOnly selama maksimal 8 jam, dengan proteksi CSRF untuk perubahan data. Sign out menghapus sesi pada server.
Untuk pemulihan akses darurat oleh operator root, set LICENSING_ALLOW_TOKEN_LOGIN=1 lalu restart, gunakan administrator token yang sudah ada, perbaiki konfigurasi Google, dan kembalikan nilainya ke 0. Jangan membagikan token kepada pengguna umum.
Sumber konfigurasi: Google OpenID Connect dan Authlib Starlette OAuth. Uji login Google langsung tetap memerlukan Client ID/Secret dari project perusahaan.
Console tetap memakai POST /api/v1/activate dengan activation code dan Console instance ID. Login Google hanya untuk administrasi License Server dan tidak mengubah protokol aktivasi, signing key, maupun kontrak Agent. Entitlement subscription baru menyertakan expires_at; Console yang mendukung claim ini menandai masa yang habis sebagai expired. Entitlement lama tanpa expiry tetap valid. Token admin hanya berlaku jika mode token diaktifkan. Lisensi memakai schema 1 dan signature Ed25519, bukan enkripsi nama perusahaan.
GET /api/v1/licenses?page=1&page_size=10: daftar lisensi, summary, pagination.GET /api/v1/activity?page=1&page_size=10: audit dengan pagination independen.GET /api/v1/customers?q=company: cari customer untuk dipakai kembali.GET/POST /api/v1/admin-users dan PATCH /api/v1/admin-users/{email}: Owner mengelola akun, role, dan akses.POST /api/v1/licenses: profil customer lengkap atau customer_id, seat_limit dan notes. Format legacy customer_name tetap diterima untuk kompatibilitas operator API.POST /api/v1/backups: download arsip terenkripsi, hanya admin.GET /api/v1/health dan /api/v1/public-key: kesiapan dan kunci publik, tanpa data rahasia.Owner dapat membuka panel Brevo transactional email pada halaman License Server. Atur nama dan alamat pengirim yang sudah diverifikasi di Brevo, alamat reply-to bila diperlukan, lalu masukkan API key. API key disimpan terenkripsi oleh server dan tidak ditampilkan kembali. Sebelum menyimpan API key, operator server harus membuat LICENSING_BREVO_SETTINGS_KEY dengan openssl rand -base64 32 dan menyimpannya pada environment file License Server dengan izin akses terbatas. Cadangkan kunci ini secara terpisah; database saja tidak cukup untuk memulihkan integrasi.
Gunakan kolom penerima dan tombol Send test email untuk memeriksa pengiriman. Pengiriman baru terjadi setelah tombol ditekan. Brevo memakai HTTPS port 443, sehingga dapat digunakan pada DigitalOcean yang membatasi SMTP keluar. Verifikasi SPF, DKIM, dan DMARC domain pengirim di Brevo. API key tidak boleh dimasukkan ke Website atau repository.