Files
device-management/resources/js/pages/documentation/deployment.tsx
T
Wian Drs 60946ddf37
tests / ci (push) Has been cancelled
update lisensi prosess
2026-08-25 13:43:55 +07:00

556 lines
28 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Head, Link } from '@inertiajs/react';
import {
AlertTriangle,
ArrowRight,
Cloud,
Database,
Download,
KeyRound,
Network,
Server,
ShieldCheck,
Terminal,
Users,
} from 'lucide-react';
import PublicThemeToggle from '@/components/public-theme-toggle';
const Code = ({ children }: { children: string }) => (
<pre className="mt-3 overflow-x-auto rounded-xl border border-white/10 bg-black/40 p-4 text-xs leading-6 text-sky-100">
<code>{children}</code>
</pre>
);
const Step = ({
number,
children,
}: {
number: number;
children: React.ReactNode;
}) => (
<li className="flex gap-3 text-sm leading-6 text-slate-300">
<span className="flex size-7 shrink-0 items-center justify-center rounded-full bg-sky-500/15 text-xs font-semibold text-sky-300">
{number}
</span>
<div>{children}</div>
</li>
);
const vendorRows = [
[
'MikroTik RouterOS 6/7',
'RouterOS API',
'8728 / 8729',
'Port API wajib diisi. TLS mengikuti pengaturan tenant.',
],
[
'OLT ZTE C300/C320',
'SSH',
'22',
'Mendukung login, enable, dan privilege perangkat. Telnet tidak dimatikan oleh RADIQ.',
],
[
'OLT HSGQ',
'SSH + Telnet',
'22 + 23',
'Port dapat dibuat custom. Perintah tertentu dijalankan melalui Telnet.',
],
[
'OLT Hisfocus/Hioso',
'Telnet + WebGUI HTTP',
'23 + 80',
'Port custom didukung, misalnya Telnet 8183 dan WebGUI 8182.',
],
];
export default function DeploymentDocumentation() {
return (
<>
<Head title="Dokumentasi RADIQ NDM" />
<main className="public-page min-h-screen bg-background text-foreground transition-colors">
<div className="mx-auto max-w-6xl px-5 py-8 md:px-8">
<header className="mb-12 flex flex-wrap items-center justify-between gap-4">
<Link href="/" className="flex items-center gap-3">
<img
src="/images/radiq-ndm-logo.png"
className="size-12 object-contain"
alt="RADIQ NDM"
/>
<div>
<p className="font-semibold">RADIQ NDM</p>
<p className="text-xs text-sky-300">
Dokumentasi aplikasi
</p>
</div>
</Link>
<nav className="flex items-center gap-2">
<PublicThemeToggle />
<Link href="/login" className="px-4 py-2 text-sm">
Login
</Link>
<Link
href="/register"
className="rounded-lg bg-sky-500 px-4 py-2 text-sm font-semibold text-slate-950"
>
Daftar Tenant
</Link>
</nav>
</header>
<section className="grid gap-8 lg:grid-cols-[1fr_280px]">
<div>
<p className="text-sm font-semibold text-sky-400">
PANDUAN RESMI APLIKASI
</p>
<h1 className="mt-3 max-w-3xl text-4xl font-bold tracking-tight md:text-5xl">
Menjalankan RADIQ NDM di Cloud atau server milik
tenant.
</h1>
<p className="mt-5 max-w-3xl leading-7 text-slate-300">
RADIQ NDM memusatkan pengelolaan akun akses
perangkat jaringan. Tenant Admin dapat membuat,
mengubah, menonaktifkan, dan menghapus Users
Perangkat pada banyak perangkat tanpa membuka
perangkat satu per satu.
</p>
</div>
<aside className="rounded-2xl border border-white/10 bg-white/5 p-5 text-sm">
<p className="font-semibold">Isi dokumentasi</p>
<div className="mt-3 grid gap-2 text-slate-400">
{[
'Pilih deployment',
'Persyaratan server',
'Instalasi Windows/Linux',
'Worker wajib',
'Konfigurasi perangkat',
'Keamanan dan backup',
'Migrasi Cloud ke Local',
].map((item) => (
<span key={item}>• {item}</span>
))}
</div>
</aside>
</section>
<section className="mt-14">
<h2 className="text-2xl font-semibold">
1. Pilih lokasi deployment
</h2>
<div className="mt-5 grid gap-5 md:grid-cols-2">
<article className="rounded-2xl border border-sky-400/25 bg-sky-400/5 p-6">
<Cloud className="size-7 text-sky-400" />
<h3 className="mt-4 text-xl font-semibold">
Cloud RADIQ
</h3>
<p className="mt-2 text-sm leading-6 text-slate-300">
Tenant langsung menggunakan server yang
dikelola RADIQ. Cocok jika tidak ingin
memelihara PHP, PostgreSQL, web server,
worker, backup aplikasi, dan pembaruan
sistem sendiri.
</p>
<p className="mt-4 text-xs text-slate-400">
Saat registrasi pilih{' '}
<strong className="text-slate-200">
Cloud RADIQ
</strong>
. Instalasi dibuat dengan status aktif.
</p>
</article>
<article className="rounded-2xl border border-white/10 bg-white/5 p-6">
<Server className="size-7 text-sky-400" />
<h3 className="mt-4 text-xl font-semibold">
Self-hosted / Local
</h3>
<p className="mt-2 text-sm leading-6 text-slate-300">
Aplikasi dan database berjalan di VPS,
server, komputer, atau laptop tenant. Tenant
tetap tercatat dan lisensinya tetap dikelola
Master Admin RADIQ.
</p>
<p className="mt-4 text-xs text-slate-400">
Saat registrasi pilih{' '}
<strong className="text-slate-200">
Install Local
</strong>
. Instalasi berstatus pending sampai
pemasangan dan lisensi selesai.
</p>
</article>
</div>
</section>
<section className="mt-14">
<h2 className="text-2xl font-semibold">
2. Persyaratan self-hosted
</h2>
<div className="mt-5 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{[
[
Terminal,
'PHP 8.3',
'Ekstensi Laravel, PDO PostgreSQL, OpenSSL, cURL, Mbstring, XML, dan ZIP.',
],
[
Database,
'PostgreSQL',
'Database dan user khusus RADIQ NDM dengan akses ke database tersebut.',
],
[
Server,
'Web & build tools',
'Nginx/Apache/IIS, Composer, Node.js dan NPM.',
],
[
Network,
'Akses jaringan',
'Server harus dapat menjangkau IP dan port management perangkat.',
],
].map(([Icon, title, text]) => {
const ItemIcon = Icon as typeof Server;
return (
<article
key={title as string}
className="rounded-xl border border-white/10 p-5"
>
<ItemIcon className="size-5 text-sky-400" />
<h3 className="mt-3 font-semibold">
{title as string}
</h3>
<p className="mt-2 text-xs leading-5 text-slate-400">
{text as string}
</p>
</article>
);
})}
</div>
<div className="mt-5 rounded-xl border border-amber-400/20 bg-amber-400/5 p-4 text-sm leading-6 text-amber-100">
<AlertTriangle className="mr-2 inline size-4" />
Document root web server wajib menunjuk ke folder{' '}
<code>public</code>, bukan ke root project.
</div>
</section>
<section className="mt-14">
<div className="flex flex-wrap items-center justify-between gap-4">
<h2 className="text-2xl font-semibold">
3. Instalasi self-hosted
</h2>
<a
href="/downloads/self-hosted"
className="inline-flex items-center gap-2 rounded-lg border border-sky-400/30 px-4 py-2 text-sm font-semibold text-sky-300 hover:bg-sky-400/10"
>
<Download className="size-4" /> Unduh paket
</a>
</div>
<div className="mt-5 rounded-2xl border border-white/10 p-6">
<h3 className="font-semibold">
Konfigurasi minimum file .env
</h3>
<Code>{`APP_NAME="RADIQ NDM"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://ndm.domain-tenant.id
DEPLOYMENT_MODE=self_hosted
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=radiq_ndm
DB_USERNAME=radiq_ndm
DB_PASSWORD=PASSWORD_DATABASE
QUEUE_CONNECTION=database
CACHE_STORE=database
SESSION_DRIVER=database
RADIQ_LICENSE_SERVER_URL=https://alamat-control-plane-radiq
RADIQ_LICENSE_PUBLIC_KEY=PUBLIC_KEY_DARI_RADIQ`}</Code>
<p className="mt-3 text-xs leading-5 text-slate-400">
URL server lisensi dan public key diberikan
Master Admin RADIQ. Private signing key tidak
boleh berada pada server tenant.
</p>
</div>
<div className="mt-5 grid gap-5 lg:grid-cols-2">
<article className="rounded-2xl border border-white/10 p-6">
<h3 className="text-lg font-semibold">
Windows
</h3>
<ol className="mt-5 space-y-4">
<Step number={1}>
Ekstrak paket dan buka PowerShell pada
folder aplikasi.
</Step>
<Step number={2}>
Jalankan installer dengan PHP 8.3:
<Code>{`powershell -ExecutionPolicy Bypass -File scripts/install-self-hosted.ps1 -Php C:\\php83\\php.exe`}</Code>
</Step>
<Step number={3}>
Installer membuat <code>.env</code>,
lalu berhenti agar koneksi database
dapat diisi. Ketik <code>LANJUT</code>{' '}
setelah selesai.
</Step>
<Step number={4}>
Isi identitas ISP dan Tenant Admin.
Password minimal 12 karakter dengan
huruf besar/kecil, angka, dan simbol.
</Step>
</ol>
</article>
<article className="rounded-2xl border border-white/10 p-6">
<h3 className="text-lg font-semibold">Linux</h3>
<ol className="mt-5 space-y-4">
<Step number={1}>
Ekstrak paket dan berikan akses folder
serta <code>storage</code> kepada user
service.
</Step>
<Step number={2}>
Jalankan installer:
<Code>{`PHP_BIN=/usr/bin/php8.3 bash scripts/install-self-hosted.sh`}</Code>
</Step>
<Step number={3}>
Lengkapi <code>.env</code>, lalu ketik{' '}
<code>LANJUT</code>. Installer
menjalankan Composer, migration, seeder,
pembuatan tenant, build frontend, dan
optimasi.
</Step>
<Step number={4}>
Konfigurasikan Nginx/Apache dengan HTTPS
dan document root ke folder{' '}
<code>public</code>.
</Step>
</ol>
</article>
</div>
</section>
<section className="mt-14">
<h2 className="text-2xl font-semibold">
4. Proses background yang wajib hidup
</h2>
<p className="mt-3 text-sm leading-6 text-slate-300">
CRUD Users Perangkat dikirim ke queue. Jika
perangkat offline, assignment menjadi pending dan
scheduler akan mencoba kembali. Jalankan kedua
proses sebagai Windows Service, Task Scheduler,
systemd, atau Supervisor.
</p>
<Code>{`# Worker sinkronisasi perangkat
php artisan queue:work --queue=default --tries=1 --timeout=60
# Scheduler pekerjaan pending dan tugas berkala
php artisan schedule:work`}</Code>
<p className="mt-3 text-xs text-slate-400">
Pada Windows, ganti <code>php</code> dengan{' '}
<code>C:\php83\php.exe</code>. Setelah deployment
jalankan <code>php artisan optimize:clear</code> dan{' '}
<code>php artisan queue:restart</code>.
</p>
</section>
<section className="mt-14">
<h2 className="text-2xl font-semibold">
5. Konfigurasi koneksi perangkat
</h2>
<div className="mt-5 overflow-x-auto rounded-2xl border border-white/10">
<table className="w-full min-w-[760px] text-left text-sm">
<thead className="bg-white/5 text-slate-200">
<tr>
{[
'Vendor',
'Protokol',
'Port default',
'Catatan',
].map((title) => (
<th
key={title}
className="px-4 py-3 font-semibold"
>
{title}
</th>
))}
</tr>
</thead>
<tbody>
{vendorRows.map((row) => (
<tr
key={row[0]}
className="border-t border-white/10"
>
{row.map((cell) => (
<td
key={cell}
className="px-4 py-3 align-top leading-6 text-slate-400"
>
{cell}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
<div className="mt-5 rounded-xl border border-white/10 p-5 text-sm leading-6 text-slate-300">
<strong>Aturan port:</strong> form perangkat berubah
mengikuti vendor. Isi hanya port protokol yang
tersedia. Port kosong berarti protokol tersebut
tidak digunakan. Firewall server RADIQ harus dapat
mencapai management network.
</div>
</section>
<section className="mt-14 grid gap-5 lg:grid-cols-2">
<article className="rounded-2xl border border-white/10 p-6">
<Users className="size-6 text-sky-400" />
<h2 className="mt-4 text-xl font-semibold">
6. Cara kerja Users Perangkat
</h2>
<ol className="mt-5 space-y-3">
<Step number={1}>
Tenant Admin mengatur Base User dan Base
Password.
</Step>
<Step number={2}>
Tambahkan perangkat dengan credential awal,
lalu Cek & Aktifkan.
</Step>
<Step number={3}>
Buat Users Perangkat, pilih perangkat tujuan
dan group akses.
</Step>
<Step number={4}>
Perangkat online langsung disinkronkan;
perangkat offline berstatus pending.
</Step>
</ol>
<p className="mt-4 text-xs leading-5 text-slate-400">
Role aplikasi tetap: Master Admin, Tenant Admin,
dan Tenant User. Tenant Admin hanya mengelola
Tenant User miliknya.
</p>
</article>
<article className="rounded-2xl border border-white/10 p-6">
<KeyRound className="size-6 text-sky-400" />
<h2 className="mt-4 text-xl font-semibold">
7. Credential dan encryption key
</h2>
<div className="mt-4 space-y-3 text-sm leading-6 text-slate-300">
<p>
Password perangkat dienkripsi dengan tenant
encryption key. Tenant key dibungkus kembali
oleh application key server.
</p>
<p>
Tenant Admin dapat membuat key otomatis atau
manual. Rotasi key mengenkripsi ulang
credential yang tersimpan.
</p>
<p>
Melihat Base Password wajib memasukkan
password login Tenant Admin dan dibatasi
rate limit.
</p>
</div>
<div className="mt-4 rounded-lg bg-red-400/5 p-3 text-xs leading-5 text-red-100">
Kehilangan APP_KEY atau encryption key tanpa
backup yang benar dapat membuat credential tidak
dapat dipulihkan.
</div>
</article>
</section>
<section className="mt-14">
<h2 className="text-2xl font-semibold">
8. Backup dan pemeliharaan
</h2>
<div className="mt-5 grid gap-4 md:grid-cols-3">
{[
[
'Database PostgreSQL',
'Backup seluruh database termasuk tenant, assignment, queue, dan credential terenkripsi.',
],
[
'File rahasia',
'Backup .env dan APP_KEY secara terenkripsi, terpisah dari database dan dengan akses terbatas.',
],
[
'Uji pemulihan',
'Lakukan restore drill pada server terisolasi. Backup yang belum diuji belum dapat dianggap aman.',
],
].map(([title, text]) => (
<article
key={title}
className="rounded-xl border border-white/10 p-5"
>
<ShieldCheck className="size-5 text-emerald-400" />
<h3 className="mt-3 font-semibold">
{title}
</h3>
<p className="mt-2 text-xs leading-5 text-slate-400">
{text}
</p>
</article>
))}
</div>
<Code>{`# Contoh backup PostgreSQL
pg_dump -Fc -U radiq_ndm -d radiq_ndm -f radiq_ndm.backup
# Maintenance setelah update aplikasi
php artisan migrate --force
php artisan optimize
php artisan queue:restart`}</Code>
</section>
<section className="mt-14">
<h2 className="text-2xl font-semibold">
9. Migrasi Cloud ke Local
</h2>
<div className="mt-4 rounded-xl border border-amber-400/20 bg-amber-400/5 p-4 text-sm leading-6 text-amber-100">
<AlertTriangle className="mr-2 inline size-4" />
Versi saat ini belum menyediakan ekspor–impor tenant
otomatis. Migrasi harus dijadwalkan bersama Master
Admin agar credential terenkripsi dan encryption key
dipindahkan dengan aman.
</div>
<ol className="mt-5 space-y-4">
{[
'Tenant Admin mengajukan migrasi dan jadwal maintenance.',
'Master Admin menyiapkan instalasi self-hosted dan lisensi tenant.',
'Pasang RADIQ NDM local dengan APP_KEY baru, tetapi jangan aktifkan worker perangkat.',
'Pindahkan data tenant dan re-enkripsi secret melalui prosedur migrasi; jangan mengekspor password sebagai plaintext.',
'Verifikasi user, perangkat, Users Perangkat, assignment, port vendor, dan status lisensi.',
'Hentikan worker Cloud sebelum menyalakan worker Local agar perintah tidak berjalan dua kali.',
'Uji satu perangkat per vendor, kemudian selesaikan cutover.',
].map((item, index) => (
<Step key={item} number={index + 1}>
{item}
</Step>
))}
</ol>
</section>
<section className="mt-14 rounded-2xl bg-sky-500 p-7 text-slate-950">
<h2 className="text-2xl font-bold">
Mulai dengan deployment yang sesuai
</h2>
<p className="mt-2 max-w-2xl">
Cloud cocok untuk penggunaan cepat. Self-hosted
cocok ketika management perangkat hanya dapat
diakses dari jaringan internal tenant.
</p>
<Link
href="/register"
className="mt-5 inline-flex items-center gap-2 rounded-lg bg-slate-950 px-5 py-3 font-semibold text-white"
>
Daftar Tenant <ArrowRight className="size-4" />
</Link>
</section>
</div>
</main>
</>
);
}